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

Update Powermax to handle Minimal Manifests with Mount Credentials #872

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
10 changes: 7 additions & 3 deletions controllers/csm_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ func (r *ContainerStorageModuleReconciler) SyncCSM(ctx context.Context, cr csmv1
modules.AddReverseProxyServiceName(&controller.Deployment)

// Set the secret mount for powermax controller.
_, err := drivers.SetPowerMaxSecretMount(&controller.Deployment, cr)
err := drivers.DynamicallyMountPowermaxContent(&controller.Deployment, cr)
if err != nil {
return err
}
Expand All @@ -783,14 +783,14 @@ func (r *ContainerStorageModuleReconciler) SyncCSM(ctx context.Context, cr csmv1
log.Info("Injecting CSI ReverseProxy")
dp, err := modules.ReverseProxyInjectDeployment(controller.Deployment, cr, operatorConfig)
if err != nil {
return fmt.Errorf("injecting replication into deployment: %v", err)
return fmt.Errorf("unable to inject ReverseProxy into deployment: %v", err)
}

controller.Deployment = *dp
}

// Set the secret mount for powermax node.
_, err := drivers.SetPowerMaxSecretMount(&node.DaemonSetApplyConfig, cr)
err := drivers.DynamicallyMountPowermaxContent(&node.DaemonSetApplyConfig, cr)
if err != nil {
return err
}
Expand Down Expand Up @@ -1383,6 +1383,10 @@ func (r *ContainerStorageModuleReconciler) PreChecks(ctx context.Context, cr *cs
if err != nil {
return fmt.Errorf("failed powermax validation: %v", err)
}

// To ensure that we are handling minimal manifests correctly and consistent, we must reset DeployAsSidecar to the original value.
// This variable will be set correctly if the reverseproxy is found in the manifests.
modules.ResetDeployAsSidecar()
default:
// Go to checkUpgrade if it is standalone module i.e. app mobility or authorizatio proxy server
if cr.HasModule(csmv1.ApplicationMobility) || cr.HasModule(csmv1.AuthorizationServer) {
Expand Down
10 changes: 0 additions & 10 deletions operatorconfig/driverconfig/powermax/v2.14.0/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -250,16 +250,6 @@ spec:
value: controller
- name: X_CSI_POWERMAX_SKIP_CERTIFICATE_VALIDATION
value: "true"
- name: X_CSI_POWERMAX_USER
valueFrom:
secretKeyRef:
key: username
name: powermax-creds
- name: X_CSI_POWERMAX_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: powermax-creds
- name: X_CSI_POWERMAX_DEBUG
value: "<X_CSI_POWERMAX_DEBUG>"
- name: X_CSI_GRPC_MAX_THREADS
Expand Down
10 changes: 0 additions & 10 deletions operatorconfig/driverconfig/powermax/v2.14.0/node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,6 @@ spec:
value: "<KUBELET_CONFIG_DIR>/plugins/powermax.emc.dell.com/disks"
- name: X_CSI_POWERMAX_SKIP_CERTIFICATE_VALIDATION
value: "true"
- name: X_CSI_POWERMAX_USER
valueFrom:
secretKeyRef:
name: powermax-creds
key: username
- name: X_CSI_POWERMAX_PASSWORD
valueFrom:
secretKeyRef:
name: powermax-creds
key: password
- name: X_CSI_POWERMAX_NODENAME
valueFrom:
fieldRef:
Expand Down
6 changes: 6 additions & 0 deletions operatorconfig/moduleconfig/common/version-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,9 @@ powermax:
replication: "v1.11.0"
observability: "v1.11.0"
resiliency: "v1.12.0"
v2.14.0:
csireverseproxy: "v2.13.0"
authorization: "v2.1.0"
replication: "v1.11.0"
observability: "v1.11.0"
resiliency: "v1.12.0"
98 changes: 75 additions & 23 deletions pkg/drivers/powermax.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"fmt"
"log"
"os"
"slices"
"strconv"
"strings"

Expand Down Expand Up @@ -91,7 +92,7 @@ func PrecheckPowerMax(ctx context.Context, cr *csmv1.ContainerStorageModule, ope
secretName = cr.Spec.Driver.AuthSecret
}

useReverseProxySecret := useReverseProxySecret(cr)
useReverseProxySecret := UseReverseProxySecret(cr)
if useReverseProxySecret {
log.Infof("[PrecheckPowerMax] Using Secret: %s", secretName)
} else {
Expand Down Expand Up @@ -121,7 +122,7 @@ func PrecheckPowerMax(ctx context.Context, cr *csmv1.ContainerStorageModule, ope
return nil
}

func useReverseProxySecret(cr *csmv1.ContainerStorageModule) bool {
func UseReverseProxySecret(cr *csmv1.ContainerStorageModule) bool {
useSecret := false

if cr.Spec.Driver.Common == nil {
Expand Down Expand Up @@ -382,27 +383,31 @@ func ModifyPowermaxCR(yamlString string, cr csmv1.ContainerStorageModule, fileTy
return yamlString
}

func SetPowerMaxSecretMount(configuration interface{}, cr csmv1.ContainerStorageModule) (bool, error) {
if useReverseProxySecret(&cr) {
secretName := cr.Spec.Driver.AuthSecret
func DynamicallyMountPowermaxContent(configuration interface{}, cr csmv1.ContainerStorageModule) error {
var podTemplate *acorev1.PodTemplateSpecApplyConfiguration
switch configuration := configuration.(type) {
case *v1.DeploymentApplyConfiguration:
dp := configuration
podTemplate = dp.Spec.Template
case *v1.DaemonSetApplyConfiguration:
ds := configuration
podTemplate = ds.Spec.Template
}

if podTemplate == nil {
return fmt.Errorf("invalid type passed through")
}

secretName := cr.Name + "-creds"
if cr.Spec.Driver.AuthSecret != "" {
secretName = cr.Spec.Driver.AuthSecret
}

if UseReverseProxySecret(&cr) {
volumeName := CSIPowerMaxSecretVolumeName
optional := false
mountPath := CSIPowerMaxSecretMountPath

var podTemplate *acorev1.PodTemplateSpecApplyConfiguration
switch configuration := configuration.(type) {
case *v1.DeploymentApplyConfiguration:
dp := configuration
podTemplate = dp.Spec.Template
case *v1.DaemonSetApplyConfiguration:
ds := configuration
podTemplate = ds.Spec.Template
}

if podTemplate == nil {
return false, fmt.Errorf("invalid type passed through")
}

// Adding volume
podTemplate.Spec.Volumes = append(podTemplate.Spec.Volumes,
acorev1.VolumeApplyConfiguration{
Expand All @@ -413,17 +418,24 @@ func SetPowerMaxSecretMount(configuration interface{}, cr csmv1.ContainerStorage
// Adding volume mount for both the reverseproxy and driver
for i, cnt := range podTemplate.Spec.Containers {
if *cnt.Name == "driver" || *cnt.Name == "reverseproxy" {
SetPowerMaxSecretVariables(&podTemplate.Spec.Containers[i], volumeName, mountPath)
setPowermaxMountCredentialContent(&podTemplate.Spec.Containers[i], volumeName, mountPath)
}
}

return true, nil
return nil
}

for i, cnt := range podTemplate.Spec.Containers {
if *cnt.Name == "driver" {
SetPowermaxConfigContent(&podTemplate.Spec.Containers[i], secretName)
break
}
}

return false, nil
return nil
}

func SetPowerMaxSecretVariables(ct *acorev1.ContainerApplyConfiguration, mN, mP string) {
func setPowermaxMountCredentialContent(ct *acorev1.ContainerApplyConfiguration, mN, mP string) {
ct.VolumeMounts = append(ct.VolumeMounts, acorev1.VolumeMountApplyConfiguration{Name: &mN, MountPath: &mP})

volumeName := CSIPowerMaxSecretFilePath
Expand All @@ -436,6 +448,46 @@ func SetPowerMaxSecretVariables(ct *acorev1.ContainerApplyConfiguration, mN, mP
acorev1.EnvVarApplyConfiguration{Name: &useSecretEnv, Value: &useSecretValue})
}

func SetPowermaxConfigContent(ct *acorev1.ContainerApplyConfiguration, secretName string) {
userNameVariable := "X_CSI_POWERMAX_USER"
userNameKey := "username"
userPasswordVariable := "X_CSI_POWERMAX_PASSWORD" // #nosec G101
userPasswordKey := "password"
dynamicallyAddEnvironmentVariable(ct, acorev1.EnvVarApplyConfiguration{
Name: &userNameVariable,
ValueFrom: &acorev1.EnvVarSourceApplyConfiguration{
SecretKeyRef: &acorev1.SecretKeySelectorApplyConfiguration{
Key: &userNameKey,
LocalObjectReferenceApplyConfiguration: acorev1.LocalObjectReferenceApplyConfiguration{
Name: &secretName,
},
},
},
})

dynamicallyAddEnvironmentVariable(ct, acorev1.EnvVarApplyConfiguration{
Name: &userPasswordVariable,
ValueFrom: &acorev1.EnvVarSourceApplyConfiguration{
SecretKeyRef: &acorev1.SecretKeySelectorApplyConfiguration{
Key: &userPasswordKey,
LocalObjectReferenceApplyConfiguration: acorev1.LocalObjectReferenceApplyConfiguration{
Name: &secretName,
},
},
},
})
}

func dynamicallyAddEnvironmentVariable(ct *acorev1.ContainerApplyConfiguration, envVar acorev1.EnvVarApplyConfiguration) {
contains := slices.ContainsFunc(ct.Env,
func(v acorev1.EnvVarApplyConfiguration) bool { return *(v.Name) == *(envVar.Name) },
)

if !contains {
ct.Env = append(ct.Env, envVar)
}
}

func getApplyCertVolumePowermax(cr csmv1.ContainerStorageModule) (*acorev1.VolumeApplyConfiguration, error) {
name := "certs"
secretName := fmt.Sprintf("%s-%s", cr.Name, name)
Expand Down
49 changes: 43 additions & 6 deletions pkg/drivers/powermax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestPrecheckPowerMax(t *testing.T) {
}
}

func TestSetPowerMaxSecretMount(t *testing.T) {
func TestDynamicallyMountPowermaxContent(t *testing.T) {
containerName := "driver"
volumeName := "myVolume"
tests := []struct {
Expand All @@ -95,7 +95,7 @@ func TestSetPowerMaxSecretMount(t *testing.T) {
expectedErr error
}{
{
name: "success: pass through deployment configuration",
name: "success: dynamically mount secret for deployment",
configuration: &v1.DeploymentApplyConfiguration{
Spec: &v1.DeploymentSpecApplyConfiguration{
Template: &acorev1.PodTemplateSpecApplyConfiguration{
Expand Down Expand Up @@ -132,7 +132,44 @@ func TestSetPowerMaxSecretMount(t *testing.T) {
expectedErr: nil,
},
{
name: "success: pass through daemonset configuration",
name: "success: dynamically mount config content for deployment",
configuration: &v1.DeploymentApplyConfiguration{
Spec: &v1.DeploymentSpecApplyConfiguration{
Template: &acorev1.PodTemplateSpecApplyConfiguration{
Spec: &acorev1.PodSpecApplyConfiguration{
Volumes: []acorev1.VolumeApplyConfiguration{
{
Name: &volumeName,
},
},
Containers: []acorev1.ContainerApplyConfiguration{
{
Name: &containerName,
VolumeMounts: []acorev1.VolumeMountApplyConfiguration{
{
Name: &volumeName,
},
},
},
},
},
},
},
},
cr: csmv1.ContainerStorageModule{
Spec: csmv1.ContainerStorageModuleSpec{
Driver: csmv1.Driver{
AuthSecret: "powermax-config",
Common: &csmv1.ContainerTemplate{
Envs: []corev1.EnvVar{{Name: "X_CSI_REVPROXY_USE_SECRET", Value: "false"}},
},
},
},
},
expectedErr: nil,
},
{
name: "success: dynamically mount secret for daemonset",
configuration: &v1.DaemonSetApplyConfiguration{
Spec: &v1.DaemonSetSpecApplyConfiguration{
Template: &acorev1.PodTemplateSpecApplyConfiguration{
Expand All @@ -154,8 +191,8 @@ func TestSetPowerMaxSecretMount(t *testing.T) {
},
{
name: "success: empty envs",
configuration: &v1.ReplicaSetApplyConfiguration{
Spec: &v1.ReplicaSetSpecApplyConfiguration{
configuration: &v1.DeploymentApplyConfiguration{
Spec: &v1.DeploymentSpecApplyConfiguration{
Template: &acorev1.PodTemplateSpecApplyConfiguration{
Spec: &acorev1.PodSpecApplyConfiguration{},
},
Expand Down Expand Up @@ -195,7 +232,7 @@ func TestSetPowerMaxSecretMount(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := SetPowerMaxSecretMount(tt.configuration, tt.cr)
err := DynamicallyMountPowermaxContent(tt.configuration, tt.cr)
if tt.expectedErr == nil {
assert.Nil(t, err)
} else {
Expand Down
Loading
Loading