Skip to content

Commit

Permalink
Support persistent home directory for common and per-workspace storag…
Browse files Browse the repository at this point in the history
…e strategies

Fix devfile#1097

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
  • Loading branch information
AObuchow committed May 15, 2023
1 parent 24d8e21 commit 1d2e8bc
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
22 changes: 19 additions & 3 deletions pkg/provision/storage/commonStorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,17 @@ func (p *CommonStorageProvisioner) ProvisionStorage(podAdditions *v1alpha1.PodAd
pvcName = commonPVC.Name
}

if err := p.rewriteContainerVolumeMounts(workspace.Status.DevWorkspaceId, pvcName, podAdditions, &workspace.Spec.Template); err != nil {
if shouldPersistHomeDirectory(workspace) {
err := addHomeVolumeMount(workspace, pvcName, podAdditions)
if err != nil {
return &dwerrors.FailError{
Err: err,
Message: "Could not add persistent home directory",
}
}
}

if err := p.rewriteContainerVolumeMounts(workspace.Status.DevWorkspaceId, pvcName, podAdditions, workspace); err != nil {
return &dwerrors.FailError{
Err: err,
Message: "Could not rewrite container volume mounts",
Expand Down Expand Up @@ -125,11 +135,11 @@ func (p *CommonStorageProvisioner) CleanupWorkspaceStorage(workspace *common.Dev
// (i.e. all volume mounts are subpaths into a common PVC used by all workspaces in the namespace).
//
// Also adds appropriate k8s Volumes to PodAdditions to accomodate the rewritten VolumeMounts.
func (p *CommonStorageProvisioner) rewriteContainerVolumeMounts(workspaceId, pvcName string, podAdditions *v1alpha1.PodAdditions, workspace *dw.DevWorkspaceTemplateSpec) error {
func (p *CommonStorageProvisioner) rewriteContainerVolumeMounts(workspaceId, pvcName string, podAdditions *v1alpha1.PodAdditions, workspace *common.DevWorkspaceWithConfig) error {
devfileVolumes := map[string]dw.VolumeComponent{}

// Construct map of volume name -> volume Component
for _, component := range workspace.Components {
for _, component := range workspace.Spec.Template.Components {
if component.Volume != nil {
if _, exists := devfileVolumes[component.Name]; exists {
return fmt.Errorf("volume component '%s' is defined multiple times", component.Name)
Expand All @@ -144,6 +154,12 @@ func (p *CommonStorageProvisioner) rewriteContainerVolumeMounts(workspaceId, pvc
additionalVolumes[additionalVolume.Name] = true
}

// When we persist the home directory, a volumeMount is created that references the PVC volume.
// This volumeMount should not be rewritten
if shouldPersistHomeDirectory(workspace) {
additionalVolumes[pvcName] = true
}

// Add implicit projects volume to support mountSources, if needed
if _, exists := devfileVolumes[devfileConstants.ProjectsVolumeName]; !exists {
projectsVolume := dw.VolumeComponent{}
Expand Down
22 changes: 19 additions & 3 deletions pkg/provision/storage/perWorkspaceStorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,18 @@ func (p *PerWorkspaceStorageProvisioner) ProvisionStorage(podAdditions *v1alpha1
}
}

if shouldPersistHomeDirectory(workspace) {
err := addHomeVolumeMount(workspace, pvcName, podAdditions)
if err != nil {
return &dwerrors.FailError{
Err: err,
Message: "Could not add persistent home directory",
}
}
}

// Rewrite container volume mounts
if err := p.rewriteContainerVolumeMounts(workspace.Status.DevWorkspaceId, pvcName, podAdditions, &workspace.Spec.Template); err != nil {
if err := p.rewriteContainerVolumeMounts(workspace.Status.DevWorkspaceId, pvcName, podAdditions, workspace); err != nil {
return &dwerrors.FailError{
Err: err,
Message: "Could not rewrite container volume mounts",
Expand All @@ -90,11 +100,11 @@ func (*PerWorkspaceStorageProvisioner) CleanupWorkspaceStorage(workspace *common
// (i.e. all volume mounts are subpaths into a PVC used by a single workspace in the namespace).
//
// Also adds appropriate k8s Volumes to PodAdditions to accomodate the rewritten VolumeMounts.
func (p *PerWorkspaceStorageProvisioner) rewriteContainerVolumeMounts(workspaceId, pvcName string, podAdditions *v1alpha1.PodAdditions, workspace *dw.DevWorkspaceTemplateSpec) error {
func (p *PerWorkspaceStorageProvisioner) rewriteContainerVolumeMounts(workspaceId, pvcName string, podAdditions *v1alpha1.PodAdditions, workspace *common.DevWorkspaceWithConfig) error {
devfileVolumes := map[string]dw.VolumeComponent{}

// Construct map of volume name -> volume Component
for _, component := range workspace.Components {
for _, component := range workspace.Spec.Template.Components {
if component.Volume != nil {
if _, exists := devfileVolumes[component.Name]; exists {
return fmt.Errorf("volume component '%s' is defined multiple times", component.Name)
Expand All @@ -109,6 +119,12 @@ func (p *PerWorkspaceStorageProvisioner) rewriteContainerVolumeMounts(workspaceI
additionalVolumes[additionalVolume.Name] = true
}

// When we persist the home directory, a volumeMount is created that references the PVC volume.
// This volumeMount should not be rewritten
if shouldPersistHomeDirectory(workspace) {
additionalVolumes[pvcName] = true
}

// Add implicit projects volume to support mountSources, if needed
if _, exists := devfileVolumes[devfileConstants.ProjectsVolumeName]; !exists {
projectsVolume := dw.VolumeComponent{}
Expand Down
29 changes: 29 additions & 0 deletions pkg/provision/storage/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,32 @@ func checkPVCTerminating(name, namespace string, api sync.ClusterAPI) (bool, err
}
return pvc.DeletionTimestamp != nil, nil
}

func shouldPersistHomeDirectory(workspace *common.DevWorkspaceWithConfig) bool {
return workspace.Config.Workspace.PersistUserHome != nil && workspace.Config.Workspace.PersistUserHome.Enabled != nil && *workspace.Config.Workspace.PersistUserHome.Enabled
}

// Adds a home volume mount to the given set of Pod Additions.
// The home volume mount is mounted to the given PVC at the path `/home/user/`.
// If a Devfile volume already mounts to `/home/user/`, an error is returned.
func addHomeVolumeMount(workspace *common.DevWorkspaceWithConfig, pvcName string, podAdditions *v1alpha1.PodAdditions) error {
homeUserDirPath := "/home/user/"
homeVolumeMount := corev1.VolumeMount{
Name: pvcName,
MountPath: homeUserDirPath,
SubPath: fmt.Sprintf("%s/home/user/", workspace.Status.DevWorkspaceId),
}

// Check if we are already trying to mount a volume to /home/user/ in one of the containers
for cIdx := range podAdditions.Containers {
for vmIdx := range podAdditions.Containers[cIdx].VolumeMounts {
if podAdditions.Containers[cIdx].VolumeMounts[vmIdx].MountPath == homeUserDirPath {
containerName := podAdditions.Containers[cIdx].Name
volumeMountName := podAdditions.Containers[cIdx].VolumeMounts[vmIdx].Name
return fmt.Errorf("volumeMount '%s' for container '%s' already mounts to %s", volumeMountName, containerName, homeUserDirPath)
}
}
podAdditions.Containers[cIdx].VolumeMounts = append(podAdditions.Containers[cIdx].VolumeMounts, homeVolumeMount)
}
return nil
}

0 comments on commit 1d2e8bc

Please sign in to comment.