Make secret file optional on install (#1699)
* Make secret file optional on install Fixes #1689 Signed-off-by: Nolan Brubaker <brubakern@vmware.com>pull/1721/head
parent
2a6929d453
commit
635dd27e1a
|
@ -0,0 +1 @@
|
|||
Make --secret-file argument on `velero install` optional, add --no-secret flag for explicit confirmation
|
|
@ -55,6 +55,7 @@ type InstallOptions struct {
|
|||
ResticPodMemLimit string
|
||||
RestoreOnly bool
|
||||
SecretFile string
|
||||
NoSecret bool
|
||||
DryRun bool
|
||||
BackupStorageConfig flag.Map
|
||||
VolumeSnapshotConfig flag.Map
|
||||
|
@ -67,7 +68,8 @@ type InstallOptions struct {
|
|||
func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
flags.StringVar(&o.ProviderName, "provider", o.ProviderName, "provider name for backup and volume storage")
|
||||
flags.StringVar(&o.BucketName, "bucket", o.BucketName, "name of the object storage bucket where backups should be stored")
|
||||
flags.StringVar(&o.SecretFile, "secret-file", o.SecretFile, "file containing credentials for backup and volume provider")
|
||||
flags.StringVar(&o.SecretFile, "secret-file", o.SecretFile, "file containing credentials for backup and volume provider. If not specified, --no-secret must be used for confirmation. Optional.")
|
||||
flags.BoolVar(&o.NoSecret, "no-secret", o.NoSecret, "flag indicating if a secret should be created. Must be used as confirmation if --secret-file is not provided. Optional.")
|
||||
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")
|
||||
|
@ -112,13 +114,16 @@ func NewInstallOptions() *InstallOptions {
|
|||
|
||||
// AsVeleroOptions translates the values provided at the command line into values used to instantiate Kubernetes resources
|
||||
func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) {
|
||||
realPath, err := filepath.Abs(o.SecretFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretData, err := ioutil.ReadFile(realPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var secretData []byte
|
||||
if o.SecretFile != "" && !o.NoSecret {
|
||||
realPath, err := filepath.Abs(o.SecretFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretData, err = ioutil.ReadFile(realPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
veleroPodResources, err := parseResourceRequests(o.VeleroPodCPURequest, o.VeleroPodMemRequest, o.VeleroPodCPULimit, o.VeleroPodMemLimit)
|
||||
if err != nil {
|
||||
|
@ -179,7 +184,7 @@ This is useful as a starting point for more customized installations.
|
|||
|
||||
# velero install --bucket gcp-backups --provider gcp --secret-file ./gcp-creds.json --wait
|
||||
|
||||
# velero install --bucket backups --provider aws --backup-location-config region=us-west-2 --secret-file ./an-empty-file --snapshot-location-config region=us-west-2 --pod-annotations iam.amazonaws.com/role=arn:aws:iam::<AWS_ACCOUNT_ID>:role/<VELERO_ROLE_NAME>
|
||||
# velero install --bucket backups --provider aws --backup-location-config region=us-west-2 --snapshot-location-config region=us-west-2 --no-secret --pod-annotations iam.amazonaws.com/role=arn:aws:iam::<AWS_ACCOUNT_ID>:role/<VELERO_ROLE_NAME>
|
||||
|
||||
# velero install --bucket gcp-backups --provider gcp --secret-file ./gcp-creds.json --velero-pod-cpu-request=1000m --velero-pod-cpu-limit=5000m --velero-pod-mem-request=512Mi --velero-pod-mem-limit=1024Mi
|
||||
|
||||
|
@ -238,6 +243,9 @@ func (o *InstallOptions) Run(c *cobra.Command, f client.Factory) error {
|
|||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
}
|
||||
if o.SecretFile == "" {
|
||||
fmt.Printf("\nNo secret file was specified, no Secret created.\n\n")
|
||||
}
|
||||
fmt.Printf("Velero is installed! ⛵ Use 'kubectl logs deployment/velero -n %s' to view the status.\n", o.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
@ -268,8 +276,11 @@ func (o *InstallOptions) Validate(c *cobra.Command, args []string, f client.Fact
|
|||
return errors.New("--provider is required")
|
||||
}
|
||||
|
||||
if o.SecretFile == "" {
|
||||
return errors.New("--secret-file is required")
|
||||
switch {
|
||||
case o.SecretFile == "" && !o.NoSecret:
|
||||
return errors.New("One of --secret-file or --no-secret is required")
|
||||
case o.SecretFile != "" && o.NoSecret:
|
||||
return errors.New("Cannot use both --secret-file and --no-secret")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -129,18 +129,6 @@ func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet {
|
|||
Name: "VELERO_SCRATCH_DIR",
|
||||
Value: "/scratch",
|
||||
},
|
||||
{
|
||||
Name: "AZURE_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AWS_SHARED_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
},
|
||||
Resources: c.resources,
|
||||
},
|
||||
|
@ -150,7 +138,7 @@ func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet {
|
|||
},
|
||||
}
|
||||
|
||||
if !c.withoutCredentialsVolume {
|
||||
if c.withSecret {
|
||||
daemonSet.Spec.Template.Spec.Volumes = append(
|
||||
daemonSet.Spec.Template.Spec.Volumes,
|
||||
corev1.Volume{
|
||||
|
@ -170,6 +158,21 @@ func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet {
|
|||
MountPath: "/credentials",
|
||||
},
|
||||
)
|
||||
|
||||
daemonSet.Spec.Template.Spec.Containers[0].Env = append(daemonSet.Spec.Template.Spec.Containers[0].Env, []corev1.EnvVar{
|
||||
{
|
||||
Name: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AWS_SHARED_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AZURE_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
daemonSet.Spec.Template.Spec.Containers[0].Env = append(daemonSet.Spec.Template.Spec.Containers[0].Env, c.envVars...)
|
||||
|
|
|
@ -29,10 +29,11 @@ func TestDaemonSet(t *testing.T) {
|
|||
assert.Equal(t, "restic", ds.Spec.Template.Spec.Containers[0].Name)
|
||||
assert.Equal(t, "velero", ds.ObjectMeta.Namespace)
|
||||
|
||||
ds = DaemonSet("velero", WithoutCredentialsVolume())
|
||||
assert.Equal(t, 2, len(ds.Spec.Template.Spec.Volumes))
|
||||
|
||||
ds = DaemonSet("velero", WithImage("gcr.io/heptio-images/velero:v0.11"))
|
||||
assert.Equal(t, "gcr.io/heptio-images/velero:v0.11", ds.Spec.Template.Spec.Containers[0].Image)
|
||||
assert.Equal(t, corev1.PullIfNotPresent, ds.Spec.Template.Spec.Containers[0].ImagePullPolicy)
|
||||
|
||||
ds = DaemonSet("velero", WithSecret(true))
|
||||
assert.Equal(t, 6, len(ds.Spec.Template.Spec.Containers[0].Env))
|
||||
assert.Equal(t, 3, len(ds.Spec.Template.Spec.Volumes))
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@ import (
|
|||
type podTemplateOption func(*podTemplateConfig)
|
||||
|
||||
type podTemplateConfig struct {
|
||||
image string
|
||||
withoutCredentialsVolume bool
|
||||
envVars []corev1.EnvVar
|
||||
restoreOnly bool
|
||||
annotations map[string]string
|
||||
resources corev1.ResourceRequirements
|
||||
image string
|
||||
envVars []corev1.EnvVar
|
||||
restoreOnly bool
|
||||
annotations map[string]string
|
||||
resources corev1.ResourceRequirements
|
||||
withSecret bool
|
||||
}
|
||||
|
||||
func WithImage(image string) podTemplateOption {
|
||||
|
@ -47,12 +47,6 @@ func WithAnnotations(annotations map[string]string) podTemplateOption {
|
|||
}
|
||||
}
|
||||
|
||||
func WithoutCredentialsVolume() podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.withoutCredentialsVolume = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithEnvFromSecretKey(varName, secret, key string) podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.envVars = append(c.envVars, corev1.EnvVar{
|
||||
|
@ -69,6 +63,12 @@ func WithEnvFromSecretKey(varName, secret, key string) podTemplateOption {
|
|||
}
|
||||
}
|
||||
|
||||
func WithSecret(secretPresent bool) podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.withSecret = secretPresent
|
||||
}
|
||||
}
|
||||
|
||||
func WithRestoreOnly() podTemplateOption {
|
||||
return func(c *podTemplateConfig) {
|
||||
c.restoreOnly = true
|
||||
|
@ -144,18 +144,6 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment
|
|||
Name: "VELERO_SCRATCH_DIR",
|
||||
Value: "/scratch",
|
||||
},
|
||||
{
|
||||
Name: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AWS_SHARED_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AZURE_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
},
|
||||
Resources: c.resources,
|
||||
},
|
||||
|
@ -179,7 +167,7 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment
|
|||
},
|
||||
}
|
||||
|
||||
if !c.withoutCredentialsVolume {
|
||||
if c.withSecret {
|
||||
deployment.Spec.Template.Spec.Volumes = append(
|
||||
deployment.Spec.Template.Spec.Volumes,
|
||||
corev1.Volume{
|
||||
|
@ -199,6 +187,21 @@ func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment
|
|||
MountPath: "/credentials",
|
||||
},
|
||||
)
|
||||
|
||||
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env, []corev1.EnvVar{
|
||||
{
|
||||
Name: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AWS_SHARED_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
{
|
||||
Name: "AZURE_CREDENTIALS_FILE",
|
||||
Value: "/credentials/cloud",
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env, c.envVars...)
|
||||
|
|
|
@ -32,15 +32,16 @@ func TestDeployment(t *testing.T) {
|
|||
assert.Equal(t, "--restore-only", deploy.Spec.Template.Spec.Containers[0].Args[1])
|
||||
|
||||
deploy = Deployment("velero", WithEnvFromSecretKey("my-var", "my-secret", "my-key"))
|
||||
envSecret := deploy.Spec.Template.Spec.Containers[0].Env[4]
|
||||
envSecret := deploy.Spec.Template.Spec.Containers[0].Env[1]
|
||||
assert.Equal(t, "my-var", envSecret.Name)
|
||||
assert.Equal(t, "my-secret", envSecret.ValueFrom.SecretKeyRef.LocalObjectReference.Name)
|
||||
assert.Equal(t, "my-key", envSecret.ValueFrom.SecretKeyRef.Key)
|
||||
|
||||
deploy = Deployment("velero", WithoutCredentialsVolume())
|
||||
assert.Equal(t, 2, len(deploy.Spec.Template.Spec.Volumes))
|
||||
|
||||
deploy = Deployment("velero", WithImage("gcr.io/heptio-images/velero:v0.11"))
|
||||
assert.Equal(t, "gcr.io/heptio-images/velero:v0.11", deploy.Spec.Template.Spec.Containers[0].Image)
|
||||
assert.Equal(t, corev1.PullIfNotPresent, deploy.Spec.Template.Spec.Containers[0].ImagePullPolicy)
|
||||
|
||||
deploy = Deployment("velero", WithSecret(true))
|
||||
assert.Equal(t, 4, len(deploy.Spec.Template.Spec.Containers[0].Env))
|
||||
assert.Equal(t, 3, len(deploy.Spec.Template.Spec.Volumes))
|
||||
}
|
||||
|
|
|
@ -229,8 +229,10 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) {
|
|||
sa := ServiceAccount(o.Namespace)
|
||||
appendUnstructured(resources, sa)
|
||||
|
||||
sec := Secret(o.Namespace, o.SecretData)
|
||||
appendUnstructured(resources, sec)
|
||||
if o.SecretData != nil {
|
||||
sec := Secret(o.Namespace, o.SecretData)
|
||||
appendUnstructured(resources, sec)
|
||||
}
|
||||
|
||||
bsl := BackupStorageLocation(o.Namespace, o.ProviderName, o.Bucket, o.Prefix, o.BSLConfig)
|
||||
appendUnstructured(resources, bsl)
|
||||
|
@ -241,15 +243,19 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) {
|
|||
appendUnstructured(resources, vsl)
|
||||
}
|
||||
|
||||
secretPresent := o.SecretData != nil
|
||||
|
||||
deploy := Deployment(o.Namespace,
|
||||
WithAnnotations(o.PodAnnotations),
|
||||
WithImage(o.Image),
|
||||
WithResources(o.VeleroPodResources),
|
||||
WithSecret(secretPresent),
|
||||
)
|
||||
if o.RestoreOnly {
|
||||
deploy = Deployment(o.Namespace,
|
||||
WithAnnotations(o.PodAnnotations),
|
||||
WithImage(o.Image),
|
||||
WithSecret(secretPresent),
|
||||
WithRestoreOnly(),
|
||||
)
|
||||
}
|
||||
|
@ -257,9 +263,11 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) {
|
|||
|
||||
if o.UseRestic {
|
||||
ds := DaemonSet(o.Namespace,
|
||||
|
||||
WithAnnotations(o.PodAnnotations),
|
||||
WithImage(o.Image),
|
||||
WithResources(o.ResticPodResources),
|
||||
WithSecret(secretPresent),
|
||||
)
|
||||
appendUnstructured(resources, ds)
|
||||
}
|
||||
|
|
|
@ -292,13 +292,11 @@ velero install \
|
|||
--pod-annotations iam.amazonaws.com/role=arn:aws:iam::<AWS_ACCOUNT_ID>:role/<VELERO_ROLE_NAME> \
|
||||
--provider aws \
|
||||
--bucket $BUCKET \
|
||||
--secret-file ./credentials-velero \
|
||||
--backup-location-config region=$REGION \
|
||||
--snapshot-location-config region=$REGION
|
||||
--snapshot-location-config region=$REGION \
|
||||
--no-secret
|
||||
```
|
||||
|
||||
Note that the `--secret-file` argument is required, but it can be an empty file.
|
||||
|
||||
[0]: namespace.md
|
||||
[5]: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html
|
||||
[6]: api-types/volumesnapshotlocation.md#aws
|
||||
|
|
|
@ -14,7 +14,8 @@ The Velero client includes an `install` command to specify the settings for each
|
|||
velero install \
|
||||
--provider <YOUR_PROVIDER> \
|
||||
--bucket <YOUR_BUCKET> \
|
||||
--secret-file <PATH_TO_FILE> \
|
||||
[--secret-file <PATH_TO_FILE>] \
|
||||
[--no-secret] \
|
||||
[--backup-location-config] \
|
||||
[--snapshot-location-config] \
|
||||
[--namespace] \
|
||||
|
@ -23,6 +24,8 @@ velero install \
|
|||
[--pod-annotations] \
|
||||
```
|
||||
|
||||
When using node-based IAM policies, `--secret-file` is not required, but `--no-secret` is required for confirmation.
|
||||
|
||||
For provider-specific instructions, see:
|
||||
|
||||
* [Run Velero on AWS][0]
|
||||
|
|
Loading…
Reference in New Issue