Skip to content

Commit

Permalink
Mount with subpath to avoid hidden files in the build context
Browse files Browse the repository at this point in the history
Signed-off-by: Ricardo Zanini <[email protected]>
  • Loading branch information
ricardozanini committed Aug 21, 2023
1 parent 37f3b2c commit 73641b4
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 17 deletions.
44 changes: 27 additions & 17 deletions container-builder/builder/kubernetes/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
)

type configMapVolumeBuildContext struct {
VolumeMount corev1.VolumeMount
VolumeMount []corev1.VolumeMount
Volume corev1.Volume
}

Expand All @@ -54,38 +54,48 @@ func addResourcesToBuilderContextVolume(ctx context.Context, client client.Clien
klog.ErrorS(err, "Failed to fetch configMap to add to build context", "configMap", resVol.ReferenceName, "Namespace", build.Namespace)
return err
}
if _, ok := mounts[resVol.DestinationDir]; !ok {
volName := uuid.NewString()
entry, ok := mounts[resVol.DestinationDir]
var volName string
if ok {
volName = entry.Volume.Name
} else {
volName = uuid.NewString()
mounts[resVol.DestinationDir] = configMapVolumeBuildContext{
VolumeMount: corev1.VolumeMount{
Name: volName,
MountPath: path.Join(task.ContextDir, resVol.DestinationDir),
ReadOnly: true,
},
Volume: corev1.Volume{
Name: volName,
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{},
},
},
}
entry = mounts[resVol.DestinationDir]
}
// mount projections
if entry, ok := mounts[resVol.DestinationDir]; ok {
entry.Volume.Projected.Sources = append(entry.Volume.Projected.Sources, corev1.VolumeProjection{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{Name: configMap.Name},
},
})
mounts[resVol.DestinationDir] = entry

cmMounts := make([]corev1.VolumeMount, len(configMap.Data))
i := 0
for fileName := range configMap.Data {
cmMounts[i] = corev1.VolumeMount{
Name: volName,
MountPath: path.Join(task.ContextDir, resVol.DestinationDir, fileName),
SubPath: fileName,
ReadOnly: true,
}
i++
}
entry.VolumeMount = append(entry.VolumeMount, cmMounts...)
entry.Volume.Projected.Sources = append(entry.Volume.Projected.Sources, corev1.VolumeProjection{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{Name: configMap.Name},
},
})
mounts[resVol.DestinationDir] = entry
default:
return errors.Errorf("unsupported resource mount type for build %s on ns %s", build.Name, build.Namespace)
}
}

for _, cmMount := range mounts {
*volumeMounts = append(*volumeMounts, cmMount.VolumeMount)
*volumeMounts = append(*volumeMounts, cmMount.VolumeMount...)
*volumes = append(*volumes, cmMount.Volume)
}

Expand Down
104 changes: 104 additions & 0 deletions container-builder/builder/kubernetes/mount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,108 @@ func Test_addResourcesToBuilderContextVolume_specificPath(t *testing.T) {
}

// TODO: add test case to verify current behavior (one created CM with a resource file)
func Test_addResourcesToBuilderContextVolume_rootPath(t *testing.T) {
cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm-data",
Namespace: t.Name(),
},
Data: map[string]string{
"workflow.sw.json": "{}",
"Dockerfike": "FROM:RHEL",
},
}
task := api.PublishTask{
ContextDir: "/build/context",
}
build := &api.ContainerBuild{
ObjectReference: api.ObjectReference{
Name: "build",
Namespace: t.Name(),
},
Status: api.ContainerBuildStatus{
ResourceVolumes: []api.ContainerBuildResourceVolume{
{
ReferenceName: "cm-data",
ReferenceType: api.ResourceReferenceTypeConfigMap,
DestinationDir: "",
},
},
},
}
volumes := make([]corev1.Volume, 0)
volumeMounts := make([]corev1.VolumeMount, 0)
client := test.NewFakeClient(cm)

err := addResourcesToBuilderContextVolume(context.TODO(), client, task, build, &volumes, &volumeMounts)
assert.NoError(t, err)

assert.Len(t, volumes, 1)
// one for each file within the CM
assert.Len(t, volumeMounts, 2)
assert.Contains(t, volumeMounts[0].MountPath, task.ContextDir)
assert.Contains(t, volumeMounts[1].MountPath, task.ContextDir)
assert.Len(t, volumes[0].Projected.Sources, 1)
}

// TODO: add test case to verify current behavior + additional CM resources
func Test_addResourcesToBuilderContextVolume_multipleCMs(t *testing.T) {
cm1 := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm-data1",
Namespace: t.Name(),
},
Data: map[string]string{
"workflow.sw.json": "{}",
"Dockerfike": "FROM:RHEL",
},
}
cm2 := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm-data2",
Namespace: t.Name(),
},
Data: map[string]string{
"openapi.json": "{}",
},
}
task := api.PublishTask{
ContextDir: "/build/context",
}
build := &api.ContainerBuild{
ObjectReference: api.ObjectReference{
Name: "build",
Namespace: t.Name(),
},
Status: api.ContainerBuildStatus{
ResourceVolumes: []api.ContainerBuildResourceVolume{
{
ReferenceName: "cm-data1",
ReferenceType: api.ResourceReferenceTypeConfigMap,
DestinationDir: "",
},
{
ReferenceName: "cm-data2",
ReferenceType: api.ResourceReferenceTypeConfigMap,
DestinationDir: "specs",
},
},
},
}
volumes := make([]corev1.Volume, 0)
volumeMounts := make([]corev1.VolumeMount, 0)
client := test.NewFakeClient(cm1, cm2)

err := addResourcesToBuilderContextVolume(context.TODO(), client, task, build, &volumes, &volumeMounts)
assert.NoError(t, err)

assert.Len(t, volumes, 2)
// one for each file within the CM
assert.Len(t, volumeMounts, 3)
assert.Contains(t, volumeMounts[0].MountPath, task.ContextDir)
assert.Contains(t, volumeMounts[1].MountPath, task.ContextDir)
assert.Contains(t, volumeMounts[2].MountPath, task.ContextDir)
// Two projections in different dirs
assert.Len(t, volumes[0].Projected.Sources, 1)
assert.Len(t, volumes[1].Projected.Sources, 1)
}

0 comments on commit 73641b4

Please sign in to comment.