Skip to content

Commit

Permalink
Implement possibility to mount secrets and configmaps (#2310)
Browse files Browse the repository at this point in the history
  • Loading branch information
pPrecel authored Jan 14, 2025
1 parent 3fd40f0 commit 908437e
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 21 deletions.
14 changes: 13 additions & 1 deletion internal/cmd/alpha/app/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type appPushConfig struct {
containerPort types.NullableInt64
istioInject types.NullableBool
expose bool
mountSecrets []string
mountConfigmaps []string
}

func NewAppPushCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
Expand Down Expand Up @@ -69,6 +71,8 @@ func NewAppPushCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
cmd.Flags().Var(&config.containerPort, "container-port", "Port on which the application will be exposed")
cmd.Flags().Var(&config.istioInject, "istio-inject", "Enable Istio for the app")
cmd.Flags().BoolVar(&config.expose, "expose", false, "Creates an ApiRule for the app")
cmd.Flags().StringArrayVar(&config.mountSecrets, "mount-secret", []string{}, "Mount secret content to the "+resources.SecretMountPathPrefix+"<SECRET_NAME> path")
cmd.Flags().StringArrayVar(&config.mountConfigmaps, "mount-config", []string{}, "Mount configmap content to the "+resources.ConfigmapMountPathPrefix+"<CONFIGMAP_NAME> path")

_ = cmd.MarkFlagRequired("name")
cmd.MarkFlagsMutuallyExclusive("image", "dockerfile", "code-path")
Expand Down Expand Up @@ -149,7 +153,15 @@ func runAppPush(cfg *appPushConfig) clierror.Error {

fmt.Printf("\nCreating deployment %s/%s\n", cfg.namespace, cfg.name)

err := resources.CreateDeployment(cfg.Ctx, client, cfg.name, cfg.namespace, image, imagePullSecret, cfg.istioInject)
err := resources.CreateDeployment(cfg.Ctx, client, resources.CreateDeploymentOpts{
Name: cfg.name,
Namespace: cfg.namespace,
Image: image,
ImagePullSecret: imagePullSecret,
InjectIstio: cfg.istioInject,
SecretMounts: cfg.mountSecrets,
ConfigmapMounts: cfg.mountConfigmaps,
})
if err != nil {
return clierror.Wrap(err, clierror.New("failed to create deployment"))
}
Expand Down
99 changes: 86 additions & 13 deletions internal/kube/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,38 +84,64 @@ func CreateClusterRoleBinding(ctx context.Context, client kube.Client, name, nam
return nil
}

func CreateDeployment(ctx context.Context, client kube.Client, name, namespace, image, imagePullSecret string, injectIstio types.NullableBool) error {
const (
SecretMountPathPrefix = "/bindings/secret-"
ConfigmapMountPathPrefix = "/bindings/configmap-"
)

type CreateDeploymentOpts struct {
Name string
Namespace string
Image string
ImagePullSecret string
InjectIstio types.NullableBool
SecretMounts []string
ConfigmapMounts []string
}

func CreateDeployment(ctx context.Context, client kube.Client, opts CreateDeploymentOpts) error {
secretVolumes, secretVolumeMounts := buildSecretVolumes(opts.SecretMounts)
configVolumes, configVolumeMounts := buildConfigmapVolumes(opts.ConfigmapMounts)

deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Name: opts.Name,
Labels: map[string]string{
"app.kubernetes.io/name": name,
"app.kubernetes.io/name": opts.Name,
"app.kubernetes.io/created-by": "kyma-cli",
},
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": name,
"app": opts.Name,
},
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Name: opts.Name,
Labels: map[string]string{
"app": name,
"app": opts.Name,
},
},
Spec: v1.PodSpec{
Volumes: append(secretVolumes, configVolumes...),
Containers: []v1.Container{
{
Ports: []v1.ContainerPort{
{
ContainerPort: 80,
},
},
Name: name,
Image: image,
Name: opts.Name,
Image: opts.Image,
Env: []v1.EnvVar{
{
Name: "SERVICE_BINDING_ROOT",
Value: "/bindings",
},
},
VolumeMounts: append(secretVolumeMounts, configVolumeMounts...),
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceMemory: resource.MustParse("64Mi"),
Expand All @@ -132,22 +158,69 @@ func CreateDeployment(ctx context.Context, client kube.Client, name, namespace,
},
},
}
if injectIstio.Value != nil {
deployment.Spec.Template.ObjectMeta.Labels["sidecar.istio.io/inject"] = injectIstio.String()
if opts.InjectIstio.Value != nil {
deployment.Spec.Template.ObjectMeta.Labels["sidecar.istio.io/inject"] = opts.InjectIstio.String()
}

if imagePullSecret != "" {
if opts.ImagePullSecret != "" {
deployment.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{
{
Name: imagePullSecret,
Name: opts.ImagePullSecret,
},
}
}

_, err := client.Static().AppsV1().Deployments(namespace).Create(ctx, deployment, metav1.CreateOptions{})
_, err := client.Static().AppsV1().Deployments(opts.Namespace).Create(ctx, deployment, metav1.CreateOptions{})
return err
}

func buildSecretVolumes(secretNames []string) ([]v1.Volume, []v1.VolumeMount) {
volumes := []v1.Volume{}
volumeMounts := []v1.VolumeMount{}
for _, secretName := range secretNames {
volumeName := fmt.Sprintf("secret-%s", secretName)
mountPath := fmt.Sprintf("%s%s", SecretMountPathPrefix, secretName)
volumes = append(volumes, v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: secretName,
},
},
})
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: volumeName,
MountPath: mountPath,
})
}

return volumes, volumeMounts
}

func buildConfigmapVolumes(configmapsNames []string) ([]v1.Volume, []v1.VolumeMount) {
volumes := []v1.Volume{}
volumeMounts := []v1.VolumeMount{}
for _, configmapName := range configmapsNames {
volumeName := fmt.Sprintf("configmap-%s", configmapName)
mountPath := fmt.Sprintf("%s%s", ConfigmapMountPathPrefix, configmapName)
volumes = append(volumes, v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{
LocalObjectReference: v1.LocalObjectReference{
Name: configmapName,
},
},
},
})
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: volumeName,
MountPath: mountPath,
})
}
return volumes, volumeMounts
}

func CreateService(ctx context.Context, client kube.Client, name, namespace string, port int32) error {
service := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Expand Down
42 changes: 35 additions & 7 deletions internal/kube/resources/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ func Test_CreateDeployment(t *testing.T) {
t.Parallel()
trueValue := true
tests := []struct {
name string
deploymentName string
namespace string
image string
istioInject *bool
wantErr bool
name string
deploymentName string
namespace string
image string
istioInject *bool
secretMounts []string
configmapMounts []string
wantErr bool
}{
{
name: "create deployment",
Expand All @@ -126,6 +128,22 @@ func Test_CreateDeployment(t *testing.T) {
image: "nginx",
wantErr: true,
},
{
name: "create deployment with volumes",
deploymentName: "deployment",
namespace: "default",
image: "nginx",
secretMounts: []string{
"secret-1",
"secret-2",
"secret-3",
},
configmapMounts: []string{
"configmap-1",
"configmap-2",
"configmap-3",
},
},
}

ctx := context.Background()
Expand All @@ -135,6 +153,8 @@ func Test_CreateDeployment(t *testing.T) {
image := tt.image
istioInject := tt.istioInject
wantErr := tt.wantErr
secretMounts := tt.secretMounts
configmapMounts := tt.configmapMounts

t.Run(tt.name, func(t *testing.T) {
existingDeployment := appsv1.Deployment{
Expand All @@ -150,7 +170,15 @@ func Test_CreateDeployment(t *testing.T) {
TestKubernetesInterface: staticClient,
}

err := CreateDeployment(ctx, kubeClient, deploymentName, namespace, image, "", types.NullableBool{Value: istioInject})
err := CreateDeployment(ctx, kubeClient, CreateDeploymentOpts{
Name: deploymentName,
Namespace: namespace,
Image: image,
ImagePullSecret: "",
InjectIstio: types.NullableBool{Value: istioInject},
SecretMounts: secretMounts,
ConfigmapMounts: configmapMounts,
})
if wantErr {
require.Error(t, err)
} else {
Expand Down

0 comments on commit 908437e

Please sign in to comment.