diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index 3b87d9154..7abb3f1cc 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -27,6 +27,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/client" @@ -66,6 +67,7 @@ type InstallOptions struct { DefaultResticMaintenanceFrequency time.Duration Plugins flag.StringArray NoDefaultBackupLocation bool + CRDsOnly bool } // BindFlags adds command line values to the options struct. @@ -96,6 +98,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { 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") + flags.BoolVar(&o.CRDsOnly, "crds-only", o.CRDsOnly, "only generate CustomResourceDefinition resources. Useful for updating CRDs for an existing Velero install.") } // NewInstallOptions instantiates a new, default InstallOptions struct. @@ -118,6 +121,7 @@ func NewInstallOptions() *InstallOptions { // Default to creating a VSL unless we're told otherwise UseVolumeSnapshots: true, NoDefaultBackupLocation: false, + CRDsOnly: false, } } @@ -222,14 +226,19 @@ This is useful as a starting point for more customized installations. // Run executes a command in the context of the provided arguments. func (o *InstallOptions) Run(c *cobra.Command, f client.Factory) error { - vo, err := o.AsVeleroOptions() - if err != nil { - return err - } + var resources *unstructured.UnstructuredList + if o.CRDsOnly { + resources = install.AllCRDs() + } else { + vo, err := o.AsVeleroOptions() + if err != nil { + return err + } - resources, err := install.AllResources(vo) - if err != nil { - return err + resources, err = install.AllResources(vo) + if err != nil { + return err + } } if _, err := output.PrintWithFormat(c, resources); err != nil { @@ -289,6 +298,11 @@ func (o *InstallOptions) Validate(c *cobra.Command, args []string, f client.Fact return err } + // If we're only installing CRDs, we can skip the rest of the validation. + if o.CRDsOnly { + return nil + } + // Our main 3 providers don't support bucket names starting with a dash, and a bucket name starting with one // can indicate that an environment variable was left blank. // This case will help catch that error diff --git a/pkg/install/resources.go b/pkg/install/resources.go index bed88a3fd..d6cec3163 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -219,9 +219,7 @@ type VeleroOptions struct { NoDefaultBackupLocation bool } -// AllResources returns a list of all resources necessary to install Velero, in the appropriate order, into a Kubernetes cluster. -// Items are unstructured, since there are different data types returned. -func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { +func AllCRDs() *unstructured.UnstructuredList { resources := new(unstructured.UnstructuredList) // Set the GVK so that the serialization framework outputs the list properly resources.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"}) @@ -231,6 +229,14 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { appendUnstructured(resources, crd) } + return resources +} + +// AllResources returns a list of all resources necessary to install Velero, in the appropriate order, into a Kubernetes cluster. +// Items are unstructured, since there are different data types returned. +func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) { + resources := AllCRDs() + ns := Namespace(o.Namespace) appendUnstructured(resources, ns)