Skip to content

Commit

Permalink
Support persistent home directory
Browse files Browse the repository at this point in the history
Fix devfile#1097

Signed-off-by: Andrew Obuchowicz <aobuchow@redhat.com>
  • Loading branch information
AObuchow committed May 30, 2023
1 parent bad287c commit 99b2aac
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 7 deletions.
5 changes: 4 additions & 1 deletion controllers/workspace/devworkspace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,15 @@ func (r *DevWorkspaceReconciler) Reconcile(ctx context.Context, req ctrl.Request
return r.failWorkspace(workspace, eventErrors.Error(), metrics.ReasonBadRequest, reqLogger, &reconcileStatus), nil
}
}

storageProvisioner, err := storage.GetProvisioner(workspace)
if err != nil {
return r.failWorkspace(workspace, fmt.Sprintf("Error provisioning storage: %s", err), metrics.ReasonBadRequest, reqLogger, &reconcileStatus), nil
}

if wsprovision.NeedsPersistentHomeDirectory(workspace) {
wsprovision.AddHomeVolumeAndVolumeMount(&workspace.Spec.Template)
}

// Set finalizer on DevWorkspace if necessary
// Note: we need to check the flattened workspace to see if a finalizer is needed, as plugins could require storage
if storageProvisioner.NeedsStorage(&workspace.Spec.Template) && !controllerutil.ContainsFinalizer(clusterWorkspace, constants.StorageCleanupFinalizer) {
Expand Down
16 changes: 13 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 Down
16 changes: 13 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 Down
66 changes: 66 additions & 0 deletions pkg/provision/workspace/persistentHome.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Copyright (c) 2019-2023 Red Hat, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package workspace

import (
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"

"github.com/devfile/devworkspace-operator/pkg/common"
)

// Adds a Devfile volume to the DevWorkspaceTemplateSpec and mounts the volume to `/home/user/` for every
// container component defined in the DevWorkspaceTemplateSpec by adding additional volumeMounts.
// The DevWorkspaceTemplateSpec remains unchanged if any of its container components already mount a volume to `/home/user/`.
func AddHomeVolumeAndVolumeMount(devWorkspaceTemplateSpec *v1alpha2.DevWorkspaceTemplateSpec) {
homeUserDirPath := "/home/user/"
homeVolumeName := "persistentHome"

homeVolume := v1alpha2.Component{
Name: homeVolumeName,
ComponentUnion: v1alpha2.ComponentUnion{
Volume: &v1alpha2.VolumeComponent{},
},
}
homeVolumeMount := v1alpha2.VolumeMount{
Name: homeVolumeName,
Path: homeUserDirPath,
}

for _, component := range devWorkspaceTemplateSpec.Components {
if component.Container == nil {
continue
}
for _, volumeMount := range component.Container.VolumeMounts {
if volumeMount.Path == homeUserDirPath {
// If a volume is already being mounted to /home/user/, it takes precedence
// over the DWO-provisioned home directory volume.
return
}
}
}

devWorkspaceTemplateSpec.Components = append(devWorkspaceTemplateSpec.Components, homeVolume)
for _, component := range devWorkspaceTemplateSpec.Components {
if component.Container == nil {
continue
}
component.Container.VolumeMounts = append(component.Container.VolumeMounts, homeVolumeMount)
}
}

func NeedsPersistentHomeDirectory(workspace *common.DevWorkspaceWithConfig) bool {
return *workspace.Config.Workspace.PersistUserHome.Enabled
}

0 comments on commit 99b2aac

Please sign in to comment.