diff --git a/cmd/app.go b/cmd/app.go index dfb3b96b..eb0123d9 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -31,8 +31,8 @@ const ( installAppDescription = ` Install an app template in the current Rancher server. This defaults to the newest version of the app template. Specify a version using '--version' if required. -The app will be installed into a new namespace unless '--namespace' is specified. - +The app will be installed into a new namespace unless '--namespace' is specified. + Example: # Install the redis template with no other options $ rancher app install redis appFoo @@ -817,7 +817,7 @@ func createNamespace(c *cliclient.MasterClient, n string) error { nsID := ns.ID startTime := time.Now() for { - logrus.Debug(fmt.Sprintf("Namespace create wait - Name: %s, State: %s, Transitioning: %s", ns.Name, ns.State, ns.Transitioning)) + logrus.Debugf("Namespace create wait - Name: %s, State: %s, Transitioning: %s", ns.Name, ns.State, ns.Transitioning) if time.Since(startTime)/time.Second > 30 { return fmt.Errorf("timed out waiting for new namespace %s", ns.Name) } diff --git a/cmd/catalog.go b/cmd/catalog.go index 914031a6..dc26d758 100644 --- a/cmd/catalog.go +++ b/cmd/catalog.go @@ -1,7 +1,11 @@ package cmd import ( + "time" + + "github.com/pkg/errors" managementClient "github.com/rancher/types/client/management/v3" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -16,6 +20,26 @@ Example: # Add a catalog and specify the branch to use $ rancher catalog add --branch awesomebranch foo https://my.catalog ` + + refreshCatalogDescription = ` +Refresh a catalog on the Rancher server + +Example: + # Refresh a catalog + $ rancher catalog refresh foo + + # Refresh multiple catalogs + $ rancher catalog refresh foo bar baz + + # Refresh all catalogs + $ rancher catalog refresh --all + + # Refresh is asynchronous unless you specify '--wait' + $ rancher catalog refresh --all --wait --wait-timeout=60 + + # Default wait timeout is 60 seconds, set to 0 to remove the timeout + $ rancher catalog refresh --all --wait --wait-timeout=0 +` ) type CatalogData struct { @@ -27,6 +51,10 @@ func CatalogCommand() cli.Command { catalogLsFlags := []cli.Flag{ formatFlag, quietFlag, + cli.BoolFlag{ + Name: "verbose,v", + Usage: "Include the catalog's state", + }, } return cli.Command{ @@ -64,6 +92,28 @@ func CatalogCommand() cli.Command { ArgsUsage: "[CATALOG_NAME/CATALOG_ID]", Action: catalogDelete, }, + cli.Command{ + Name: "refresh", + Usage: "Refresh catalog templates", + Description: refreshCatalogDescription, + ArgsUsage: "[CATALOG_NAME/CATALOG_ID]...", + Action: catalogRefresh, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "all", + Usage: "Refresh all catalogs", + }, + cli.BoolFlag{ + Name: "wait,w", + Usage: "Wait for catalog(s) to become active", + }, + cli.IntFlag{ + Name: "wait-timeout", + Usage: "Wait timeout duration in seconds", + Value: 60, + }, + }, + }, }, } } @@ -79,13 +129,19 @@ func catalogLs(ctx *cli.Context) error { return err } - writer := NewTableWriter([][]string{ + fields := [][]string{ {"ID", "ID"}, {"NAME", "Catalog.Name"}, {"URL", "Catalog.URL"}, {"BRANCH", "Catalog.Branch"}, {"KIND", "Catalog.Kind"}, - }, ctx) + } + + if ctx.Bool("verbose") { + fields = append(fields, []string{"STATE", "Catalog.State"}) + } + + writer := NewTableWriter(fields, ctx) defer writer.Close() @@ -153,3 +209,92 @@ func catalogDelete(ctx *cli.Context) error { } return nil } + +func catalogRefresh(ctx *cli.Context) error { + if len(ctx.Args()) < 1 && !ctx.Bool("all") { + return cli.ShowSubcommandHelp(ctx) + } + + c, err := GetClient(ctx) + if err != nil { + return err + } + + var catalogs []managementClient.Catalog + + if ctx.Bool("all") { + opts := baseListOpts() + + collection, err := c.ManagementClient.Catalog.List(opts) + if err != nil { + return err + } + + // save the catalogs in case we need to wait for them to become active + catalogs = collection.Data + + err = c.ManagementClient.Catalog.CollectionActionRefresh(collection) + if err != nil { + return err + } + + } else { + for _, arg := range ctx.Args() { + resource, err := Lookup(c, arg, "catalog") + if err != nil { + return err + } + + catalog, err := c.ManagementClient.Catalog.ByID(resource.ID) + if err != nil { + return err + } + + // collect the refreshing catalogs in case we need to wait for them later + catalogs = append(catalogs, *catalog) + + err = c.ManagementClient.Catalog.ActionRefresh(catalog) + if err != nil { + return err + } + } + } + + if ctx.Bool("wait") { + timeout := time.Duration(ctx.Int("wait-timeout")) * time.Second + start := time.Now() + + logrus.Debugf("catalog: waiting for catalogs to become active (timeout=%v)", timeout) + + for _, catalog := range catalogs { + + logrus.Debugf("catalog: waiting for %s to become active", catalog.Name) + + resource, err := Lookup(c, catalog.Name, "catalog") + if err != nil { + return err + } + + catalog, err := c.ManagementClient.Catalog.ByID(resource.ID) + if err != nil { + return err + } + + for catalog.State != "active" { + time.Sleep(time.Second) + catalog, err = c.ManagementClient.Catalog.ByID(resource.ID) + if err != nil { + return err + } + + if timeout > 0 && time.Since(start) > timeout { + return errors.New("catalog: timed out waiting for refresh") + } + } + + } + logrus.Debugf("catalog: waited for %v", time.Since(start)) + } + + return nil +}