diff --git a/cmd/root.go b/cmd/root.go index 4e213de0..cb1ef614 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -161,10 +161,6 @@ func InitPipeline() *client.APIClient { return client.NewAPIClient(config) } -func Out1(data interface{}, fields []string) { - Out([]interface{}{data}, fields) -} - func Out(data interface{}, fields []string) { switch rootOptions.Output { case "json": diff --git a/internal/cli/command/cluster/cmd.go b/internal/cli/command/cluster/cmd.go new file mode 100644 index 00000000..8a648474 --- /dev/null +++ b/internal/cli/command/cluster/cmd.go @@ -0,0 +1,39 @@ +// Copyright © 2019 Banzai Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cluster + +import ( + "github.com/banzaicloud/banzai-cli/internal/cli" + "github.com/spf13/cobra" +) + +// NewClusterCommand returns a cobra command for `cluster` subcommands. +func NewClusterCommand(banzaiCli cli.Cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "cluster", + Aliases: []string{"clusters", "c"}, + Short: "Manage clusters", + } + + cmd.AddCommand( + clusterListCmd, + clusterGetCmd, + clusterCreateCmd, + clusterShellCmd, + clusterDeleteCmd, + ) + + return cmd +} diff --git a/cmd/cluster.go b/internal/cli/command/cluster/legacy.go similarity index 96% rename from cmd/cluster.go rename to internal/cli/command/cluster/legacy.go index dafcd847..c880dc20 100644 --- a/cmd/cluster.go +++ b/internal/cli/command/cluster/legacy.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cmd +package cluster import ( "bytes" @@ -27,14 +27,14 @@ import ( "github.com/antihax/optional" "github.com/banzaicloud/pipeline/client" - yaml "github.com/ghodss/yaml" + "github.com/ghodss/yaml" "github.com/goph/emperror" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/ttacon/chalk" - survey "gopkg.in/AlecAivazis/survey.v1" + "gopkg.in/AlecAivazis/survey.v1" ) const clusterIdKey = "cluster.id" @@ -43,14 +43,6 @@ var clusterOptions struct { Name string } -// clusterCmd represents the cluster command -var clusterCmd = &cobra.Command{ - Use: "cluster", - Aliases: []string{"clusters", "c"}, - Short: "Handle clusters", - Run: ClusterList, -} - var clusterListCmd = &cobra.Command{ Use: "list", Aliases: []string{"l"}, @@ -426,13 +418,6 @@ func GetClusterId(org int32, ask bool) int32 { } func init() { - rootCmd.AddCommand(clusterCmd) - clusterCmd.AddCommand(clusterListCmd) - clusterCmd.AddCommand(clusterGetCmd) - clusterCmd.AddCommand(clusterCreateCmd) - clusterCmd.AddCommand(clusterShellCmd) - clusterCmd.AddCommand(clusterDeleteCmd) - clusterShellCmd.PersistentFlags().Int32("cluster", 0, "cluster id") viper.BindPFlag(clusterIdKey, clusterShellCmd.PersistentFlags().Lookup("cluster")) clusterShellCmd.PersistentFlags().StringVar(&clusterOptions.Name, "cluster-name", "", "cluster name") diff --git a/internal/cli/command/cluster/legacy_organization.go b/internal/cli/command/cluster/legacy_organization.go new file mode 100644 index 00000000..1e21a779 --- /dev/null +++ b/internal/cli/command/cluster/legacy_organization.go @@ -0,0 +1,67 @@ +// Copyright © 2019 Banzai Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cluster + +import ( + "context" + + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "gopkg.in/AlecAivazis/survey.v1" +) + +const orgIdKey = "organization.id" + +func searchOrganizationId(name string) int32 { + pipeline := InitPipeline() + orgs, _, err := pipeline.OrganizationsApi.ListOrgs(context.Background()) + if err != nil { + logAPIError("list organizations", err, nil) + return 0 + } + for _, org := range orgs { + if org.Name == name { + return org.Id + } + } + log.Errorf("Could not find organization %q", name) + return 0 +} + +func GetOrgId(ask bool) int32 { + id := viper.GetInt32(orgIdKey) + if id != 0 { + return id + } + if ask && !isInteractive() { + log.Fatal("No organization is selected. Use the --organization switch, or set it using `banzai org`.") + } + pipeline := InitPipeline() + orgs, _, err := pipeline.OrganizationsApi.ListOrgs(context.Background()) + if err != nil { + log.Fatalf("could not list organizations: %v", err) + } + orgSlice := make([]string, len(orgs)) + for i, org := range orgs { + orgSlice[i] = org.Name + } + name := "" + survey.AskOne(&survey.Select{Message: "Organization:", Options: orgSlice}, &name, survey.Required) + id = searchOrganizationId(name) + if id != 0 { + viper.Set(orgIdKey, id) + } + return id +} diff --git a/internal/cli/command/cluster/legacy_root.go b/internal/cli/command/cluster/legacy_root.go new file mode 100644 index 00000000..81184baf --- /dev/null +++ b/internal/cli/command/cluster/legacy_root.go @@ -0,0 +1,94 @@ +// Copyright © 2019 Banzai Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cluster + +import ( + "encoding/json" + "fmt" + "log" + "os" + + "github.com/banzaicloud/banzai-cli/pkg/formatting" + "github.com/banzaicloud/pipeline/client" + "github.com/mattn/go-isatty" + "github.com/spf13/viper" + "golang.org/x/oauth2" + "gopkg.in/yaml.v2" +) + +var rootOptions struct { + CfgFile string + Output string +} + +func InitPipeline() *client.APIClient { + config := client.NewConfiguration() + config.BasePath = viper.GetString("pipeline.basepath") + config.UserAgent = "banzai-cli/1.0.0/go" + config.HTTPClient = oauth2.NewClient(nil, oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: viper.GetString("pipeline.token")}, + )) + + return client.NewAPIClient(config) +} + +func Out1(data interface{}, fields []string) { + Out([]interface{}{data}, fields) +} + +func Out(data interface{}, fields []string) { + switch rootOptions.Output { + case "json": + bytes, err := json.MarshalIndent(data, "", " ") + if err != nil { + log.Fatalf("can't marshal output: %v", err) + } + fmt.Printf("%s\n", bytes) + + case "yaml": + bytes, err := yaml.Marshal(data) + if err != nil { + log.Fatalf("can't marshal output: %v", err) + } + fmt.Printf("%s\n", bytes) + + default: + table := formatting.NewTable(data, fields) + out := table.Format(isColor()) + fmt.Println(out) + } +} + +func logAPIError(action string, err error, request interface{}) { + if err, ok := err.(client.GenericOpenAPIError); ok { + log.Printf("failed to %s: %v (err %[2]T, request=%+v, response=%s)", action, err, request, err.Body()) + } else { + log.Printf("failed to %s: %v", action, err) + } +} + +func isInteractive() bool { + if isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stdin.Fd()) { + return !viper.GetBool("formatting.no-interactive") + } + return viper.GetBool("formatting.force-interactive") +} + +func isColor() bool { + if isatty.IsTerminal(os.Stdout.Fd()) { + return !viper.GetBool("formatting.no-color") + } + return viper.GetBool("formatting.force-color") +} diff --git a/internal/cli/command/cmd.go b/internal/cli/command/cmd.go index 2ef52e40..fa6a333e 100644 --- a/internal/cli/command/cmd.go +++ b/internal/cli/command/cmd.go @@ -16,6 +16,7 @@ package command import ( "github.com/banzaicloud/banzai-cli/internal/cli" + "github.com/banzaicloud/banzai-cli/internal/cli/command/cluster" "github.com/banzaicloud/banzai-cli/internal/cli/command/organization" "github.com/banzaicloud/banzai-cli/internal/cli/command/secret" "github.com/spf13/cobra" @@ -24,6 +25,7 @@ import ( // AddCommands adds all the commands from cli/command to the root command func AddCommands(cmd *cobra.Command, banzaiCli cli.Cli) { cmd.AddCommand( + cluster.NewClusterCommand(banzaiCli), organization.NewOrganizationCommand(banzaiCli), secret.NewSecretCommand(banzaiCli), )