diff --git a/pkg/agent/bakerapi.go b/pkg/agent/bakerapi.go index 1d540b4af7b..f12ee25241e 100644 --- a/pkg/agent/bakerapi.go +++ b/pkg/agent/bakerapi.go @@ -106,6 +106,10 @@ func (agentBaker *agentBakerImpl) GetLatestSigImageConfig(sigConfig datamodel.SI sigImageConfig.Version = imageVersion } } + + sigImageConfig.CachedFromManifest = datamodel.CachedFromManifest + sigImageConfig.CachedFromComponsents = datamodel.CachedFromComponsents + return sigImageConfig, nil } diff --git a/pkg/agent/bakerapi_test.go b/pkg/agent/bakerapi_test.go index b89bd7bb907..eadb98d84be 100644 --- a/pkg/agent/bakerapi_test.go +++ b/pkg/agent/bakerapi_test.go @@ -19,6 +19,9 @@ var _ = Describe("AgentBaker API implementation tests", func() { ) BeforeEach(func() { + datamodel.CacheManifest() + datamodel.CacheComponents() + toggles = agenttoggles.New() cs = &datamodel.ContainerService{ @@ -312,6 +315,26 @@ var _ = Describe("AgentBaker API implementation tests", func() { Expect(sigImageConfig.Version).To(Equal("2021.11.06")) }) + It("should return cached VHD data", func() { + agentBaker, err := NewAgentBaker() + Expect(err).NotTo(HaveOccurred()) + agentBaker = agentBaker.WithToggles(toggles) + + sigImageConfig, err := agentBaker.GetLatestSigImageConfig(config.SIGConfig, datamodel.AKSUbuntu1604, &datamodel.EnvironmentInfo{ + SubscriptionID: config.SubscriptionID, + TenantID: config.TenantID, + Region: cs.Location, + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(sigImageConfig.CachedFromManifest["runc"].Installed["default"]).To(Equal("1.1.12")) + Expect(sigImageConfig.CachedFromManifest["containerd"].Pinned["1804"]).To(Equal("1.7.1-1")) + Expect(sigImageConfig.CachedFromManifest["containerd"].Edge).To(Equal("1.7.15-1")) + Expect(sigImageConfig.CachedFromComponsents["pause"].MultiArchVersions[0]).To(Equal("3.6")) + Expect(sigImageConfig.CachedFromComponsents["azure-cns"].PrefetchOptimizations.Version).To(Equal("v1.5.23")) + Expect(sigImageConfig.CachedFromComponsents["azure-cns"].PrefetchOptimizations.Binaries[0]).To(Equal("usr/local/bin/azure-cns")) + }) + It("should return correct value for existing distro when linux node image version override is provided", func() { toggles.Maps = map[string]agenttoggles.MapToggle{ "linux-node-image-version": func(entity *agenttoggles.Entity) map[string]string { diff --git a/pkg/agent/datamodel/helper.go b/pkg/agent/datamodel/helper.go index 80637169a58..c2b22ab8165 100644 --- a/pkg/agent/datamodel/helper.go +++ b/pkg/agent/datamodel/helper.go @@ -98,3 +98,24 @@ func IndentString(original string, spaces int) string { } return out.String() } + +func trimEOF(data []byte) []byte { + eofIndex := bytes.LastIndex(data, []byte("#EOF")) + if eofIndex != -1 { // #EOF found + newlineIndex := bytes.LastIndex(data[:eofIndex], []byte("\n")) + if newlineIndex != -1 { + return data[:newlineIndex] + } + } + return data +} + +func processDownloadURL(downloadURL string) string { + // example URL "downloadURL": "mcr.microsoft.com/oss/kubernetes/autoscaler/addon-resizer:*", + // getting the data between the last / and the last : + parts := strings.Split(downloadURL, "/") + lastPart := parts[len(parts)-1] + component := strings.Split(lastPart, ":") + componentName := component[0] + return componentName +} diff --git a/pkg/agent/datamodel/helper_test.go b/pkg/agent/datamodel/helper_test.go index c03c4b75287..b441d27fb1c 100644 --- a/pkg/agent/datamodel/helper_test.go +++ b/pkg/agent/datamodel/helper_test.go @@ -346,3 +346,29 @@ func TestIndentString(t *testing.T) { }) } } + +func TestTrimEOF(t *testing.T) { + tests := []struct { + name string + input []byte + expected string + }{ + { + name: "Should remove #EOF at the end of a file", + input: []byte(`"versions":["1.26.6","1.26.10","1.26.12","1.27.3","1.27.7","1.27.9","1.28.1","1.28.3","1.28.5","1.29.0","1.29.2"]},"_template":{"fileName":"","downloadLocation":"","downloadURL":"","versions":[]}}` + "\n#EOF"), //nolint:lll + expected: `"versions":["1.26.6","1.26.10","1.26.12","1.27.3","1.27.7","1.27.9","1.28.1","1.28.3","1.28.5","1.29.0","1.29.2"]},"_template":{"fileName":"","downloadLocation":"","downloadURL":"","versions":[]}}`, //nolint:lll + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + got := trimEOF(test.input) + diff := cmp.Diff(test.expected, string(got)) + if diff != "" { + t.Fatalf(diff) + } + }) + } +} diff --git a/pkg/agent/datamodel/sig_config.go b/pkg/agent/datamodel/sig_config.go index d6ae6796343..872009503f6 100644 --- a/pkg/agent/datamodel/sig_config.go +++ b/pkg/agent/datamodel/sig_config.go @@ -4,6 +4,9 @@ import ( _ "embed" "encoding/json" "fmt" + "os" + "path" + "runtime" "strings" ) @@ -12,6 +15,30 @@ const ( AzurePublicCloudSigSubscription string = "109a5e88-712a-48ae-9078-9ca8b3c81345" // AKS VHD ) +//nolint:gochecknoglobals +var ( + CachedFromComponsents = make(map[string]ProcessedComponents) + CachedFromManifest = make(map[string]ProcessedManifest) +) + +//nolint:gochecknoinits +func init() { + CacheManifest() + CacheComponents() +} + +func CacheManifest() { + _, filename, _, _ := runtime.Caller(0) + manifestFilePath := "../../../parts/linux/cloud-init/artifacts/manifest.json" + getCachedK8sVersionFromManifest(path.Join(path.Dir(filename), manifestFilePath)) +} + +func CacheComponents() { + _, filename, _, _ := runtime.Caller(0) + componentsFilePath := "../../../vhdbuilder/packer/components.json" + getCachedComponentsFromComponents(path.Join(path.Dir(filename), componentsFilePath)) +} + // SIGAzureEnvironmentSpecConfig is the overall configuration differences in different cloud environments. /* TODO(tonyxu) merge this with AzureEnvironmentSpecConfig from aks-engine(pkg/api/azenvtypes.go) once it's moved into AKS RP. */ @@ -273,8 +300,6 @@ func (d Distro) IsWindowsDistro() bool { } // SigImageConfigTemplate represents the SIG image configuration template. -// -//nolint:musttag // tags can be added if deemed necessary type SigImageConfigTemplate struct { ResourceGroup string Gallery string @@ -285,7 +310,9 @@ type SigImageConfigTemplate struct { // SigImageConfig represents the SIG image configuration. type SigImageConfig struct { SigImageConfigTemplate - SubscriptionID string + SubscriptionID string + CachedFromManifest map[string]ProcessedManifest + CachedFromComponsents map[string]ProcessedComponents } // WithOptions converts a SigImageConfigTemplate to SigImageConfig instance via function opts. @@ -875,3 +902,120 @@ func withSubscription(subscriptionID string) SigImageConfigOpt { c.SubscriptionID = subscriptionID } } + +type Manifest struct { + Containerd struct { + Edge string `json:"edge"` + Versions []string `json:"versions"` + Pinned map[string]string `json:"pinned"` + } `json:"containerd"` + Runc struct { + Versions []string `json:"versions"` + Pinned map[string]string `json:"pinned"` + Installed map[string]string `json:"installed"` + } `json:"runc"` + NvidiaContainerRuntime struct { + Versions []string `json:"versions"` + } `json:"nvidia-container-runtime"` + NvidiaDrivers struct { + Versions []string `json:"versions"` + } `json:"nvidia-drivers"` + Kubernetes struct { + Versions []string `json:"versions"` + } `json:"kubernetes"` +} + +type ProcessedManifest struct { + Name string + Versions []string + Pinned map[string]string + Edge string + Installed map[string]string +} + +func getCachedK8sVersionFromManifest(manifestFilePath string) { + data, err := os.ReadFile(manifestFilePath) + if err != nil { + panic(err) + } + data = trimEOF(data) + var manifest Manifest + if err = json.Unmarshal(data, &manifest); err != nil { + panic(err) + } + + CachedFromManifest["kubernetes"] = ProcessedManifest{ + Name: "kubernetes", + Versions: manifest.Kubernetes.Versions, + } + CachedFromManifest["runc"] = ProcessedManifest{ + Name: "runc", + Versions: manifest.Runc.Versions, + Pinned: manifest.Runc.Pinned, + Installed: manifest.Runc.Installed, + } + CachedFromManifest["containerd"] = ProcessedManifest{ + Name: "containerd", + Versions: manifest.Containerd.Versions, + Pinned: manifest.Containerd.Pinned, + Edge: manifest.Containerd.Edge, + } + CachedFromManifest["nvidia-container-runtime"] = ProcessedManifest{ + Name: "nvidia-container-runtime", + Versions: manifest.NvidiaContainerRuntime.Versions, + } + CachedFromManifest["nvidia-drivers"] = ProcessedManifest{ + Name: "nvidia-drivers", + Versions: manifest.NvidiaDrivers.Versions, + } +} + +type Components struct { + ContainerImages []struct { + DownloadURL string `json:"downloadURL"` + Amd64OnlyVersions []string `json:"amd64OnlyVersions"` + MultiArchVersions []string `json:"multiArchVersions"` + PrefetchOptimizations []struct { + Version string `json:"version"` + Binaries []string `json:"binaries"` + } `json:"prefetchOptimizations"` + } `json:"ContainerImages"` +} +type PrefetchOptimizations struct { + Version string + Binaries []string +} + +type ProcessedComponents struct { + Name string + MultiArchVersions []string + Amd64OnlyVersions []string + PrefetchOptimizations PrefetchOptimizations +} + +func getCachedComponentsFromComponents(componentsFilePath string) { + data, err := os.ReadFile(componentsFilePath) + if err != nil { + panic(err) + } + var components Components + if err = json.Unmarshal(data, &components); err != nil { + panic(err) + } + + for _, image := range components.ContainerImages { + componentName := processDownloadURL(image.DownloadURL) + processed := ProcessedComponents{ + Name: componentName, + MultiArchVersions: image.MultiArchVersions, + Amd64OnlyVersions: image.Amd64OnlyVersions, + } + if len(image.PrefetchOptimizations) > 0 { + processed.PrefetchOptimizations = PrefetchOptimizations{ + Version: image.PrefetchOptimizations[0].Version, + Binaries: image.PrefetchOptimizations[0].Binaries, + } + } + CachedFromComponsents[componentName] = processed + } +} diff --git a/pkg/agent/datamodel/types.go b/pkg/agent/datamodel/types.go index a70e7d52b72..cb43c75e3ff 100644 --- a/pkg/agent/datamodel/types.go +++ b/pkg/agent/datamodel/types.go @@ -1620,8 +1620,6 @@ type K8sComponents struct { // GetLatestSigImageConfigRequest describes the input for a GetLatestSigImageConfig HTTP request. // This is mostly a wrapper over existing types so RP doesn't have to manually construct JSON. -// -//nolint:musttag // tags can be added if deemed necessary type GetLatestSigImageConfigRequest struct { SIGConfig SIGConfig SubscriptionID string @@ -1631,8 +1629,6 @@ type GetLatestSigImageConfigRequest struct { } // NodeBootstrappingConfiguration represents configurations for node bootstrapping. -// -//nolint:musttag // tags can be added if deemed necessary type NodeBootstrappingConfiguration struct { ContainerService *ContainerService CloudSpecConfig *AzureEnvironmentSpecConfig @@ -1695,8 +1691,6 @@ const ( ) // NodeBootstrapping represents the custom data, CSE, and OS image info needed for node bootstrapping. -// -//nolint:musttag // tags can be added if deemed necessary type NodeBootstrapping struct { CustomData string CSE string diff --git a/pkg/agent/utils_test.go b/pkg/agent/utils_test.go index 0739765450f..832e7bace0a 100644 --- a/pkg/agent/utils_test.go +++ b/pkg/agent/utils_test.go @@ -725,5 +725,4 @@ var _ = Describe("Test removeComments", func() { result := removeComments(input) Expect(string(result)).To(Equal(expected)) }) - })