Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature flag for ignoring proxy within oneAgent and activeGate #737

Merged
merged 5 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/api/v1beta1/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
AnnotationFeatureActiveGateAppArmor = AnnotationFeaturePrefix + "activegate-apparmor"
AnnotationFeatureActiveGateReadOnlyFilesystem = AnnotationFeaturePrefix + "activegate-readonly-fs"
AnnotationFeatureAutomaticKubernetesApiMonitoring = AnnotationFeaturePrefix + "automatic-kubernetes-api-monitoring"
AnnotationFeatureActiveGateIgnoreProxy = AnnotationFeaturePrefix + "activegate-ignore-proxy"

// statsD
AnnotationFeatureUseActiveGateImageForStatsd = AnnotationFeaturePrefix + "use-activegate-image-for-statsd"
Expand All @@ -49,6 +50,7 @@ const (
AnnotationFeatureOneAgentMaxUnavailable = AnnotationFeaturePrefix + "oneagent-max-unavailable"
AnnotationFeatureDisableReadOnlyOneAgent = AnnotationFeaturePrefix + "disable-oneagent-readonly-host-fs"
AnnotationFeatureEnableMultipleOsAgentsOnNode = AnnotationFeaturePrefix + "multiple-osagents-on-node"
AnnotationFeatureOneAgentIgnoreProxy = AnnotationFeaturePrefix + "oneagent-ignore-proxy"

// injection (webhook)
AnnotationFeatureEnableWebhookReinvocationPolicy = AnnotationFeaturePrefix + "enable-webhook-reinvocation-policy"
Expand Down Expand Up @@ -180,6 +182,16 @@ func (dk *DynaKube) FeatureActiveGateAppArmor() bool {
return dk.getFeatureFlagRaw(AnnotationFeatureActiveGateAppArmor) == "true"
}

// FeatureOneAgentIgnoreProxy is a feature flag to ignore the proxy for oneAgents when set in CR
func (dk *DynaKube) FeatureOneAgentIgnoreProxy() bool {
return dk.getFeatureFlagRaw(AnnotationFeatureOneAgentIgnoreProxy) == "true"
}

// FeatureActiveGateIgnoreProxy is a feature flag to ignore the proxy for ActiveGate when set in CR
func (dk *DynaKube) FeatureActiveGateIgnoreProxy() bool {
return dk.getFeatureFlagRaw(AnnotationFeatureActiveGateIgnoreProxy) == "true"
}

func (dk *DynaKube) getFeatureFlagRaw(annotation string) string {
if raw, ok := dk.Annotations[annotation]; ok {
return raw
Expand Down
10 changes: 9 additions & 1 deletion src/api/v1beta1/properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,18 @@ func (dk *DynaKube) HasActiveGateCaCert() bool {
return dk.ActiveGateMode() && dk.Spec.ActiveGate.TlsSecretName != ""
}

func (dk *DynaKube) HasProxy() bool {
func (dk *DynaKube) hasProxy() bool {
return dk.Spec.Proxy != nil && (dk.Spec.Proxy.Value != "" || dk.Spec.Proxy.ValueFrom != "")
}

func (dk *DynaKube) NeedsActiveGateProxy() bool {
return !dk.FeatureActiveGateIgnoreProxy() && dk.hasProxy()
}

func (dk *DynaKube) NeedsOneAgentProxy() bool {
return !dk.FeatureOneAgentIgnoreProxy() && dk.hasProxy()
}

// ShouldAutoUpdateOneAgent returns true if the Operator should update OneAgent instances automatically.
func (dk *DynaKube) ShouldAutoUpdateOneAgent() bool {
if dk.CloudNativeFullstackMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func buildVolumes(stsProperties *statefulSetProperties, extraContainerBuilders [

volumes = append(volumes, stsProperties.volumes...)

if stsProperties.HasProxy() {
if stsProperties.NeedsActiveGateProxy() {
volumes = append(volumes, buildProxyVolumes()...)
}

Expand Down Expand Up @@ -368,7 +368,7 @@ func buildVolumeMounts(stsProperties *statefulSetProperties) []corev1.VolumeMoun

volumeMounts = append(volumeMounts, stsProperties.containerVolumeMounts...)

if stsProperties.HasProxy() {
if stsProperties.NeedsActiveGateProxy() {
volumeMounts = append(volumeMounts, buildProxyMounts()...)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,39 @@ func TestStatefulSet_VolumeMounts(t *testing.T) {
SubPath: InternalProxySecretPassword,
})
})
t.Run(`with proxy from value source and feature flag to ignore proxy on activeGate enabled`, func(t *testing.T) {
instance.Spec.Proxy = &dynatracev1beta1.DynaKubeProxy{ValueFrom: testName}
instance.Annotations[dynatracev1beta1.AnnotationFeatureActiveGateIgnoreProxy] = "true"
volumeMounts := buildVolumeMounts(NewStatefulSetProperties(instance, capabilityProperties, "", "", "", "", "", nil, nil, nil))

assert.NotContains(t, volumeMounts, corev1.VolumeMount{
ReadOnly: true,
Name: InternalProxySecretVolumeName,
MountPath: InternalProxySecretHostMountPath,
SubPath: InternalProxySecretHost,
})

assert.NotContains(t, volumeMounts, corev1.VolumeMount{
ReadOnly: true,
Name: InternalProxySecretVolumeName,
MountPath: InternalProxySecretPortMountPath,
SubPath: InternalProxySecretPort,
})

assert.NotContains(t, volumeMounts, corev1.VolumeMount{
ReadOnly: true,
Name: InternalProxySecretVolumeName,
MountPath: InternalProxySecretUsernameMountPath,
SubPath: InternalProxySecretUsername,
})

assert.NotContains(t, volumeMounts, corev1.VolumeMount{
ReadOnly: true,
Name: InternalProxySecretVolumeName,
MountPath: InternalProxySecretPasswordMountPath,
SubPath: InternalProxySecretPassword,
})
})
}

func TestStatefulSet_Resources(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/dynakube/dynakube_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (controller *DynakubeController) reconcileActiveGate(ctx context.Context, d

func (controller *DynakubeController) reconcileActiveGateProxySecret(ctx context.Context, dynakubeState *status.DynakubeState) bool {
luhi-DT marked this conversation as resolved.
Show resolved Hide resolved
gen := agproxysecret.NewActiveGateProxySecretGenerator(controller.client, controller.apiReader, dynakubeState.Instance.Namespace, log)
if dynakubeState.Instance.HasProxy() {
if dynakubeState.Instance.NeedsActiveGateProxy() {
upd, err := gen.GenerateForDynakube(ctx, dynakubeState.Instance)
if dynakubeState.Error(err) || dynakubeState.Update(upd, "new ActiveGate proxy secret created") {
return false
Expand Down
30 changes: 30 additions & 0 deletions src/controllers/dynakube/dynakube_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,36 @@ func TestReconcileActiveGate_Reconcile(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, proxySecret)
})
t.Run(`has proxy secret but feature flag disables proxy`, func(t *testing.T) {
mockClient := createDTMockClient(dtclient.TokenScopes{dtclient.TokenScopeInstallerDownload},
dtclient.TokenScopes{dtclient.TokenScopeDataExport})
instance := &dynatracev1beta1.DynaKube{
ObjectMeta: metav1.ObjectMeta{
Name: testName,
Namespace: testNamespace,
},
Spec: dynatracev1beta1.DynaKubeSpec{
Proxy: &dynatracev1beta1.DynaKubeProxy{
Value: "https://proxy:1234",
ValueFrom: "",
}}}
instance.Annotations = map[string]string{dynatracev1beta1.AnnotationFeatureActiveGateIgnoreProxy: "true"}
controller := createFakeClientAndReconcile(mockClient, instance, testPaasToken, testAPIToken)

result, err := controller.Reconcile(context.TODO(), reconcile.Request{
NamespacedName: types.NamespacedName{Namespace: testNamespace, Name: testName},
})

assert.NoError(t, err)
assert.NotNil(t, result)

var proxySecret corev1.Secret
name := agproxysecret.BuildProxySecretName()
err = controller.client.Get(context.TODO(), client.ObjectKey{Name: name, Namespace: testNamespace}, &proxySecret)

assert.Error(t, err)
assert.True(t, k8serrors.IsNotFound(err))
})
}

func TestReconcileOnlyOneTokenProvided_Reconcile(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/dynakube/oneagent/daemonset/arguments.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (dsInfo *builderInfo) appendNetworkZoneArg(args []string) []string {
}

func (dsInfo *builderInfo) appendProxyArg(args []string) []string {
if dsInfo.hasProxy() {
if dsInfo.instance.NeedsOneAgentProxy() {
return append(args, "--set-proxy=$(https_proxy)")
}
return args
Expand Down
7 changes: 7 additions & 0 deletions src/controllers/dynakube/oneagent/daemonset/arguments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func TestPodSpec_Arguments(t *testing.T) {
},
}

instance.Annotations = map[string]string{}
podSpecs := dsInfo.podSpec()
require.NotNil(t, podSpecs)
require.NotEmpty(t, podSpecs.Containers)
Expand All @@ -98,6 +99,12 @@ func TestPodSpec_Arguments(t *testing.T) {
podSpecs = dsInfo.podSpec()
assert.NotContains(t, podSpecs.Containers[0].Args, "--set-proxy=$(https_proxy)")
})
t.Run(`has proxy arg but feature flag to ignore is enabled`, func(t *testing.T) {
instance.Spec.Proxy = &dynatracev1beta1.DynaKubeProxy{Value: testValue}
instance.Annotations[dynatracev1beta1.AnnotationFeatureOneAgentIgnoreProxy] = "true"
podSpecs = dsInfo.podSpec()
assert.NotContains(t, podSpecs.Containers[0].Args, "--set-proxy=$(https_proxy)")
})
t.Run(`has network zone arg`, func(t *testing.T) {
instance.Spec.NetworkZone = testValue
podSpecs = dsInfo.podSpec()
Expand Down