-
Notifications
You must be signed in to change notification settings - Fork 244
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
36 changed files
with
1,788 additions
and
194 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
docs/website/docs/user-guides/advanced/automounting-volumes.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
title: Automounting Volumes | ||
sidebar_position: 8 | ||
--- | ||
|
||
Existing [ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/), [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/), and [Persistent Volume Claims](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) on the cluster can be mounted automatically to all containers created by `odo`. These resources can be configured by applying the appropriate labels. | ||
|
||
To mark a resource for mounting to containers created by `odo`, apply the following label to the resource: | ||
|
||
```yaml | ||
metadata: | ||
labels: | ||
controller.devfile.io/mount-to-containers: "true" | ||
``` | ||
By default, resources will be mounted based on the resource name: | ||
- Secrets will be mounted to `/etc/secret/<secret-name>` | ||
|
||
- Configmaps will be mounted to `/etc/config/<configmap-name>` | ||
|
||
- Persistent volume claims will be mounted to `/tmp/<pvc-name>` | ||
|
||
Mounting resources can be additionally configured via annotations: | ||
|
||
- `controller.devfile.io/mount-path`: configure where the resource should be mounted | ||
|
||
- `controller.devfile.io/mount-as`: for secrets and configmaps only, configure how the resource should be mounted to the container | ||
|
||
- If `controller.devfile.io/mount-as: file`, the configmap/secret will be mounted as files within the mount path. This is the default behavior. | ||
|
||
- If `controller.devfile.io/mount-as: subpath`, the keys and values in the configmap/secret will be mounted as files within the mount path using subpath volume mounts. | ||
|
||
- If `controller.devfile.io/mount-as: env`, the keys and values in the configmap/secret will be mounted as environment variables in all containers. | ||
|
||
When `file` is used, the configmap is mounted as a directory within the containers, erasing any files/directories already present. When `subpath` is used, each key in the configmap/secret is mounted as a subpath volume mount in the mount path, leaving existing files intact but preventing changes to the secret/configmap from propagating into the containers without a restart. | ||
|
||
- `controller.devfile.io/read-only`: for persistent volume claims, mount the resource as read-only | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// configAutomount package provides functions to work with automounted configuration resources (Configmap, Secret, PVC) | ||
// Specified at https://github.com/devfile/devworkspace-operator/blob/main/docs/additional-configuration.adoc#automatically-mounting-volumes-configmaps-and-secrets | ||
package configAutomount |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package configAutomount | ||
|
||
type MountAs int | ||
type VolumeType int | ||
|
||
const ( | ||
MountAsFile MountAs = iota + 1 | ||
MountAsSubpath | ||
MountAsEnv | ||
) | ||
|
||
const ( | ||
VolumeTypePVC VolumeType = iota + 1 | ||
VolumeTypeConfigmap | ||
VolumeTypeSecret | ||
) | ||
|
||
type AutomountInfo struct { | ||
// VolumeType gives the type of the volume (PVC, Secret, ConfigMap) | ||
VolumeType VolumeType | ||
// VolumeName is the name of the resource to mount | ||
VolumeName string | ||
// MountPath indicates on which path to mount the volume (empty if MountAs is Env) | ||
MountPath string | ||
// MountAs indicates how to mount the volume | ||
// - File: by default | ||
// - Env: As environment variables (for Secret and Configmap) | ||
// - Subpath: As individual files in specific paths (For Secret and ConfigMap). Keys must be provided | ||
MountAs MountAs | ||
// ReadOnly indicates to mount the volume as Read-Only | ||
ReadOnly bool | ||
// Keys defines the list of keys to mount when MountAs is Subpath | ||
Keys []string | ||
} | ||
|
||
type Client interface { | ||
GetAutomountingVolumes() ([]AutomountInfo, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package configAutomount | ||
|
||
import ( | ||
"path/filepath" | ||
"sort" | ||
|
||
"github.com/redhat-developer/odo/pkg/kclient" | ||
) | ||
|
||
const ( | ||
labelMountName = "controller.devfile.io/mount-to-containers" | ||
labelMountValue = "true" | ||
|
||
annotationMountPathName = "controller.devfile.io/mount-path" | ||
annotationMountAsName = "controller.devfile.io/mount-as" | ||
annotationReadOnlyName = "controller.devfile.io/read-only" | ||
) | ||
|
||
type KubernetesClient struct { | ||
kubeClient kclient.ClientInterface | ||
} | ||
|
||
func NewKubernetesClient(kubeClient kclient.ClientInterface) KubernetesClient { | ||
return KubernetesClient{ | ||
kubeClient: kubeClient, | ||
} | ||
} | ||
|
||
func (o KubernetesClient) GetAutomountingVolumes() ([]AutomountInfo, error) { | ||
var result []AutomountInfo | ||
|
||
pvcs, err := o.getAutomountingPVCs() | ||
if err != nil { | ||
return nil, err | ||
} | ||
result = append(result, pvcs...) | ||
|
||
secrets, err := o.getAutomountingSecrets() | ||
if err != nil { | ||
return nil, err | ||
} | ||
result = append(result, secrets...) | ||
|
||
cms, err := o.getAutomountingConfigmaps() | ||
if err != nil { | ||
return nil, err | ||
} | ||
result = append(result, cms...) | ||
|
||
return result, nil | ||
} | ||
|
||
func (o KubernetesClient) getAutomountingPVCs() ([]AutomountInfo, error) { | ||
pvcs, err := o.kubeClient.ListPVCs(labelMountName + "=" + labelMountValue) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var result []AutomountInfo | ||
for _, pvc := range pvcs { | ||
mountPath := filepath.ToSlash(filepath.Join("/", "tmp", pvc.Name)) | ||
if val, found := getMountPathFromAnnotation(pvc.Annotations); found { | ||
mountPath = val | ||
} | ||
result = append(result, AutomountInfo{ | ||
VolumeType: VolumeTypePVC, | ||
VolumeName: pvc.Name, | ||
MountPath: mountPath, | ||
MountAs: MountAsFile, | ||
ReadOnly: pvc.Annotations[annotationReadOnlyName] == "true", | ||
}) | ||
} | ||
return result, nil | ||
} | ||
|
||
func (o KubernetesClient) getAutomountingSecrets() ([]AutomountInfo, error) { | ||
secrets, err := o.kubeClient.ListSecrets(labelMountName + "=" + labelMountValue) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var result []AutomountInfo | ||
for _, secret := range secrets { | ||
mountAs := getMountAsFromAnnotation(secret.Annotations) | ||
mountPath := filepath.ToSlash(filepath.Join("/", "etc", "secret", secret.Name)) | ||
var keys []string | ||
if val, found := getMountPathFromAnnotation(secret.Annotations); found { | ||
mountPath = val | ||
} | ||
if mountAs == MountAsEnv { | ||
mountPath = "" | ||
} | ||
if mountAs == MountAsSubpath { | ||
for k := range secret.Data { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
} | ||
result = append(result, AutomountInfo{ | ||
VolumeType: VolumeTypeSecret, | ||
VolumeName: secret.Name, | ||
MountPath: mountPath, | ||
MountAs: mountAs, | ||
ReadOnly: secret.Annotations[annotationReadOnlyName] == "true", | ||
Keys: keys, | ||
}) | ||
} | ||
return result, nil | ||
} | ||
|
||
func (o KubernetesClient) getAutomountingConfigmaps() ([]AutomountInfo, error) { | ||
cms, err := o.kubeClient.ListConfigMaps(labelMountName + "=" + labelMountValue) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var result []AutomountInfo | ||
for _, cm := range cms { | ||
mountAs := getMountAsFromAnnotation(cm.Annotations) | ||
mountPath := filepath.ToSlash(filepath.Join("/", "etc", "config", cm.Name)) | ||
var keys []string | ||
if val, found := getMountPathFromAnnotation(cm.Annotations); found { | ||
mountPath = val | ||
} | ||
if mountAs == MountAsEnv { | ||
mountPath = "" | ||
} | ||
if mountAs == MountAsSubpath { | ||
for k := range cm.Data { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
} | ||
result = append(result, AutomountInfo{ | ||
VolumeType: VolumeTypeConfigmap, | ||
VolumeName: cm.Name, | ||
MountPath: mountPath, | ||
MountAs: mountAs, | ||
ReadOnly: cm.Annotations[annotationReadOnlyName] == "true", | ||
Keys: keys, | ||
}) | ||
} | ||
return result, nil | ||
} | ||
|
||
func getMountPathFromAnnotation(annotations map[string]string) (string, bool) { | ||
val, found := annotations[annotationMountPathName] | ||
return val, found | ||
} | ||
|
||
func getMountAsFromAnnotation(annotations map[string]string) MountAs { | ||
switch annotations[annotationMountAsName] { | ||
case "subpath": | ||
return MountAsSubpath | ||
case "env": | ||
return MountAsEnv | ||
default: | ||
return MountAsFile | ||
} | ||
} |
Oops, something went wrong.