diff --git a/cmd/openshift-install/create.go b/cmd/openshift-install/create.go index 4d53d47e4b8..f441c8b70fd 100644 --- a/cmd/openshift-install/create.go +++ b/cmd/openshift-install/create.go @@ -104,25 +104,18 @@ var ( logrus.Fatal(errors.Wrap(err, "loading kubeconfig")) } - err = destroyBootstrap(ctx, config, rootOpts.dir) + err = waitForBootstrapComplete(ctx, config, rootOpts.dir) if err != nil { logrus.Fatal(err) } - if err := waitForInitializedCluster(ctx, config); err != nil { - logrus.Fatal(err) - } - - consoleURL, err := waitForConsole(ctx, config, rootOpts.dir) + logrus.Info("Destroying the bootstrap resources...") + err = destroybootstrap.Destroy(rootOpts.dir) if err != nil { logrus.Fatal(err) } - if err = addRouterCAToClusterCA(config, rootOpts.dir); err != nil { - logrus.Fatal(err) - } - - err = logComplete(rootOpts.dir, consoleURL) + err = finish(ctx, config, rootOpts.dir) if err != nil { logrus.Fatal(err) } @@ -244,7 +237,7 @@ func addRouterCAToClusterCA(config *rest.Config, directory string) (err error) { // FIXME: pulling the kubeconfig and metadata out of the root // directory is a bit cludgy when we already have them in memory. -func destroyBootstrap(ctx context.Context, config *rest.Config, directory string) (err error) { +func waitForBootstrapComplete(ctx context.Context, config *rest.Config, directory string) (err error) { client, err := kubernetes.NewForConfig(config) if err != nil { return errors.Wrap(err, "creating a Kubernetes client") @@ -288,12 +281,7 @@ func destroyBootstrap(ctx context.Context, config *rest.Config, directory string eventTimeout := 30 * time.Minute logrus.Infof("Waiting up to %v for the bootstrap-complete event...", eventTimeout) - if err := waitForEvent(ctx, client.CoreV1().RESTClient(), "bootstrap-complete", eventTimeout); err != nil { - return err - } - - logrus.Info("Destroying the bootstrap resources...") - return destroybootstrap.Destroy(rootOpts.dir) + return waitForEvent(ctx, client.CoreV1().RESTClient(), "bootstrap-complete", eventTimeout) } // waitForEvent watches the events in the kube-system namespace, waits @@ -454,3 +442,20 @@ func logComplete(directory, consoleURL string) error { logrus.Infof("Login to the console with user: kubeadmin, password: %s", pw) return nil } + +func finish(ctx context.Context, config *rest.Config, directory string) error { + if err := waitForInitializedCluster(ctx, config); err != nil { + return err + } + + consoleURL, err := waitForConsole(ctx, config, rootOpts.dir) + if err != nil { + return err + } + + if err = addRouterCAToClusterCA(config, rootOpts.dir); err != nil { + return err + } + + return logComplete(rootOpts.dir, consoleURL) +} diff --git a/cmd/openshift-install/main.go b/cmd/openshift-install/main.go index 4971cac8447..51b3a9fd8c8 100644 --- a/cmd/openshift-install/main.go +++ b/cmd/openshift-install/main.go @@ -46,6 +46,7 @@ func installerMain() { for _, subCmd := range []*cobra.Command{ newCreateCmd(), newDestroyCmd(), + newUPICmd(), newVersionCmd(), newGraphCmd(), newCompletionCmd(), diff --git a/cmd/openshift-install/upi.go b/cmd/openshift-install/upi.go new file mode 100644 index 00000000000..ce0d8d99cf1 --- /dev/null +++ b/cmd/openshift-install/upi.go @@ -0,0 +1,96 @@ +package main + +import ( + "context" + "path/filepath" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "k8s.io/client-go/tools/clientcmd" +) + +var ( + upiLong = `Entry-points for user-provided infrastructure. + +Most users will want to use 'create cluster' to have the installer +create the required infrastructure for their cluster. But in some +installations the infrastructure needs to be adapted in ways that +installer-created infrastructure does not support. This command +provides entry points to support the following workflow: + +1. Call 'create ignition-configs' to create the bootstrap Ignition + config and admin kubeconfig. +2. Creates all required cluster resources, after which the cluster + will being bootstrapping. +3. Call 'user-provided-infrastructure bootstrap-complete' to wait + until the bootstrap phase has completed. +4. Destroy the bootstrap resources. +5. Call 'user-provided-infrastructure finish' to wait until the + cluster finishes deploying its initial version. This also + retrieves the router certificate authority from the cluster and + inserts it into the admin kubeconfig.` +) + +func newUPICmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "user-provided-infrastructure", + Aliases: []string{"upi"}, + Short: "Entry-points for user-provided infrastructure", + Long: upiLong, + RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, + } + cmd.AddCommand(newUPIBootstrapCompleteCmd()) + cmd.AddCommand(newUPIFinishCmd()) + return cmd +} + +func newUPIBootstrapCompleteCmd() *cobra.Command { + return &cobra.Command{ + Use: "bootstrap-complete", + Short: "Wait until cluster bootstrapping has completed", + Args: cobra.ExactArgs(0), + Run: func(_ *cobra.Command, _ []string) { + ctx := context.Background() + + cleanup := setupFileHook(rootOpts.dir) + defer cleanup() + + config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(rootOpts.dir, "auth", "kubeconfig")) + if err != nil { + logrus.Fatal(errors.Wrap(err, "loading kubeconfig")) + } + + err = waitForBootstrapComplete(ctx, config, rootOpts.dir) + if err != nil { + logrus.Fatal(err) + } + }, + } +} + +func newUPIFinishCmd() *cobra.Command { + return &cobra.Command{ + Use: "finish", + Short: "Wait for the cluster to finish updating and update local resources", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + ctx := context.Background() + + cleanup := setupFileHook(rootOpts.dir) + defer cleanup() + + config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(rootOpts.dir, "auth", "kubeconfig")) + if err != nil { + logrus.Fatal(errors.Wrap(err, "loading kubeconfig")) + } + + err = finish(ctx, config, rootOpts.dir) + if err != nil { + logrus.Fatal(err) + } + }, + } +}