diff --git a/changelogs/unreleased/1626-tlkamp b/changelogs/unreleased/1626-tlkamp new file mode 100644 index 000000000..e49ace987 --- /dev/null +++ b/changelogs/unreleased/1626-tlkamp @@ -0,0 +1 @@ +enhancement: allow users to specify additional Velero/Restic pod annotations on the command line with the pod-annotations flag. \ No newline at end of file diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index 8b4374ff0..97d07e63a 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -43,6 +43,7 @@ type InstallOptions struct { BucketName string Prefix string ProviderName string + PodAnnotations flag.Map RestoreOnly bool SecretFile string DryRun bool @@ -60,6 +61,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { flags.StringVar(&o.SecretFile, "secret-file", o.SecretFile, "file containing credentials for backup and volume provider") flags.StringVar(&o.Image, "image", o.Image, "image to use for the Velero and restic server pods. Optional.") flags.StringVar(&o.Prefix, "prefix", o.Prefix, "prefix under which all Velero data should be stored within the bucket. Optional.") + flags.Var(&o.PodAnnotations, "pod-annotations", "annotations to add to the Velero and Restic pods. Optional. Format is key1=value1,key2=value2") flags.StringVar(&o.Namespace, "namespace", o.Namespace, "namespace to install Velero and associated data into. Optional.") flags.Var(&o.BackupStorageConfig, "backup-location-config", "configuration to use for the backup storage location. Format is key1=value1,key2=value2") flags.Var(&o.VolumeSnapshotConfig, "snapshot-location-config", "configuration to use for the volume snapshot location. Format is key1=value1,key2=value2") @@ -70,13 +72,14 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { flags.BoolVar(&o.Wait, "wait", o.Wait, "wait for Velero deployment to be ready. Optional.") } -// NewInstallOptions instantiates a new, default InstallOptions stuct. +// NewInstallOptions instantiates a new, default InstallOptions struct. func NewInstallOptions() *InstallOptions { return &InstallOptions{ Namespace: api.DefaultNamespace, Image: install.DefaultImage, BackupStorageConfig: flag.NewMap(), VolumeSnapshotConfig: flag.NewMap(), + PodAnnotations: flag.NewMap(), // Default to creating a VSL unless we're told otherwise UseVolumeSnapshots: true, } @@ -98,6 +101,7 @@ func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) { ProviderName: o.ProviderName, Bucket: o.BucketName, Prefix: o.Prefix, + PodAnnotations: o.PodAnnotations.Data(), SecretData: secretData, RestoreOnly: o.RestoreOnly, UseRestic: o.UseRestic, diff --git a/pkg/install/daemonset.go b/pkg/install/daemonset.go index a4c0bc6b4..1ea24f414 100644 --- a/pkg/install/daemonset.go +++ b/pkg/install/daemonset.go @@ -61,6 +61,7 @@ func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet { "name": "restic", "component": "velero", }, + Annotations: c.annotations, }, Spec: corev1.PodSpec{ ServiceAccountName: "velero", diff --git a/pkg/install/deployment.go b/pkg/install/deployment.go index 436f80fb4..b7c75ad05 100644 --- a/pkg/install/deployment.go +++ b/pkg/install/deployment.go @@ -31,6 +31,7 @@ type podTemplateConfig struct { withoutCredentialsVolume bool envVars []corev1.EnvVar restoreOnly bool + annotations map[string]string } func WithImage(image string) podTemplateOption { @@ -39,6 +40,12 @@ func WithImage(image string) podTemplateOption { } } +func WithAnnotations(annotations map[string]string) podTemplateOption { + return func(c *podTemplateConfig) { + c.annotations = annotations + } +} + func WithoutCredentialsVolume() podTemplateOption { return func(c *podTemplateConfig) { c.withoutCredentialsVolume = true @@ -98,7 +105,7 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1beta1.Deploy Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: containerLabels, - Annotations: podAnnotations(), + Annotations: podAnnotations(c.annotations), }, Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyAlways, diff --git a/pkg/install/resources.go b/pkg/install/resources.go index 18d4d5891..6eb7024c6 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -45,12 +45,20 @@ func labels() map[string]string { } } -func podAnnotations() map[string]string { - return map[string]string{ +func podAnnotations(userAnnotations map[string]string) map[string]string { + // Use the default annotations as a starting point + base := map[string]string{ "prometheus.io/scrape": "true", "prometheus.io/port": "8085", "prometheus.io/path": "/metrics", } + + // Merge base annotations with user annotations to enforce CLI precedence + for k, v := range userAnnotations { + base[k] = v + } + + return base } func containerPorts() []corev1.ContainerPort { @@ -180,6 +188,7 @@ type VeleroOptions struct { ProviderName string Bucket string Prefix string + PodAnnotations map[string]string SecretData []byte RestoreOnly bool UseRestic bool @@ -221,10 +230,12 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { } deploy := Deployment(o.Namespace, + WithAnnotations(o.PodAnnotations), WithImage(o.Image), ) if o.RestoreOnly { deploy = Deployment(o.Namespace, + WithAnnotations(o.PodAnnotations), WithImage(o.Image), WithRestoreOnly(), ) @@ -233,6 +244,7 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { if o.UseRestic { ds := DaemonSet(o.Namespace, + WithAnnotations(o.PodAnnotations), WithImage(o.Image), ) appendUnstructured(resources, ds)