Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor get to use subcommands instead of a manual case statement
- Loading branch information
Showing
5 changed files
with
397 additions
and
301 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package cli | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/pkg/errors" | ||
"github.com/replicatedhq/kots/pkg/api/handlers/types" | ||
"github.com/replicatedhq/kots/pkg/auth" | ||
"github.com/replicatedhq/kots/pkg/k8sutil" | ||
"github.com/replicatedhq/kots/pkg/logger" | ||
"github.com/replicatedhq/kots/pkg/print" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"io/ioutil" | ||
"net/http" | ||
"os" | ||
) | ||
|
||
func GetAppsCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "apps", | ||
Aliases: []string{"app"}, | ||
Short: "Get apps", | ||
Long: "", | ||
SilenceUsage: false, | ||
SilenceErrors: false, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
viper.BindPFlags(cmd.Flags()) | ||
}, | ||
RunE: getAppsCmd, | ||
} | ||
|
||
cmd.Flags().StringP("output", "o", "", "output format. supported values: json") | ||
|
||
return cmd | ||
} | ||
|
||
func getAppsCmd(cmd *cobra.Command, args []string) error { | ||
v := viper.GetViper() | ||
|
||
log := logger.NewCLILogger() | ||
|
||
stopCh := make(chan struct{}) | ||
defer close(stopCh) | ||
|
||
clientset, err := k8sutil.GetClientset() | ||
if err != nil { | ||
return errors.Wrap(err, "failed to get clientset") | ||
} | ||
|
||
namespace := v.GetString("namespace") | ||
if err := validateNamespace(namespace); err != nil { | ||
return errors.Wrap(err, "failed to validate namespace") | ||
} | ||
|
||
podName, err := k8sutil.FindKotsadm(clientset, namespace) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to find kotsadm pod") | ||
} | ||
|
||
localPort, errChan, err := k8sutil.PortForward(0, 3000, namespace, podName, false, stopCh, log) | ||
if err != nil { | ||
log.FinishSpinnerWithError() | ||
return errors.Wrap(err, "failed to start port forwarding") | ||
} | ||
|
||
go func() { | ||
select { | ||
case err := <-errChan: | ||
if err != nil { | ||
log.Error(err) | ||
} | ||
case <-stopCh: | ||
} | ||
}() | ||
|
||
authSlug, err := auth.GetOrCreateAuthSlug(clientset, namespace) | ||
if err != nil { | ||
log.FinishSpinnerWithError() | ||
log.Info("Unable to authenticate to the Admin Console running in the %s namespace. Ensure you have read access to secrets in this namespace and try again.", namespace) | ||
if v.GetBool("debug") { | ||
return errors.Wrap(err, "failed to get kotsadm auth slug") | ||
} | ||
os.Exit(2) // not returning error here as we don't want to show the entire stack trace to normal users | ||
} | ||
|
||
url := fmt.Sprintf("http://localhost:%d/api/v1/apps", localPort) | ||
apps, err := getApps(url, authSlug) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to get apps") | ||
} | ||
|
||
printableApps := make([]print.App, 0) | ||
for _, app := range apps.Apps { | ||
versionLabel := "" | ||
for _, d := range app.Downstreams { | ||
if d.CurrentVersion != nil { | ||
versionLabel = d.CurrentVersion.VersionLabel | ||
break | ||
} | ||
} | ||
url := fmt.Sprintf("http://localhost:%d/api/v1/app/%s/status", localPort, app.Slug) | ||
appStatus, err := getAppStatus(url, authSlug) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to get app status for %s", app.Slug) | ||
} | ||
printableApps = append(printableApps, print.App{ | ||
Slug: app.Slug, | ||
State: string(appStatus.AppStatus.State), | ||
VersionLabel: versionLabel, | ||
}) | ||
} | ||
|
||
print.Apps(printableApps, v.GetString("output")) | ||
|
||
return nil | ||
} | ||
|
||
func getApps(url string, authSlug string) (*types.ListAppsResponse, error) { | ||
newReq, err := http.NewRequest("GET", url, nil) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to create request") | ||
} | ||
newReq.Header.Add("Content-Type", "application/json") | ||
newReq.Header.Add("Authorization", authSlug) | ||
|
||
resp, err := http.DefaultClient.Do(newReq) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to execute request") | ||
} | ||
defer resp.Body.Close() | ||
|
||
b, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to read") | ||
} | ||
|
||
apps := &types.ListAppsResponse{} | ||
if err := json.Unmarshal(b, apps); err != nil { | ||
return nil, errors.Wrap(err, "failed to unmarshal apps") | ||
} | ||
|
||
return apps, nil | ||
} | ||
|
||
func getAppStatus(url string, authSlug string) (*types.AppStatusResponse, error) { | ||
newReq, err := http.NewRequest("GET", url, nil) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to create request") | ||
} | ||
newReq.Header.Add("Content-Type", "application/json") | ||
newReq.Header.Add("Authorization", authSlug) | ||
|
||
resp, err := http.DefaultClient.Do(newReq) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to execute request") | ||
} | ||
defer resp.Body.Close() | ||
|
||
b, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to read") | ||
} | ||
|
||
status := &types.AppStatusResponse{} | ||
if err := json.Unmarshal(b, status); err != nil { | ||
return nil, errors.Wrap(err, "failed to unmarshal status") | ||
} | ||
|
||
return status, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package cli | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/replicatedhq/kots/pkg/print" | ||
"github.com/replicatedhq/kots/pkg/snapshot" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func GetBackupsCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "backups", | ||
Aliases: []string{"backup"}, | ||
Short: "Get backups", | ||
Long: "", | ||
SilenceUsage: false, | ||
SilenceErrors: false, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
viper.BindPFlags(cmd.Flags()) | ||
}, | ||
RunE: getBackupsCmd, | ||
} | ||
|
||
cmd.Flags().StringP("output", "o", "", "output format. supported values: json") | ||
|
||
return cmd | ||
} | ||
|
||
func getBackupsCmd(cmd *cobra.Command, args []string) error { | ||
v := viper.GetViper() | ||
|
||
options := snapshot.ListInstanceBackupsOptions{ | ||
Namespace: v.GetString("namespace"), | ||
} | ||
backups, err := snapshot.ListInstanceBackups(cmd.Context(), options) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to list instance backups") | ||
} | ||
|
||
print.Backups(backups, v.GetString("output")) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package cli | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/pkg/errors" | ||
"github.com/replicatedhq/kots/pkg/auth" | ||
"github.com/replicatedhq/kots/pkg/handlers" | ||
"github.com/replicatedhq/kots/pkg/k8sutil" | ||
"github.com/replicatedhq/kots/pkg/logger" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"io/ioutil" | ||
"net/http" | ||
"os" | ||
"sigs.k8s.io/yaml" | ||
) | ||
|
||
func GetConfigCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "config --sequence=1 --appslug=my-app", | ||
Short: "Get config values for an application", | ||
Long: "", | ||
SilenceUsage: false, | ||
SilenceErrors: false, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
viper.BindPFlags(cmd.Flags()) | ||
}, | ||
RunE: getConfigCmd, | ||
} | ||
|
||
cmd.Flags().Int("sequence", -1, "app sequence to retrieve config for") | ||
cmd.Flags().String("appslug", "", "app slug to retrieve config for") | ||
|
||
return cmd | ||
} | ||
|
||
func getConfigCmd(cmd *cobra.Command, args []string) error { | ||
v := viper.GetViper() | ||
|
||
log := logger.NewCLILogger() | ||
|
||
stopCh := make(chan struct{}) | ||
defer close(stopCh) | ||
|
||
clientset, err := k8sutil.GetClientset() | ||
if err != nil { | ||
return errors.Wrap(err, "failed to get clientset") | ||
} | ||
|
||
namespace := v.GetString("namespace") | ||
if err := validateNamespace(namespace); err != nil { | ||
return errors.Wrap(err, "failed to validate namespace") | ||
} | ||
|
||
podName, err := k8sutil.FindKotsadm(clientset, namespace) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to find kotsadm pod") | ||
} | ||
|
||
localPort, errChan, err := k8sutil.PortForward(0, 3000, namespace, podName, false, stopCh, log) | ||
if err != nil { | ||
log.FinishSpinnerWithError() | ||
return errors.Wrap(err, "failed to start port forwarding") | ||
} | ||
|
||
go func() { | ||
select { | ||
case err := <-errChan: | ||
if err != nil { | ||
log.Error(err) | ||
} | ||
case <-stopCh: | ||
} | ||
}() | ||
|
||
authSlug, err := auth.GetOrCreateAuthSlug(clientset, namespace) | ||
if err != nil { | ||
log.FinishSpinnerWithError() | ||
log.Info("Unable to authenticate to the Admin Console running in the %s namespace. Ensure you have read access to secrets in this namespace and try again.", namespace) | ||
if v.GetBool("debug") { | ||
return errors.Wrap(err, "failed to get kotsadm auth slug") | ||
} | ||
os.Exit(2) // not returning error here as we don't want to show the entire stack trace to normal users | ||
} | ||
|
||
url := fmt.Sprintf("http://localhost:%d/api/v1/app/%s/config/%d", localPort, v.GetString("appslug"), v.GetInt("sequence")) | ||
config, err := getConfig(url, authSlug) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to get config") | ||
} | ||
|
||
values := handlers.ConfigGroupToValues(config.ConfigGroups) | ||
configYaml, err := yaml.Marshal(values) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to marshal config") | ||
} | ||
|
||
fmt.Print(string(configYaml)) | ||
|
||
return nil | ||
} | ||
|
||
func getConfig(url string, authSlug string) (*handlers.CurrentAppConfigResponse, error) { | ||
newReq, err := http.NewRequest("GET", url, nil) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to create request") | ||
} | ||
newReq.Header.Add("Content-Type", "application/json") | ||
newReq.Header.Add("Authorization", authSlug) | ||
|
||
resp, err := http.DefaultClient.Do(newReq) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to execute request") | ||
} | ||
defer resp.Body.Close() | ||
|
||
b, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to read") | ||
} | ||
|
||
config := &handlers.CurrentAppConfigResponse{} | ||
if err := json.Unmarshal(b, config); err != nil { | ||
return nil, errors.Wrap(err, "failed to unmarshal status") | ||
} | ||
|
||
if !config.Success { | ||
return nil, fmt.Errorf("failed to get config: %s", config.Error) | ||
} | ||
|
||
return config, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package cli | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/replicatedhq/kots/pkg/print" | ||
"github.com/replicatedhq/kots/pkg/snapshot" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func GetRestoresCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "restores", | ||
Aliases: []string{"restore"}, | ||
Short: "Get restores", | ||
Long: "", | ||
SilenceUsage: false, | ||
SilenceErrors: false, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
viper.BindPFlags(cmd.Flags()) | ||
}, | ||
RunE: getRestoresCmd, | ||
} | ||
|
||
cmd.Flags().StringP("output", "o", "", "output format. supported values: json") | ||
|
||
return cmd | ||
} | ||
|
||
func getRestoresCmd(cmd *cobra.Command, args []string) error { | ||
v := viper.GetViper() | ||
|
||
options := snapshot.ListInstanceRestoresOptions{ | ||
Namespace: v.GetString("namespace"), | ||
} | ||
restores, err := snapshot.ListInstanceRestores(cmd.Context(), options) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to list instance restores") | ||
} | ||
|
||
print.Restores(restores, v.GetString("output")) | ||
|
||
return nil | ||
} |
Oops, something went wrong.