diff --git a/pkg/clients/dynatrace/activegate_version.go b/pkg/clients/dynatrace/activegate_version.go index 639ed3e4df..e7fb579e64 100644 --- a/pkg/clients/dynatrace/activegate_version.go +++ b/pkg/clients/dynatrace/activegate_version.go @@ -3,7 +3,6 @@ package dynatrace import ( "context" - "github.com/Dynatrace/dynatrace-operator/pkg/arch" "github.com/pkg/errors" ) @@ -13,7 +12,7 @@ func (dtc *dynatraceClient) GetLatestActiveGateVersion(ctx context.Context, os s LatestGatewayVersion string `json:"latestGatewayVersion"` }{} - url := dtc.getLatestActiveGateVersionUrl(os, arch.Arch) + url := dtc.getLatestActiveGateVersionUrl(os) err := dtc.makeRequestAndUnmarshal(ctx, url, dynatracePaaSToken, &response) return response.LatestGatewayVersion, errors.WithStack(err) diff --git a/pkg/clients/dynatrace/agent_version.go b/pkg/clients/dynatrace/agent_version.go index 8f5f05c2a7..38d37b7063 100644 --- a/pkg/clients/dynatrace/agent_version.go +++ b/pkg/clients/dynatrace/agent_version.go @@ -53,23 +53,32 @@ func (dtc *dynatraceClient) GetLatestAgentVersion(ctx context.Context, os, insta return "", errors.New("os or installerType is empty") } - var flavor string - // Default installer type has no "multidistro" flavor - // so the default flavor is always needed in that case + url := dtc.getLatestAgentVersionUrl(os, installerType, determineFlavor(installerType), determineArch(installerType)) + err := dtc.makeRequestAndUnmarshal(ctx, url, dynatracePaaSToken, &response) + + return response.LatestAgentVersion, errors.WithStack(err) +} + +// determineArch gives you the proper arch value, because the OSAgent and ActiveGate images on the tenant-image-registry only have AMD images. +func determineArch(installerType string) string { if installerType == InstallerTypeDefault { - flavor = arch.FlavorDefault - } else { - flavor = arch.Flavor + return "" } - url := dtc.getLatestAgentVersionUrl(os, installerType, flavor, arch.Arch) - err := dtc.makeRequestAndUnmarshal(ctx, url, dynatracePaaSToken, &response) + return arch.Arch +} - return response.LatestAgentVersion, errors.WithStack(err) +// determineFlavor gives you the proper flavor value, because the default installer type has no "multidistro" flavor so the default flavor is always needed in that case. +func determineFlavor(installerType string) string { + if installerType == InstallerTypeDefault { + return arch.FlavorDefault + } + + return arch.Flavor } // GetAgentVersions gets available agent versions for the given OS and installer type. -func (dtc *dynatraceClient) GetAgentVersions(ctx context.Context, os, installerType, flavor, arch string) ([]string, error) { +func (dtc *dynatraceClient) GetAgentVersions(ctx context.Context, os, installerType, flavor string) ([]string, error) { response := struct { AvailableVersions []string `json:"availableVersions"` }{} @@ -78,7 +87,7 @@ func (dtc *dynatraceClient) GetAgentVersions(ctx context.Context, os, installerT return nil, errors.New("os or installerType is empty") } - url := dtc.getAgentVersionsUrl(os, installerType, flavor, arch) + url := dtc.getAgentVersionsUrl(os, installerType, flavor, determineArch(installerType)) err := dtc.makeRequestAndUnmarshal(ctx, url, dynatracePaaSToken, &response) return response.AvailableVersions, errors.WithStack(err) diff --git a/pkg/clients/dynatrace/agent_version_test.go b/pkg/clients/dynatrace/agent_version_test.go index c2c2019b30..94594d6795 100644 --- a/pkg/clients/dynatrace/agent_version_test.go +++ b/pkg/clients/dynatrace/agent_version_test.go @@ -214,7 +214,7 @@ func TestDynatraceClient_GetAgentVersions(t *testing.T) { dynatraceServer, dtc := createTestDynatraceClientWithFunc(t, versionsRequestHandler) defer dynatraceServer.Close() - availableVersions, err := dtc.GetAgentVersions(ctx, OsUnix, InstallerTypePaaS, "", "") + availableVersions, err := dtc.GetAgentVersions(ctx, OsUnix, InstallerTypePaaS, "") require.NoError(t, err) assert.Len(t, availableVersions, 4) @@ -227,7 +227,7 @@ func TestDynatraceClient_GetAgentVersions(t *testing.T) { dynatraceServer, dtc := createTestDynatraceClientWithFunc(t, errorHandler) defer dynatraceServer.Close() - availableVersions, err := dtc.GetAgentVersions(ctx, OsUnix, InstallerTypePaaS, "", "") + availableVersions, err := dtc.GetAgentVersions(ctx, OsUnix, InstallerTypePaaS, "") require.EqualError(t, err, "dynatrace server error 400: test-error") assert.Empty(t, availableVersions) diff --git a/pkg/clients/dynatrace/client.go b/pkg/clients/dynatrace/client.go index b4b3e36e8d..d51f0c7873 100644 --- a/pkg/clients/dynatrace/client.go +++ b/pkg/clients/dynatrace/client.go @@ -44,7 +44,7 @@ type Client interface { // GetAgentVersions on success returns an array of versions that can be used with GetAgent to // download a specific agent version - GetAgentVersions(ctx context.Context, os, installerType, flavor, arch string) ([]string, error) + GetAgentVersions(ctx context.Context, os, installerType, flavor string) ([]string, error) GetOneAgentConnectionInfo(ctx context.Context) (OneAgentConnectionInfo, error) diff --git a/pkg/clients/dynatrace/dynatrace_client_test.go b/pkg/clients/dynatrace/dynatrace_client_test.go index 6596d79c61..bd95a620ff 100644 --- a/pkg/clients/dynatrace/dynatrace_client_test.go +++ b/pkg/clients/dynatrace/dynatrace_client_test.go @@ -17,19 +17,19 @@ import ( var ( flavorUri = fmt.Sprintf("/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", - OsUnix, InstallerTypeDefault, arch.FlavorDefault+"a", arch.Arch) + OsUnix, InstallerTypePaaS, arch.FlavorMultidistro+"a", arch.Arch) flavourUriResponse = `{"error":{"code":400,"message":"Constraints violated.","constraintViolations":[{"path":"flavor","message":"'defaulta' must be any of [default, multidistro, musl]","parameterLocation":"QUERY","location":null}]}}` archUri = fmt.Sprintf("/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", - OsUnix, InstallerTypeDefault, arch.FlavorDefault, arch.Arch+"a") + OsUnix, InstallerTypePaaS, arch.FlavorMultidistro, arch.Arch+"a") archUriResponse = `{"error":{"code":400,"message":"Constraints violated.","constraintViolations":[{"path":"arch","message":"'x86a' must be any of [all, arm, ppc, ppcle, s390, sparc, x86, zos]","parameterLocation":"QUERY","location":null}]}}` flavorArchUri = fmt.Sprintf("/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", - OsUnix, InstallerTypeDefault, arch.FlavorDefault+"a", arch.Arch+"a") + OsUnix, InstallerTypePaaS, arch.FlavorMultidistro+"a", arch.Arch+"a") flavourArchUriResponse = `{"error":{"code":400,"message":"Constraints violated.","constraintViolations":[{"path":"flavor","message":"'defaulta' must be any of [default, multidistro, musl]","parameterLocation":"QUERY","location":null},{"path":"arch","message":"'x86a' must be any of [all, arm, ppc, ppcle, s390, sparc, x86, zos]","parameterLocation":"QUERY","location":null}]}}` oaLatestMetainfoUri = fmt.Sprintf("/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", - "aix", InstallerTypeDefault, arch.FlavorDefault, arch.Arch) + "aix", InstallerTypePaaS, arch.FlavorMultidistro, arch.Arch) oaLatestMetainfoUriResponse = `{"error":{"code":404,"message":"non supported architecture on OS "}}` ) @@ -315,7 +315,7 @@ func testServerErrors(t *testing.T) { }) t.Run("GetLatestAgentVersion - invalid architecture", func(t *testing.T) { - _, err = dtc.GetLatestAgentVersion(context.Background(), "aix", InstallerTypeDefault) + _, err = dtc.GetLatestAgentVersion(context.Background(), "aix", InstallerTypePaaS) assert.Equal(t, "dynatrace server error 404: non supported architecture on OS ", err.Error()) }) } diff --git a/pkg/clients/dynatrace/endpoints.go b/pkg/clients/dynatrace/endpoints.go index 7b56d8b5d9..387ad10dac 100644 --- a/pkg/clients/dynatrace/endpoints.go +++ b/pkg/clients/dynatrace/endpoints.go @@ -17,18 +17,28 @@ func (dtc *dynatraceClient) getLatestAgentUrl(os, installerType, flavor, arch st } func (dtc *dynatraceClient) getLatestAgentVersionUrl(os, installerType, flavor, arch string) string { - return fmt.Sprintf("%s/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", - dtc.url, os, installerType, flavor, arch) + if arch != "" { + return fmt.Sprintf("%s/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s&arch=%s", + dtc.url, os, installerType, flavor, arch) + } + + return fmt.Sprintf("%s/v1/deployment/installer/agent/%s/%s/latest/metainfo?bitness=64&flavor=%s", + dtc.url, os, installerType, flavor) } -func (dtc *dynatraceClient) getLatestActiveGateVersionUrl(os, arch string) string { - return fmt.Sprintf("%s/v1/deployment/installer/gateway/%s/latest/metainfo?arch=%s", - dtc.url, os, arch) +func (dtc *dynatraceClient) getLatestActiveGateVersionUrl(os string) string { + return fmt.Sprintf("%s/v1/deployment/installer/gateway/%s/latest/metainfo", + dtc.url, os) } func (dtc *dynatraceClient) getAgentVersionsUrl(os, installerType, flavor, arch string) string { - return fmt.Sprintf("%s/v1/deployment/installer/agent/versions/%s/%s?flavor=%s&arch=%s", - dtc.url, os, installerType, flavor, arch) + if arch != "" { + return fmt.Sprintf("%s/v1/deployment/installer/agent/versions/%s/%s?flavor=%s&arch=%s", + dtc.url, os, installerType, flavor, arch) + } + + return fmt.Sprintf("%s/v1/deployment/installer/agent/versions/%s/%s?flavor=%s", + dtc.url, os, installerType, flavor) } func (dtc *dynatraceClient) getOneAgentConnectionInfoUrl() string { diff --git a/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset.go b/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset.go index cb7dafd9b0..472460a291 100644 --- a/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset.go +++ b/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset.go @@ -3,6 +3,7 @@ package statefulset import ( "strconv" + "github.com/Dynatrace/dynatrace-operator/pkg/api/status" "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube" "github.com/Dynatrace/dynatrace-operator/pkg/controllers/dynakube/activegate/capability" "github.com/Dynatrace/dynatrace-operator/pkg/controllers/dynakube/activegate/consts" @@ -116,7 +117,7 @@ func (statefulSetBuilder Builder) addTemplateSpec(sts *appsv1.StatefulSet) { Containers: statefulSetBuilder.buildBaseContainer(), NodeSelector: statefulSetBuilder.capability.Properties().NodeSelector, ServiceAccountName: statefulSetBuilder.dynakube.ActiveGate().GetServiceAccountName(), - Affinity: nodeAffinity(), + Affinity: statefulSetBuilder.nodeAffinity(), Tolerations: statefulSetBuilder.capability.Properties().Tolerations, SecurityContext: &corev1.PodSecurityContext{ SeccompProfile: &corev1.SeccompProfile{ @@ -222,16 +223,13 @@ func (statefulSetBuilder Builder) buildCommonEnvs() []corev1.EnvVar { return statefulSetBuilder.envMap.AsEnvVars() } -func nodeAffinity() *corev1.Affinity { - return &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - }, - }, - }, - }, +func (statefulSetBuilder Builder) nodeAffinity() *corev1.Affinity { + var affinity corev1.Affinity + if statefulSetBuilder.dynakube.Status.ActiveGate.Source == status.TenantRegistryVersionSource || statefulSetBuilder.dynakube.Status.ActiveGate.Source == status.CustomVersionVersionSource { + affinity = node.AMDOnlyAffinity() + } else { + affinity = node.Affinity() } + + return &affinity } diff --git a/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset_test.go b/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset_test.go index 09fad29d7e..63bd7a3c52 100644 --- a/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset_test.go +++ b/pkg/controllers/dynakube/activegate/internal/statefulset/statefulset_test.go @@ -86,7 +86,34 @@ func TestGetBaseObjectMeta(t *testing.T) { require.NotEmpty(t, sts.Spec.Template.Labels) assert.Equal(t, expectedTemplateAnnotations, sts.Spec.Template.Annotations) }) - t.Run("has default node affinity", func(t *testing.T) { + t.Run("has default(tenant-registry) node affinity", func(t *testing.T) { + dk := getTestDynakube() + dk.Status.ActiveGate.VersionStatus.Source = status.TenantRegistryVersionSource + multiCapability := capability.NewMultiCapability(&dk) + builder := NewStatefulSetBuilder(testKubeUID, testConfigHash, dk, multiCapability) + sts, _ := builder.CreateStatefulSet(nil) + expectedNodeSelectorTerms := []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/arch", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"amd64"}, + }, + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, + }, + }} + + require.NotEmpty(t, sts.Spec.Template.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) + assert.Contains(t, sts.Spec.Template.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, expectedNodeSelectorTerms[0]) + }) + t.Run("has none tenant-registry node affinity", func(t *testing.T) { + dk := getTestDynakube() + dk.Status.ActiveGate.VersionStatus.Source = status.CustomImageVersionSource multiCapability := capability.NewMultiCapability(&dk) builder := NewStatefulSetBuilder(testKubeUID, testConfigHash, dk, multiCapability) sts, _ := builder.CreateStatefulSet(nil) diff --git a/pkg/controllers/dynakube/extension/eec/reconciler_test.go b/pkg/controllers/dynakube/extension/eec/reconciler_test.go index 9c9cdd3641..90c16302e0 100644 --- a/pkg/controllers/dynakube/extension/eec/reconciler_test.go +++ b/pkg/controllers/dynakube/extension/eec/reconciler_test.go @@ -462,19 +462,8 @@ func TestAffinity(t *testing.T) { statefulSet := getStatefulset(t, dk) - expectedAffinity := &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - }, - }, - }, - }, - } - - assert.Equal(t, expectedAffinity, statefulSet.Spec.Template.Spec.Affinity) + expectedAffinity := node.Affinity() + assert.Equal(t, expectedAffinity, *statefulSet.Spec.Template.Spec.Affinity) }) } diff --git a/pkg/controllers/dynakube/extension/eec/statefulset.go b/pkg/controllers/dynakube/extension/eec/statefulset.go index 19c168b918..7421b3982a 100644 --- a/pkg/controllers/dynakube/extension/eec/statefulset.go +++ b/pkg/controllers/dynakube/extension/eec/statefulset.go @@ -160,17 +160,7 @@ func buildAppLabels(dynakubeName string) *labels.AppLabels { } func buildAffinity() corev1.Affinity { - return corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - }, - }, - }, - }, - } + return node.Affinity() } func setImagePullSecrets(imagePullSecrets []corev1.LocalObjectReference) func(o *appsv1.StatefulSet) { diff --git a/pkg/controllers/dynakube/extension/otel/statefulset.go b/pkg/controllers/dynakube/extension/otel/statefulset.go index 7f4a4dc2df..10b0ce421b 100644 --- a/pkg/controllers/dynakube/extension/otel/statefulset.go +++ b/pkg/controllers/dynakube/extension/otel/statefulset.go @@ -245,17 +245,7 @@ func buildAppLabels(dkName string) *labels.AppLabels { func buildAffinity() corev1.Affinity { // TODO: implement new attributes in CR dk.Spec.Templates.OpenTelemetryCollector.Affinity // otherwise to use defaults ones - return corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - }, - }, - }, - }, - } + return node.Affinity() } func setImagePullSecrets(imagePullSecrets []corev1.LocalObjectReference) func(o *appsv1.StatefulSet) { diff --git a/pkg/controllers/dynakube/extension/otel/statefulset_test.go b/pkg/controllers/dynakube/extension/otel/statefulset_test.go index 9718bf6097..a70cdc6836 100644 --- a/pkg/controllers/dynakube/extension/otel/statefulset_test.go +++ b/pkg/controllers/dynakube/extension/otel/statefulset_test.go @@ -268,19 +268,9 @@ func TestAffinity(t *testing.T) { dk := getTestDynakube() statefulSet := getStatefulset(t, dk) - expectedAffinity := &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - }, - }, - }, - }, - } + expectedAffinity := node.Affinity() - assert.Equal(t, expectedAffinity, statefulSet.Spec.Template.Spec.Affinity) + assert.Equal(t, expectedAffinity, *statefulSet.Spec.Template.Spec.Affinity) }) } diff --git a/pkg/controllers/dynakube/kspm/daemonset/reconciler.go b/pkg/controllers/dynakube/kspm/daemonset/reconciler.go index 87ac0655f4..7d36529e62 100644 --- a/pkg/controllers/dynakube/kspm/daemonset/reconciler.go +++ b/pkg/controllers/dynakube/kspm/daemonset/reconciler.go @@ -89,7 +89,7 @@ func (r *Reconciler) generateDaemonSet() (*appsv1.DaemonSet, error) { daemonset.SetAllLabels(labels.BuildLabels(), labels.BuildMatchLabels(), labels.BuildLabels(), r.dk.KSPM().Labels), daemonset.SetAllAnnotations(r.dk.KSPM().Annotations, templateAnnotations), daemonset.SetServiceAccount(serviceAccountName), - daemonset.SetAffinity(node.Affinity()), + daemonset.SetAffinity(node.AMDOnlyAffinity()), daemonset.SetPriorityClass(r.dk.KSPM().PriorityClassName), daemonset.SetTolerations(r.dk.KSPM().Tolerations), daemonset.SetPullSecret(r.dk.ImagePullSecretReferences()...), diff --git a/pkg/controllers/dynakube/oneagent/daemonset/affinity.go b/pkg/controllers/dynakube/oneagent/daemonset/affinity.go index d63b098614..8025aaca7e 100644 --- a/pkg/controllers/dynakube/oneagent/daemonset/affinity.go +++ b/pkg/controllers/dynakube/oneagent/daemonset/affinity.go @@ -1,30 +1,18 @@ package daemonset import ( + "github.com/Dynatrace/dynatrace-operator/pkg/api/status" "github.com/Dynatrace/dynatrace-operator/pkg/util/kubeobjects/node" corev1 "k8s.io/api/core/v1" ) func (b *builder) affinity() *corev1.Affinity { - return &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: b.affinityNodeSelectorTerms(), - }, - }, - } -} - -func (b *builder) affinityNodeSelectorTerms() []corev1.NodeSelectorTerm { - nodeSelectorTerms := []corev1.NodeSelectorTerm{ - kubernetesArchOsSelectorTerm(), + var affinity corev1.Affinity + if b.dk.Status.OneAgent.VersionStatus.Source == status.TenantRegistryVersionSource || b.dk.Status.OneAgent.VersionStatus.Source == status.CustomVersionVersionSource { + affinity = node.AMDOnlyAffinity() + } else { + affinity = node.Affinity() } - return nodeSelectorTerms -} - -func kubernetesArchOsSelectorTerm() corev1.NodeSelectorTerm { - return corev1.NodeSelectorTerm{ - MatchExpressions: node.AffinityNodeRequirementForSupportedArches(), - } + return &affinity } diff --git a/pkg/controllers/dynakube/oneagent/daemonset/affinity_test.go b/pkg/controllers/dynakube/oneagent/daemonset/affinity_test.go index e16e3096ab..4019c068da 100644 --- a/pkg/controllers/dynakube/oneagent/daemonset/affinity_test.go +++ b/pkg/controllers/dynakube/oneagent/daemonset/affinity_test.go @@ -3,39 +3,66 @@ package daemonset import ( "testing" + "github.com/Dynatrace/dynatrace-operator/pkg/api/status" + "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" ) func TestAffinity(t *testing.T) { - dsBuilder := builder{} - affinity := dsBuilder.affinity() - assert.NotContains(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, corev1.NodeSelectorTerm{ - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "beta.kubernetes.io/arch", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"amd64", "arm64", "ppc64le", "s390x"}, + t.Run("none tenant-registry DynaKube has all the architectures", func(t *testing.T) { + dk := dynakube.DynaKube{} + dk.Status.OneAgent.VersionStatus.Source = status.CustomImageVersionSource + dsBuilder := builder{dk: &dk} + affinity := dsBuilder.affinity() + assert.NotContains(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, corev1.NodeSelectorTerm{ + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "beta.kubernetes.io/arch", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"amd64", "arm64", "ppc64le", "s390x"}, + }, + { + Key: "beta.kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, - { - Key: "beta.kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + }) + assert.Contains(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, corev1.NodeSelectorTerm{ + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/arch", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"amd64", "arm64", "ppc64le", "s390x"}, + }, + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, - }, + }) }) - assert.Contains(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, corev1.NodeSelectorTerm{ - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/arch", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"amd64", "arm64", "ppc64le", "s390x"}, - }, - { - Key: "kubernetes.io/os", - Operator: corev1.NodeSelectorOpIn, - Values: []string{"linux"}, + + t.Run("tenant-registry DynaKube has only AMD architectures", func(t *testing.T) { + dk := dynakube.DynaKube{} + dk.Status.OneAgent.VersionStatus.Source = status.TenantRegistryVersionSource + dsBuilder := builder{dk: &dk} + affinity := dsBuilder.affinity() + assert.Contains(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, corev1.NodeSelectorTerm{ + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "kubernetes.io/arch", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"amd64"}, + }, + { + Key: "kubernetes.io/os", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"linux"}, + }, }, - }, + }) }) } diff --git a/pkg/injection/codemodule/installer/url/download.go b/pkg/injection/codemodule/installer/url/download.go index 090261bb80..061b7cd777 100644 --- a/pkg/injection/codemodule/installer/url/download.go +++ b/pkg/injection/codemodule/installer/url/download.go @@ -58,7 +58,6 @@ func (installer Installer) downloadOneAgentWithVersion(ctx context.Context, tmpF installer.props.Os, installer.props.Type, installer.props.Flavor, - installer.props.Arch, ) if getVersionsError != nil { log.Info("failed to get available versions", "err", getVersionsError) diff --git a/pkg/util/kubeobjects/node/affinity.go b/pkg/util/kubeobjects/node/affinity.go index e74078785d..db39995353 100644 --- a/pkg/util/kubeobjects/node/affinity.go +++ b/pkg/util/kubeobjects/node/affinity.go @@ -11,12 +11,22 @@ const ( ) func Affinity() corev1.Affinity { + return AffinityForArches(arch.AMDImage, arch.ARMImage, arch.PPCLEImage, arch.S390Image) +} + +// AMDOnlyAffinity provides an affinity that will only allow deployment on AMD64 nodes. +// This is manly needed for the Dynatrace tenant-registry as it only has AMD64 images. +func AMDOnlyAffinity() corev1.Affinity { + return AffinityForArches(arch.AMDImage) +} + +func AffinityForArches(arches ...string) corev1.Affinity { return corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ NodeSelectorTerms: []corev1.NodeSelectorTerm{ { - MatchExpressions: AffinityNodeRequirementForSupportedArches(), + MatchExpressions: affinityNodeRequirementsForArches(arches...), }, }, }, @@ -24,10 +34,6 @@ func Affinity() corev1.Affinity { } } -func AffinityNodeRequirementForSupportedArches() []corev1.NodeSelectorRequirement { - return affinityNodeRequirementsForArches(arch.AMDImage, arch.ARMImage, arch.PPCLEImage, arch.S390Image) -} - func affinityNodeRequirementsForArches(arches ...string) []corev1.NodeSelectorRequirement { return []corev1.NodeSelectorRequirement{ { diff --git a/pkg/util/kubeobjects/node/affinity_test.go b/pkg/util/kubeobjects/node/affinity_test.go index b5fdd187c5..041a8b6c40 100644 --- a/pkg/util/kubeobjects/node/affinity_test.go +++ b/pkg/util/kubeobjects/node/affinity_test.go @@ -5,12 +5,33 @@ import ( "github.com/Dynatrace/dynatrace-operator/pkg/arch" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" ) -func TestAffinityNodeRequirement(t *testing.T) { - assert.Equal(t, AffinityNodeRequirementForSupportedArches(), affinityNodeRequirementsForArches(arch.AMDImage, arch.ARMImage, arch.PPCLEImage, arch.S390Image)) - assert.Contains(t, AffinityNodeRequirementForSupportedArches(), linuxRequirement()) +func TestAffinity(t *testing.T) { + affinity := Affinity() + + require.NotNil(t, affinity) + require.NotNil(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution) + require.Len(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, 1) + + matchExpression := affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions + assert.Equal(t, matchExpression, affinityNodeRequirementsForArches(arch.AMDImage, arch.ARMImage, arch.PPCLEImage, arch.S390Image)) + assert.Contains(t, matchExpression, linuxRequirement()) +} + +func TestAffinityForArches(t *testing.T) { + expectedArches := []string{"arch1", "arch2", "arch3"} + affinity := AffinityForArches(expectedArches...) + + require.NotNil(t, affinity) + require.NotNil(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution) + require.Len(t, affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, 1) + + matchExpression := affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions + assert.Equal(t, matchExpression, affinityNodeRequirementsForArches(expectedArches...)) + assert.Contains(t, matchExpression, linuxRequirement()) } func linuxRequirement() corev1.NodeSelectorRequirement { diff --git a/pkg/webhook/mutation/pod/oneagent/env.go b/pkg/webhook/mutation/pod/oneagent/env.go index bfc55f6c81..9bf9a32ec9 100644 --- a/pkg/webhook/mutation/pod/oneagent/env.go +++ b/pkg/webhook/mutation/pod/oneagent/env.go @@ -68,7 +68,7 @@ func addVersionDetectionEnvs(container *corev1.Container, labelMapping VersionLa func addInstallerInitEnvs(initContainer *corev1.Container, installer installerInfo) { initContainer.Env = append(initContainer.Env, - corev1.EnvVar{Name: consts.AgentInstallerFlavorEnv, Value: installer.flavor}, + corev1.EnvVar{Name: consts.AgentInstallerFlavorEnv, Value: installer.flavor}, // TODO: is this needed corev1.EnvVar{Name: consts.AgentInstallerTechEnv, Value: installer.technologies}, corev1.EnvVar{Name: consts.AgentInstallPathEnv, Value: installer.installPath}, corev1.EnvVar{Name: consts.AgentInstallerUrlEnv, Value: installer.installerURL}, diff --git a/test/mocks/pkg/clients/dynatrace/client.go b/test/mocks/pkg/clients/dynatrace/client.go index 0bb92f83d0..8be5525119 100644 --- a/test/mocks/pkg/clients/dynatrace/client.go +++ b/test/mocks/pkg/clients/dynatrace/client.go @@ -9,7 +9,6 @@ import ( dynatrace "github.com/Dynatrace/dynatrace-operator/pkg/clients/dynatrace" logmonitoring "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube/logmonitoring" - mock "github.com/stretchr/testify/mock" ) @@ -370,9 +369,9 @@ func (_c *Client_GetAgent_Call) RunAndReturn(run func(context.Context, string, s return _c } -// GetAgentVersions provides a mock function with given fields: ctx, os, installerType, flavor, arch -func (_m *Client) GetAgentVersions(ctx context.Context, os string, installerType string, flavor string, arch string) ([]string, error) { - ret := _m.Called(ctx, os, installerType, flavor, arch) +// GetAgentVersions provides a mock function with given fields: ctx, os, installerType, flavor +func (_m *Client) GetAgentVersions(ctx context.Context, os string, installerType string, flavor string) ([]string, error) { + ret := _m.Called(ctx, os, installerType, flavor) if len(ret) == 0 { panic("no return value specified for GetAgentVersions") @@ -380,19 +379,19 @@ func (_m *Client) GetAgentVersions(ctx context.Context, os string, installerType var r0 []string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) ([]string, error)); ok { - return rf(ctx, os, installerType, flavor, arch) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) ([]string, error)); ok { + return rf(ctx, os, installerType, flavor) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) []string); ok { - r0 = rf(ctx, os, installerType, flavor, arch) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) []string); ok { + r0 = rf(ctx, os, installerType, flavor) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]string) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok { - r1 = rf(ctx, os, installerType, flavor, arch) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, os, installerType, flavor) } else { r1 = ret.Error(1) } @@ -410,14 +409,13 @@ type Client_GetAgentVersions_Call struct { // - os string // - installerType string // - flavor string -// - arch string -func (_e *Client_Expecter) GetAgentVersions(ctx interface{}, os interface{}, installerType interface{}, flavor interface{}, arch interface{}) *Client_GetAgentVersions_Call { - return &Client_GetAgentVersions_Call{Call: _e.mock.On("GetAgentVersions", ctx, os, installerType, flavor, arch)} +func (_e *Client_Expecter) GetAgentVersions(ctx interface{}, os interface{}, installerType interface{}, flavor interface{}) *Client_GetAgentVersions_Call { + return &Client_GetAgentVersions_Call{Call: _e.mock.On("GetAgentVersions", ctx, os, installerType, flavor)} } -func (_c *Client_GetAgentVersions_Call) Run(run func(ctx context.Context, os string, installerType string, flavor string, arch string)) *Client_GetAgentVersions_Call { +func (_c *Client_GetAgentVersions_Call) Run(run func(ctx context.Context, os string, installerType string, flavor string)) *Client_GetAgentVersions_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string)) + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string)) }) return _c } @@ -427,7 +425,7 @@ func (_c *Client_GetAgentVersions_Call) Return(_a0 []string, _a1 error) *Client_ return _c } -func (_c *Client_GetAgentVersions_Call) RunAndReturn(run func(context.Context, string, string, string, string) ([]string, error)) *Client_GetAgentVersions_Call { +func (_c *Client_GetAgentVersions_Call) RunAndReturn(run func(context.Context, string, string, string) ([]string, error)) *Client_GetAgentVersions_Call { _c.Call.Return(run) return _c }