From 7538c47e6eb8a7ffbd77351a00d2fe12e43ed61f Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Tue, 17 Sep 2019 12:38:30 -0400 Subject: [PATCH 1/5] Add plugins flag to install Signed-off-by: Nolan Brubaker --- pkg/cmd/cli/install/install.go | 3 +++ pkg/install/resources.go | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index f625843562..dcdda62353 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -63,6 +63,7 @@ type InstallOptions struct { Wait bool UseVolumeSnapshots bool DefaultResticMaintenanceFrequency time.Duration + Plugins flag.StringArray } // BindFlags adds command line values to the options struct. @@ -90,6 +91,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { flags.BoolVar(&o.UseRestic, "use-restic", o.UseRestic, "create restic deployment. Optional.") flags.BoolVar(&o.Wait, "wait", o.Wait, "wait for Velero deployment to be ready. Optional.") flags.DurationVar(&o.DefaultResticMaintenanceFrequency, "default-restic-prune-frequency", o.DefaultResticMaintenanceFrequency, "how often 'restic prune' is run for restic repositories by default. Optional.") + flags.Var(&o.Plugins, "plugins", "Plugin container images to install into the Velero Deployment. Optional.") } // NewInstallOptions instantiates a new, default InstallOptions struct. @@ -151,6 +153,7 @@ func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) { BSLConfig: o.BackupStorageConfig.Data(), VSLConfig: o.VolumeSnapshotConfig.Data(), DefaultResticMaintenanceFrequency: o.DefaultResticMaintenanceFrequency, + Plugins: o.Plugins, }, nil } diff --git a/pkg/install/resources.go b/pkg/install/resources.go index 81b036ae75..b948b45258 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -211,6 +211,7 @@ type VeleroOptions struct { BSLConfig map[string]string VSLConfig map[string]string DefaultResticMaintenanceFrequency time.Duration + Plugins []string } // AllResources returns a list of all resources necessary to install Velero, in the appropriate order, into a Kubernetes cluster. @@ -262,13 +263,16 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { deployOpts = append(deployOpts, WithRestoreOnly()) } + if len(o.Plugins) > 0 { + deployOpts = append(deployOpts, WithPlugins(o.Plugins)) + } + deploy := Deployment(o.Namespace, deployOpts...) appendUnstructured(resources, deploy) if o.UseRestic { ds := DaemonSet(o.Namespace, - WithAnnotations(o.PodAnnotations), WithImage(o.Image), WithResources(o.ResticPodResources), From 3094d2f0aa9ebc9c27c791b846b0a03b3f4c25ae Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Wed, 2 Oct 2019 16:33:49 -0400 Subject: [PATCH 2/5] Add plugin images to installed Deployment Signed-off-by: Nolan Brubaker --- pkg/install/deployment.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pkg/install/deployment.go b/pkg/install/deployment.go index 4f8686ecf8..62a2ca1d82 100644 --- a/pkg/install/deployment.go +++ b/pkg/install/deployment.go @@ -36,6 +36,7 @@ type podTemplateConfig struct { resources corev1.ResourceRequirements withSecret bool defaultResticMaintenanceFrequency time.Duration + plugins []string } func WithImage(image string) podTemplateOption { @@ -90,6 +91,12 @@ func WithDefaultResticMaintenanceFrequency(val time.Duration) podTemplateOption } } +func WithPlugins(plugins []string) podTemplateOption { + return func(c *podTemplateConfig) { + c.plugins = plugins + } +} + func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment { // TODO: Add support for server args c := &podTemplateConfig{ @@ -235,5 +242,25 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--default-restic-prune-frequency=%v", c.defaultResticMaintenanceFrequency)) } + if len(c.plugins) > 0 { + for _, plugin := range c.plugins { + // TODO: unify this logic with cmd/cli/plugin/add.go + container := corev1.Container{ + // TODO: name needs to be specified + Name: plugin, + Image: plugin, + ImagePullPolicy: pullPolicy, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "plugins", + MountPath: "/target", + }, + }, + } + deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, container) + } + + } + return deployment } From b64d5890fbcfce548bcf195083c225c56841016e Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Wed, 2 Oct 2019 17:09:38 -0400 Subject: [PATCH 3/5] Add changelog Signed-off-by: Nolan Brubaker --- changelogs/unreleased/1930-nrb | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/1930-nrb diff --git a/changelogs/unreleased/1930-nrb b/changelogs/unreleased/1930-nrb new file mode 100644 index 0000000000..616d3c33ac --- /dev/null +++ b/changelogs/unreleased/1930-nrb @@ -0,0 +1 @@ +Add a new required --plugins flag for velero install command. --plugins takes a list of container images to add as initcontainers. From dbffccd1db94075735926c6265cfeba4c76d10a4 Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Thu, 3 Oct 2019 16:59:48 -0400 Subject: [PATCH 4/5] Use a dedicated builder for plugin init containers Signed-off-by: Nolan Brubaker --- pkg/builder/container_builder.go | 33 ++++++++++++++++++++++++++++++++ pkg/cmd/cli/plugin/add.go | 33 ++------------------------------ pkg/install/deployment.go | 18 ++++------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/pkg/builder/container_builder.go b/pkg/builder/container_builder.go index 8483477634..d58b3e03fa 100644 --- a/pkg/builder/container_builder.go +++ b/pkg/builder/container_builder.go @@ -17,6 +17,8 @@ limitations under the License. package builder import ( + "strings" + corev1api "k8s.io/api/core/v1" ) @@ -35,6 +37,32 @@ func ForContainer(name, image string) *ContainerBuilder { } } +// ForPluginContainer is a helper builder specifically for plugin init containers +func ForPluginContainer(image string, pullPolicy corev1api.PullPolicy) *ContainerBuilder { + volumeMount := ForVolumeMount("plugins", "/target").Result() + return ForContainer(getName(image), image).PullPolicy(pullPolicy).VolumeMounts(volumeMount) +} + +// getName returns the 'name' component of a docker +// image (i.e. everything after the last '/' and before +// any subsequent ':') +func getName(image string) string { + slashIndex := strings.LastIndex(image, "/") + colonIndex := strings.LastIndex(image, ":") + + start := 0 + if slashIndex > 0 { + start = slashIndex + 1 + } + + end := len(image) + if colonIndex > slashIndex { + end = colonIndex + } + + return image[start:end] +} + // Result returns the built Container. func (b *ContainerBuilder) Result() *corev1api.Container { return b.object @@ -66,3 +94,8 @@ func (b *ContainerBuilder) Env(vars ...*corev1api.EnvVar) *ContainerBuilder { } return b } + +func (b *ContainerBuilder) PullPolicy(pullPolicy corev1api.PullPolicy) *ContainerBuilder { + b.object.ImagePullPolicy = pullPolicy + return b +} diff --git a/pkg/cmd/cli/plugin/add.go b/pkg/cmd/cli/plugin/add.go index a8eea20ae2..50e7f1f0ba 100644 --- a/pkg/cmd/cli/plugin/add.go +++ b/pkg/cmd/cli/plugin/add.go @@ -28,6 +28,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/client" "github.com/vmware-tanzu/velero/pkg/cmd" "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" @@ -104,17 +105,7 @@ func NewAddCommand(f client.Factory) *cobra.Command { } // add the plugin as an init container - plugin := v1.Container{ - Name: getName(args[0]), - Image: args[0], - ImagePullPolicy: v1.PullPolicy(imagePullPolicyFlag.String()), - VolumeMounts: []v1.VolumeMount{ - { - Name: pluginsVolumeName, - MountPath: "/target", - }, - }, - } + plugin := *builder.ForPluginContainer(args[0], v1.PullPolicy(imagePullPolicyFlag.String())).Result() veleroDeploy.Spec.Template.Spec.InitContainers = append(veleroDeploy.Spec.Template.Spec.InitContainers, plugin) @@ -134,23 +125,3 @@ func NewAddCommand(f client.Factory) *cobra.Command { return c } - -// getName returns the 'name' component of a docker -// image (i.e. everything after the last '/' and before -// any subsequent ':') -func getName(image string) string { - slashIndex := strings.LastIndex(image, "/") - colonIndex := strings.LastIndex(image, ":") - - start := 0 - if slashIndex > 0 { - start = slashIndex + 1 - } - - end := len(image) - if colonIndex > slashIndex { - end = colonIndex - } - - return image[start:end] -} diff --git a/pkg/install/deployment.go b/pkg/install/deployment.go index 62a2ca1d82..9d89227152 100644 --- a/pkg/install/deployment.go +++ b/pkg/install/deployment.go @@ -24,6 +24,8 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/vmware-tanzu/velero/pkg/builder" ) type podTemplateOption func(*podTemplateConfig) @@ -243,20 +245,8 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment } if len(c.plugins) > 0 { - for _, plugin := range c.plugins { - // TODO: unify this logic with cmd/cli/plugin/add.go - container := corev1.Container{ - // TODO: name needs to be specified - Name: plugin, - Image: plugin, - ImagePullPolicy: pullPolicy, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "plugins", - MountPath: "/target", - }, - }, - } + for _, image := range c.plugins { + container := *builder.ForPluginContainer(image, pullPolicy).Result() deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, container) } From fc9f670e5bcf24c897c7004e4395bd4186b39e67 Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Thu, 3 Oct 2019 17:17:25 -0400 Subject: [PATCH 5/5] Move getName tests Signed-off-by: Nolan Brubaker --- .../plugin/add_test.go => builder/container_builder_test.go} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename pkg/{cmd/cli/plugin/add_test.go => builder/container_builder_test.go} (96%) diff --git a/pkg/cmd/cli/plugin/add_test.go b/pkg/builder/container_builder_test.go similarity index 96% rename from pkg/cmd/cli/plugin/add_test.go rename to pkg/builder/container_builder_test.go index f87bad9e4b..4a3d7a584e 100644 --- a/pkg/cmd/cli/plugin/add_test.go +++ b/pkg/builder/container_builder_test.go @@ -1,5 +1,5 @@ /* -Copyright 2018 the Velero contributors. +Copyright 2018, 2019 the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ 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 plugin +package builder import ( "testing"