Skip to content

Commit

Permalink
mco:alertmanager: Allow mounting of arbitrary secrets via volumes in …
Browse files Browse the repository at this point in the history
…advanced config

Signed-off-by: Philip Gough <[email protected]>
  • Loading branch information
philipgough committed Aug 28, 2024
1 parent 905d976 commit c21c3b0
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,88 +40,104 @@ func (r *MCORenderer) newAlertManagerRenderer() {
}
}

func (r *MCORenderer) renderAlertManagerStatefulSet(res *resource.Resource,
namespace string, labels map[string]string) (*unstructured.Unstructured, error) {
func (r *MCORenderer) renderAlertManagerStatefulSet(res *resource.Resource, namespace string, labels map[string]string) (*unstructured.Unstructured, error) {
u, err := r.renderer.RenderNamespace(res, namespace, labels)
if err != nil {
return nil, err
}

obj := util.GetK8sObj(u.GetKind())
err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj)
if err != nil {
return nil, err
}

crLabelKey := mcoconfig.GetCrLabelKey()
imagePullPolicy := mcoconfig.GetImagePullPolicy(r.cr.Spec)
dep := obj.(*v1.StatefulSet)
dep.ObjectMeta.Labels[crLabelKey] = r.cr.Name
dep.Name = mcoconfig.GetOperandName(mcoconfig.Alertmanager)
dep.Spec.Selector.MatchLabels[crLabelKey] = r.cr.Name
dep.Spec.Template.ObjectMeta.Labels[crLabelKey] = r.cr.Name
dep.Name = mcoconfig.GetOperandName(mcoconfig.Alertmanager)
dep.Spec.Replicas = mcoconfig.GetReplicas(mcoconfig.Alertmanager, r.cr.Spec.InstanceSize, r.cr.Spec.AdvancedConfig)

spec := &dep.Spec.Template.Spec
spec.NodeSelector = r.cr.Spec.NodeSelector
spec.Tolerations = r.cr.Spec.Tolerations
spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: mcoconfig.GetImagePullSecret(r.cr.Spec)}}

imagePullPolicy := mcoconfig.GetImagePullPolicy(r.cr.Spec)
spec.Containers[0].ImagePullPolicy = imagePullPolicy
args := spec.Containers[0].Args
if len(spec.Containers) != 4 {
return nil, fmt.Errorf("expected 4 containers in alertmanager statefulset, got %d", len(spec.Containers))
}

// set the container names for readability
alertManagerContainer := &spec.Containers[0]
configReloaderContainer := &spec.Containers[1]
oauthProxyContainer := &spec.Containers[2]
kubeRbacProxyContainer := &spec.Containers[3]

alertManagerContainer.ImagePullPolicy = imagePullPolicy
if *dep.Spec.Replicas > 1 {
for i := int32(0); i < *dep.Spec.Replicas; i++ {
args = append(args, "--cluster.peer="+
alertManagerContainer.Args = append(alertManagerContainer.Args, "--cluster.peer="+
mcoconfig.GetOperandName(mcoconfig.Alertmanager)+"-"+
strconv.Itoa(int(i))+".alertmanager-operated."+
mcoconfig.GetDefaultNamespace()+".svc:9094")
}
}
alertManagerContainer.Resources = mcoconfig.GetResources(mcoconfig.Alertmanager, r.cr.Spec.InstanceSize, r.cr.Spec.AdvancedConfig)
alertManagerContainer.Image = mcoconfig.DefaultImgRepository + "/" + mcoconfig.AlertManagerImgName + ":" + mcoconfig.DefaultImgTagSuffix
//replace the alertmanager image
found, image := mcoconfig.ReplaceImage(r.cr.Annotations, mcoconfig.DefaultImgRepository+"/"+mcoconfig.AlertManagerImgName, mcoconfig.AlertManagerImgKey)
if found {
alertManagerContainer.Image = image
}

// mount the secrets referenced in the advanced config as volumes
if r.cr.Spec.AdvancedConfig != nil && r.cr.Spec.AdvancedConfig.Alertmanager != nil {
for _, secret := range r.cr.Spec.AdvancedConfig.Alertmanager.Secrets {
volume := corev1.Volume{
Name: fmt.Sprintf("secret-%s", secret),
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secret,
},
},
}
mount := corev1.VolumeMount{
Name: secret,
MountPath: fmt.Sprintf("/etc/alertmanager/secrets/%s", secret),
ReadOnly: true,
}

spec.Containers[0].Args = args
spec.Containers[0].Resources = mcoconfig.GetResources(mcoconfig.Alertmanager, r.cr.Spec.InstanceSize, r.cr.Spec.AdvancedConfig)

spec.Containers[1].ImagePullPolicy = imagePullPolicy
spec.NodeSelector = r.cr.Spec.NodeSelector
spec.Tolerations = r.cr.Spec.Tolerations
spec.ImagePullSecrets = []corev1.LocalObjectReference{
{Name: mcoconfig.GetImagePullSecret(r.cr.Spec)},
dep.Spec.Template.Spec.Volumes = append(dep.Spec.Template.Spec.Volumes, volume)
alertManagerContainer.VolumeMounts = append(alertManagerContainer.VolumeMounts, mount)
}
}

spec.Containers[0].Image = mcoconfig.DefaultImgRepository + "/" + mcoconfig.AlertManagerImgName +
":" + mcoconfig.DefaultImgTagSuffix
//replace the alertmanager and config-reloader images
found, image := mcoconfig.ReplaceImage(
r.cr.Annotations,
mcoconfig.DefaultImgRepository+"/"+mcoconfig.AlertManagerImgName,
mcoconfig.AlertManagerImgKey)
configReloaderContainer.ImagePullPolicy = imagePullPolicy
//replace the config-reloader image
found, image = mcoconfig.ReplaceImage(r.cr.Annotations, mcoconfig.ConfigmapReloaderImgRepo, mcoconfig.ConfigmapReloaderKey)
if found {
spec.Containers[0].Image = image
configReloaderContainer.Image = image
}

found, image = mcoconfig.ReplaceImage(r.cr.Annotations, mcoconfig.ConfigmapReloaderImgRepo,
mcoconfig.ConfigmapReloaderKey)
if found {
spec.Containers[1].Image = image
}
// the oauth-proxy image only exists in mch-image-manifest configmap
// pass nil annotation to make sure oauth-proxy overrided from mch-image-manifest
found, image = mcoconfig.ReplaceImage(nil, mcoconfig.OauthProxyImgRepo,
mcoconfig.OauthProxyKey)
// pass nil annotation to make sure oauth-proxy overridden from mch-image-manifest
found, image = mcoconfig.ReplaceImage(nil, mcoconfig.OauthProxyImgRepo, mcoconfig.OauthProxyKey)
if found {
spec.Containers[2].Image = image
oauthProxyContainer.Image = image
}
spec.Containers[2].ImagePullPolicy = imagePullPolicy
oauthProxyContainer.ImagePullPolicy = imagePullPolicy

// fail if kube-rbac-proxy container is not at the expected index
if spec.Containers[3].Name != "kube-rbac-proxy" {
return nil, fmt.Errorf("kube-rbac-proxy container not found in statefulset")
}
if ok, image := mcoconfig.ReplaceImage(r.cr.Annotations, mcoconfig.DefaultImgRepository+"/"+mcoconfig.KubeRBACProxyImgName, mcoconfig.KubeRBACProxyKey); ok {
spec.Containers[3].Image = image
kubeRbacProxyContainer.Image = image
}
spec.Containers[3].ImagePullPolicy = imagePullPolicy
kubeRbacProxyContainer.ImagePullPolicy = imagePullPolicy

//replace the volumeClaimTemplate
dep.Spec.VolumeClaimTemplates[0].Spec.StorageClassName = &r.cr.Spec.StorageConfig.StorageClass
dep.Spec.VolumeClaimTemplates[0].Spec.Resources.Requests[corev1.ResourceStorage] =
apiresource.MustParse(r.cr.Spec.StorageConfig.AlertmanagerStorageSize)
dep.Spec.VolumeClaimTemplates[0].Spec.Resources.Requests[corev1.ResourceStorage] = apiresource.MustParse(r.cr.Spec.StorageConfig.AlertmanagerStorageSize)

unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@ func TestAlertManagerRendererMCOConfig(t *testing.T) {
ret := makeBaseMco()
replicas := int32(3)
ret.Spec.AdvancedConfig = &mcov1beta2.AdvancedConfig{
Alertmanager: &mcov1beta2.CommonSpec{
Replicas: &replicas,
Alertmanager: &mcov1beta2.AlertmanagerSpec{
CommonSpec: mcov1beta2.CommonSpec{
Replicas: &replicas,
},
},
}
return ret
Expand All @@ -167,15 +169,18 @@ func TestAlertManagerRendererMCOConfig(t *testing.T) {
mco: func() *mcov1beta2.MultiClusterObservability {
ret := makeBaseMco()
ret.Spec.AdvancedConfig = &mcov1beta2.AdvancedConfig{
Alertmanager: &mcov1beta2.CommonSpec{
Resources: &corev1.ResourceRequirements{
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("500m"),
corev1.ResourceMemory: resource.MustParse("500Mi"),

Alertmanager: &mcov1beta2.AlertmanagerSpec{
CommonSpec: mcov1beta2.CommonSpec{
Resources: &corev1.ResourceRequirements{
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("500m"),
corev1.ResourceMemory: resource.MustParse("500Mi"),
},
},
},
},
Expand All @@ -189,6 +194,46 @@ func TestAlertManagerRendererMCOConfig(t *testing.T) {
assert.Equal(t, resource.MustParse("500Mi"), sts.Spec.Template.Spec.Containers[0].Resources.Requests[corev1.ResourceMemory])
},
},
"secrets": {
mco: func() *mcov1beta2.MultiClusterObservability {
ret := makeBaseMco()
ret.Spec.AdvancedConfig = &mcov1beta2.AdvancedConfig{
Alertmanager: &mcov1beta2.AlertmanagerSpec{
Secrets: []string{"this", "that"},
},
}
return ret
},
expect: func(t *testing.T, sts *appsv1.StatefulSet) {
assert.Contains(t, sts.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "secret-this",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "this",
},
},
})
assert.Contains(t, sts.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: "this",
MountPath: "/etc/alertmanager/secrets/this",
ReadOnly: true,
})

assert.Contains(t, sts.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "secret-that",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "that",
},
},
})
assert.Contains(t, sts.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: "that",
MountPath: "/etc/alertmanager/secrets/that",
ReadOnly: true,
})
},
},
}

for name, tc := range testCases {
Expand Down

0 comments on commit c21c3b0

Please sign in to comment.