Skip to content

Commit

Permalink
feat(operator): enable storage configuration
Browse files Browse the repository at this point in the history
We look for default storage class in the cluster if no configuration is provided
  • Loading branch information
squakez committed Feb 17, 2023
1 parent 2a12f0c commit f82d1e2
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 58 deletions.
8 changes: 1 addition & 7 deletions config/manager/operator-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ spec:
app.kubernetes.io/version: "1.12.0-SNAPSHOT"
spec:
serviceAccountName: camel-k-operator
volumes:
- name: camel-k-maven-repo
persistentVolumeClaim:
claimName: camel-k-maven-repo
containers:
- name: camel-k-operator
image: docker.io/apache/camel-k:1.12.0-SNAPSHOT
Expand Down Expand Up @@ -82,6 +78,4 @@ spec:
port: 8081
initialDelaySeconds: 20
periodSeconds: 10
volumeMounts:
- mountPath: "/tmp/artifacts/m2"
name: camel-k-maven-repo

27 changes: 0 additions & 27 deletions config/manager/operator-storage.yaml

This file was deleted.

13 changes: 13 additions & 0 deletions pkg/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
// save
cmd.Flags().Bool("save", false, "Save the install parameters into the default kamel configuration file (kamel-config.yaml)")

// Storage settings
cmd.Flags().String("storage-class-name", "", "Use a storage class name to create a dynamic volume (if empty will look up for cluster default)")
cmd.Flags().String("storage-capacity", "20Gi", "How much capacity to use")
cmd.Flags().String("storage-volume-name", "", "Use an existing PersistentVolume")

return &cmd, &options
}

Expand Down Expand Up @@ -198,6 +203,9 @@ type installCmdOptions struct {
ResourcesRequirements []string `mapstructure:"operator-resources"`
LogLevel string `mapstructure:"log-level"`
EnvVars []string `mapstructure:"operator-env-vars"`
StorageClassName string `mapstructure:"storage-class-name"`
StorageCapacity string `mapstructure:"storage-capacity"`
StorageVolumeName string `mapstructure:"storage-volume-name"`

registry v1.RegistrySpec
registryAuth registry.Auth
Expand Down Expand Up @@ -428,6 +436,11 @@ func (o *installCmdOptions) setupOperator(
NodeSelectors: o.NodeSelectors,
ResourcesRequirements: o.ResourcesRequirements,
EnvVars: o.EnvVars,
Storage: install.OperatorStorageConfiguration{
ClassName: o.StorageClassName,
Capacity: o.StorageCapacity,
VolumeName: o.StorageVolumeName,
},
}

return install.OperatorOrCollect(o.Context, cmd, c, cfg, output, o.Force)
Expand Down
10 changes: 5 additions & 5 deletions pkg/controller/build/build_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,14 @@ func addBuildTaskToPod(build *v1.Build, taskName string, pod *corev1.Pod) {
},
)
}
if !hasVolume(pod, "camel-k-maven-repo") {
if !hasVolume(pod, defaults.DefaultPVC) {
pod.Spec.Volumes = append(pod.Spec.Volumes,
// Maven repo volume
corev1.Volume{
Name: "camel-k-maven-repo",
Name: defaults.DefaultPVC,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "camel-k-maven-repo",
ClaimName: defaults.DefaultPVC,
},
},
},
Expand Down Expand Up @@ -482,9 +482,9 @@ func addContainerToPod(build *v1.Build, container corev1.Container, pod *corev1.
MountPath: filepath.Join(builderDir, build.Name),
})
}
if hasVolume(pod, "camel-k-maven-repo") {
if hasVolume(pod, defaults.DefaultPVC) {
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
Name: "camel-k-maven-repo",
Name: defaults.DefaultPVC,
MountPath: "/tmp/artifacts/m2",
})
}
Expand Down
8 changes: 0 additions & 8 deletions pkg/install/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (

networking "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
k8s "k8s.io/client-go/kubernetes"

ctrl "sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -106,13 +105,6 @@ func ObjectOrCollect(ctx context.Context, c client.Client, namespace string, col

obj.SetNamespace(namespace)

if obj.GetObjectKind().GroupVersionKind().Kind == "PersistentVolumeClaim" {
if err := c.Create(ctx, obj); err != nil && !errors.IsAlreadyExists(err) {
return err
}
return nil
}

if force {
if _, err := kubernetes.ReplaceResource(ctx, c, obj); err != nil {
return err
Expand Down
102 changes: 101 additions & 1 deletion pkg/install/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/client"
"github.com/apache/camel-k/pkg/resources"
"github.com/apache/camel-k/pkg/util/defaults"
"github.com/apache/camel-k/pkg/util/envvar"
"github.com/apache/camel-k/pkg/util/knative"
"github.com/apache/camel-k/pkg/util/kubernetes"
Expand All @@ -60,6 +61,7 @@ type OperatorConfiguration struct {
NodeSelectors []string
ResourcesRequirements []string
EnvVars []string
Storage OperatorStorageConfiguration
}

type OperatorHealthConfiguration struct {
Expand All @@ -71,6 +73,13 @@ type OperatorMonitoringConfiguration struct {
Port int32
}

// OperatorStorageConfiguration represents the configuration required for Camel K operator storage
type OperatorStorageConfiguration struct {
ClassName string
Capacity string
VolumeName string
}

// OperatorOrCollect installs the operator resources or adds them to the collector if present.
// nolint: maintidx // TODO: refactor the code
func OperatorOrCollect(ctx context.Context, cmd *cobra.Command, c client.Client, cfg OperatorConfiguration, collection *kubernetes.Collection, force bool) error {
Expand All @@ -79,7 +88,40 @@ func OperatorOrCollect(ctx context.Context, cmd *cobra.Command, c client.Client,
return err
}

camelKPVC, err := installPVC(ctx, cmd, c, cfg, collection, force)
if err != nil {
return err
}

customizer := func(o ctrl.Object) ctrl.Object {
if camelKPVC != nil {
if d, ok := o.(*appsv1.Deployment); ok {
if d.Labels["camel.apache.org/component"] == "operator" {
volume := corev1.Volume{
Name: defaults.DefaultPVC,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: camelKPVC.Name,
},
},
}
if d.Spec.Template.Spec.Volumes == nil {
d.Spec.Template.Spec.Volumes = make([]corev1.Volume, 0, 1)
}
d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, volume)

vm := corev1.VolumeMount{
MountPath: defaults.LocalRepository,
Name: volume.Name,
}
if d.Spec.Template.Spec.Containers[0].VolumeMounts == nil {
d.Spec.Template.Spec.Containers[0].VolumeMounts = make([]corev1.VolumeMount, 0, 1)
}
d.Spec.Template.Spec.Containers[0].VolumeMounts = append(d.Spec.Template.Spec.Containers[0].VolumeMounts, vm)
}
}
}

if cfg.CustomImage != "" {
if d, ok := o.(*appsv1.Deployment); ok {
if d.Labels["camel.apache.org/component"] == "operator" {
Expand Down Expand Up @@ -318,6 +360,65 @@ func OperatorOrCollect(ctx context.Context, cmd *cobra.Command, c client.Client,
return nil
}

func installPVC(ctx context.Context, cmd *cobra.Command, c client.Client, cfg OperatorConfiguration, collection *kubernetes.Collection, force bool) (*corev1.PersistentVolumeClaim, error) {
// Verify if a PVC already exists
camelKPVC, err := kubernetes.LookupPersistentVolumeClaim(ctx, c, cfg.Namespace, defaults.DefaultPVC)
if err != nil {
return nil, err
}
if camelKPVC != nil {
fmt.Fprintf(cmd.ErrOrStderr(), "A persistent volume claim for \"%s\" already exist, reusing it\n", defaults.DefaultPVC)
return camelKPVC, nil
}

// Use a static persistent volume
if cfg.Storage.VolumeName != "" {
fmt.Fprintf(cmd.ErrOrStderr(), "Using a static persistent volume \"%s\" for the operator\n", cfg.Storage.VolumeName)
camelKPVC = kubernetes.NewPersistentVolumeClaim(
cfg.Namespace,
defaults.DefaultPVC,
"",
cfg.Storage.VolumeName,
cfg.Storage.Capacity,
corev1.ReadWriteMany,
)
err = ObjectOrCollect(ctx, c, cfg.Namespace, collection, false, camelKPVC)
return camelKPVC, err
}

// Use a dynamic volume based on storage classes
storageClassName, err := getStorageClassName(ctx, c, cfg.Storage.ClassName)
if err != nil {
return nil, err
}
if storageClassName != "" {
fmt.Fprintf(cmd.ErrOrStderr(), "Using storage class \"%s\" to create a dynamic volume or the operator\n", storageClassName)
camelKPVC = kubernetes.NewPersistentVolumeClaim(
cfg.Namespace,
defaults.DefaultPVC,
storageClassName,
"",
cfg.Storage.Capacity,
corev1.ReadWriteMany,
)
err = ObjectOrCollect(ctx, c, cfg.Namespace, collection, false, camelKPVC)
return camelKPVC, err
}
fmt.Fprintf(cmd.ErrOrStderr(), "Could not find a default storage class in the cluster. The operator will be installed with an ephemeral storage. Bear in mind certain build strategies such as \"pod\" may not work as expected.\n")
return nil, nil
}

func getStorageClassName(ctx context.Context, c client.Client, cfgStorageClassName string) (string, error) {
if cfgStorageClassName != "" {
return cfgStorageClassName, nil
}
defaultStorageClass, err := kubernetes.LookupDefaultStorageClass(ctx, c)
if err != nil {
return "", err
}
return defaultStorageClass.Name, nil
}

func installNamespacedRoleBinding(ctx context.Context, c client.Client, collection *kubernetes.Collection, namespace string, path string) error {
yaml, err := resources.ResourceAsString(path)
if err != nil {
Expand Down Expand Up @@ -456,7 +557,6 @@ func installKubernetesRoles(ctx context.Context, c client.Client, namespace stri

func installOperator(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection, force bool) error {
return ResourcesOrCollect(ctx, c, namespace, collection, force, customizer,
"/manager/operator-storage.yaml",
"/manager/operator-deployment.yaml",
)
}
Expand Down
Loading

0 comments on commit f82d1e2

Please sign in to comment.