diff --git a/cmd/deactivate.go b/cmd/deactivate.go index fe733cb..cd60be6 100644 --- a/cmd/deactivate.go +++ b/cmd/deactivate.go @@ -25,7 +25,7 @@ import ( // deactivateCmd represents the deactivate command var deactivateCmd = &cobra.Command{ Args: cobra.MinimumNArgs(1), - Use: "deactivate collection-name", + Use: "deactivate stack-name version", Short: "Remove the specified collection from the list of available application types, without deleting it from the Kabanero instance.", Long: ` Run the deactivate command to remove the specified collection from the list of available application types, without deleting it from the Kabanero instance. @@ -34,15 +34,18 @@ This command is useful in a case where you have cloned a collection and customiz RunE: func(cmd *cobra.Command, args []string) error { // fmt.Println("deactivate called") collectionName := args[0] - url := getRESTEndpoint("v1/collections/" + collectionName) + version := args[1] + url := getRESTEndpoint("v1/stacks/" + collectionName + "/versions/" + version) resp, err := sendHTTPRequest("DELETE", url, nil) if err != nil { + Debug.log("deactivate: Error on sendHTTPRequest:") return err } data := make(map[string]interface{}) err = json.NewDecoder(resp.Body).Decode(&data) if err != nil { + Debug.log("deactivate: Error on Decode:") return err } deactivateResponse := data["status"] diff --git a/cmd/list.go b/cmd/list.go index 6f4fd32..6c11f27 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -18,7 +18,7 @@ package cmd import ( "encoding/json" "fmt" - "net/http" + // "net/http" "os" "strings" "text/tabwriter" @@ -26,49 +26,65 @@ import ( "github.com/spf13/cobra" ) -// CollStruct : Each collection contains following information to be displayed -type CollStruct struct { - Name string - Version string - Status string - DesiredState string +// The list command gets a set of "stacks" back from the CLI Service. +// There are 2 distinct structs for the returned stacks: +// - KabStruct represents the JSON returned for the Kabanero stacks. +// - CommonStackStruct represents the JSON returned for all the other stacks. +type KabStruct struct { + Name string + Status []StatusStruct `json:"status"` +} +type StatusStruct struct { + Version string + Status string +} + +type CommonStackStruct struct { + Name string + Versions []VersionStruct `json:"versions"` } -// CollectionsResponse : all the collections -type CollectionsResponse struct { - NewColl []CollStruct `json:"new curated collections"` - ActivateColl []CollStruct `json:"activate collections"` - KabColl []CollStruct `json:"kabanero collections"` - ObsoleteColl []CollStruct `json:"obsolete collections"` - CuratedColl []CollStruct `json:"curated collections"` - VChangeColl []CollStruct `json:"version change collections"` +type VersionStruct struct { + Version string + Images []string `json:"image"` } -// KabCollectionsHeader for all references to what we call the "Kab Collections" -var KabCollectionsHeader = "Kabanero Instance Collections" +// StacksResponse : all the stacks +type StacksResponse struct { + NewStack []CommonStackStruct `json:"new curated stacks"` + ActivateStack []CommonStackStruct `json:"activate stacks"` + KabStack []KabStruct `json:"kabanero stacks"` + ObsoleteStack []CommonStackStruct `json:"obsolete stacks"` + CuratedStack []CommonStackStruct `json:"curated stacks"` +} + +// KabStacksHeader for all references to what we call the "Kab stacks" +var KabStacksHeader = "Kabanero Instance Stacks " -// GHCollectionsHeader for all references to the "curated collections" -var GHCollectionsHeader = "GitHub Curated Collections" +// GHStacksHeader for all references to the "curated stacks" +var GHStacksHeader = "GitHub Curated Stacks" // listCmd represents the list command var listCmd = &cobra.Command{ Use: "list ", - Short: "List all the collections in the kabanero instance, and their status", - Long: `List all the collections in the kabanero instance, and their status. - Modifications to the curated collection may be slow to replicate in git hub and therefore may not be reflected immediately in KABANERO LIST or SYNC display output`, + Short: "List all the stacks in the kabanero instance, and their status", + Long: `List all the stacks in the kabanero instance, and their status. + Modifications to the curated stack may be slow to replicate in git hub and therefore may not be reflected immediately in KABANERO LIST or SYNC display output`, RunE: func(cmd *cobra.Command, args []string) error { - url := getRESTEndpoint("v1/collections") + Debug.log("List called...") + url := getRESTEndpoint("v1/stacks") resp, err := sendHTTPRequest("GET", url, nil) if err != nil { + Debug.log("list: Error on sendHTTPRequest:") return err } - - Debug.log("RESPONSE ", url, resp.StatusCode, http.StatusText(resp.StatusCode)) + // cannot reference resp here. May not be fully formed and cause nil pointer deref: Debug.log("RESPONSE ", url, resp.StatusCode, http.StatusText(resp.StatusCode)) //Decode the response into data decoder := json.NewDecoder(resp.Body) - var data CollectionsResponse + var data StacksResponse err = decoder.Decode(&data) if err != nil { + Debug.log("list: Error on Decode:") return err } @@ -76,34 +92,45 @@ var listCmd = &cobra.Command{ tWriter := new(tabwriter.Writer) tWriter.Init(os.Stdout, 0, 8, 0, '\t', 0) - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", KabCollectionsHeader, "Version", "Status") - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", strings.Repeat("-", len(KabCollectionsHeader)), "-------", "------") + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", KabStacksHeader, "Version", "Status") + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", strings.Repeat("-", len(KabStacksHeader)), "-------", "------") - for i := 0; i < len(data.KabColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.KabColl[i].Name, data.KabColl[i].Version, data.KabColl[i].Status) + for i := 0; i < len(data.KabStack); i++ { + for j := 0; j < len(data.KabStack[i].Status); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.KabStack[i].Name, data.KabStack[i].Status[j].Version, data.KabStack[i].Status[j].Status) + } } - for i := 0; i < len(data.ObsoleteColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ObsoleteColl[i].Name, data.ObsoleteColl[i].Version, "obsolete") + for i := 0; i < len(data.ObsoleteStack); i++ { + for j := 0; j < len(data.ObsoleteStack[i].Versions); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ObsoleteStack[i].Name, data.ObsoleteStack[i].Versions[j].Version, "obsolete") + } } - fmt.Fprintln(tWriter) - tWriter.Flush() - // put new collections into a map to compare to curated - mNewColl := make(map[string]string) - for i := 0; i < len(data.NewColl); i++ { - mNewColl[data.NewColl[i].Name] = data.NewColl[i].Name + " *" + // put new stacks name/version into a map to compare to curated. + mNewStack := make(map[string]string) + for i := 0; i < len(data.NewStack); i++ { + for j := 0; j < len(data.NewStack[i].Versions); j++ { + mNewStack[data.NewStack[i].Name] = data.NewStack[i].Name + data.NewStack[i].Versions[j].Version + } } - fmt.Fprintf(tWriter, "\n%s\t%s", GHCollectionsHeader, "Version") - fmt.Fprintf(tWriter, "\n%s\t%s", strings.Repeat("-", len(GHCollectionsHeader)), "-------") - for i := 0; i < len(data.CuratedColl); i++ { - name := data.CuratedColl[i].Name - if nameStarred, found := mNewColl[name]; found { - fmt.Fprintf(tWriter, "\n%s\t%s", nameStarred, data.CuratedColl[i].Version) - } else { - fmt.Fprintf(tWriter, "\n%s\t%s", name, data.CuratedColl[i].Version) + fmt.Fprintf(tWriter, "\n%s\t%s", GHStacksHeader, "Version") + fmt.Fprintf(tWriter, "\n%s\t%s", strings.Repeat("-", len(GHStacksHeader)), "-------") + for i := 0; i < len(data.CuratedStack); i++ { + name := data.CuratedStack[i].Name + for j := 0; j < len(data.CuratedStack[i].Versions); j++ { + version := data.CuratedStack[i].Versions[j].Version + nameAndVersion := name + version + + //fmt.Fprintf(tWriter, "\n%s", name) + _, found := mNewStack[nameAndVersion] + if found { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", name, version, "new") + } else { + fmt.Fprintf(tWriter, "\n%s\t%s", name, version) + } } } fmt.Fprintln(tWriter) diff --git a/cmd/login.go b/cmd/login.go index 94576e9..086d016 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -95,6 +95,7 @@ var loginCmd = &cobra.Command{ resp, err := sendHTTPRequest("POST", kabLoginURL, requestBody) if err != nil { + Debug.log("login: Error on sendHTTPRequest:") return err } diff --git a/cmd/root.go b/cmd/root.go index 6efe275..3b60688 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,8 +1,5 @@ package cmd -//import collections "github.com/kabanero-command-line/kab-cli/kabanero/collections/cmd" -//import access "github.com/kabanero-command-line/kab-cli/kabanero/onboard/cmd" - import ( "flag" "fmt" @@ -14,8 +11,6 @@ import ( // for logging "k8s.io/klog" - // homedir "github.com/mitchellh/go-homedir" - "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -29,9 +24,9 @@ var ( APIVersionV1 = "v1" //dryrun bool verbose bool + verboseHTTP bool klogInitialized = false KabURLKey = "KABURL" - KabURLContext = "KabCollections-1.0-SNAPSHOT" ) func homeDir() string { @@ -46,7 +41,7 @@ func homeDir() string { var rootCmd = &cobra.Command{ Use: "kabanero", Short: "This repo defines a command line interface used by the enterprise, solution, or application architect who defines and manages the kabanero collections that are used by developers to create governed applications for their business.", - Long: `**kabanero** is a command line interface for managing the collections in a Kabanero + Long: `**kabanero** is a command line interface for managing the stacks in a Kabanero environment, as well as to on-board the people that will use the environment to build applications. @@ -69,7 +64,12 @@ func init() { // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kabanero.yaml)") // Added for logging rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Turns on debug output and logging to a file in $HOME/.kabanero/logs") - + rootCmd.PersistentFlags().BoolVarP(&verboseHTTP, "debug http", "x", false, "Turns on debug output for http request/responses") + err := rootCmd.PersistentFlags().MarkHidden("debug http") + if err != nil { + fmt.Fprintln(os.Stdout, "err with MarkHidden") + } + //rootCmd.Execute() // not implemented: rootCmd.PersistentFlags().BoolVar(&dryrun, "dryrun", false, "Turns on dry run mode") // The subbcommand processor for commands to manage the apphub diff --git a/cmd/sync.go b/cmd/sync.go index fef5928..510543c 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "net/http" + "net/http/httputil" "os" "strings" "text/tabwriter" @@ -66,6 +67,15 @@ func sendHTTPRequest(method string, url string, jsonBody []byte) (*http.Response return resp, errors.New("Login to your kabanero instance") } } + + if verboseHTTP { + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + fmt.Println(err) + } + Info.log("requestDump: " + string(requestDump)) + } + resp, err = client.Do(req) if err != nil { return resp, errors.New(err.Error()) @@ -84,16 +94,25 @@ func sendHTTPRequest(method string, url string, jsonBody []byte) (*http.Response if resp.StatusCode == 401 { return nil, errors.New("Your session may have expired or the credentials entered may be invalid") } - if resp.StatusCode == 539 { + if resp.StatusCode == 539 || resp.StatusCode == 424 || resp.StatusCode == 500 { message := make(map[string]interface{}) err = json.NewDecoder(resp.Body).Decode(&message) if err != nil { + Debug.log("sync: Decode error for 500/539/424") return nil, err } - fmt.Println(message["message"].(string)) - return nil, nil + fmt.Println("HTTP Status " + string(resp.StatusCode) + ": " + message["message"].(string)) + return resp, errors.New("Invalid Response") } - Debug.log("RESPONSE ", url, resp.StatusCode, http.StatusText(resp.StatusCode)) + + if verboseHTTP { + responseDump, err := httputil.DumpResponse(resp, true) + if err != nil { + fmt.Println(err) + } + Info.log("responseDump: " + string(responseDump)) + } + Debug.log("RESPONSE ", url, " ", resp.StatusCode, " ", http.StatusText(resp.StatusCode)) return resp, nil } @@ -106,48 +125,56 @@ var syncCmd = &cobra.Command{ Modifications to the curated collection may be slow to replicate in git hub and therefore may not be reflected immediately in KABANERO LIST or SYNC display output `, RunE: func(cmd *cobra.Command, args []string) error { - url := getRESTEndpoint("v1/collections") + url := getRESTEndpoint("v1/stacks") resp, err := sendHTTPRequest("PUT", url, nil) if err != nil { + Debug.log("sync: Error on sendHTTPRequest:") return errors.New(err.Error()) } Debug.log("RESPONSE ", url, resp.StatusCode, http.StatusText(resp.StatusCode)) defer resp.Body.Close() //Decode the response into data decoder := json.NewDecoder(resp.Body) - var data CollectionsResponse + var data StacksResponse err = decoder.Decode(&data) if err != nil { + Debug.log("sync: Error on Decode:") return err } Debug.log(data) tWriter := new(tabwriter.Writer) tWriter.Init(os.Stdout, 0, 8, 0, '\t', 0) - if len(data.NewColl) == 0 && (len(data.KabColl) == 0) && len(data.ObsoleteColl) == 0 && len(data.CuratedColl) == 0 && len(data.VChangeColl) == 0 && len(data.ActivateColl) == 0 { - syncedOutput := KabCollectionsHeader + " is already synchronized with the " + GHCollectionsHeader + if len(data.NewStack) == 0 && (len(data.KabStack) == 0) && len(data.ObsoleteStack) == 0 && len(data.CuratedStack) == 0 && len(data.ActivateStack) == 0 { + syncedOutput := KabStacksHeader + " is already synchronized with the " + GHStacksHeader fmt.Println(strings.ToLower(syncedOutput)) } else { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", KabCollectionsHeader, "Version", "Status") - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", strings.Repeat("-", len(KabCollectionsHeader)), "-------", "------") - for i := 0; i < len(data.NewColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.NewColl[i].Name, data.NewColl[i].Version, "added to kabanero") - } - for i := 0; i < len(data.ActivateColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ActivateColl[i].Name, data.ActivateColl[i].Version, "inactive ==> active") + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", KabStacksHeader, "Version", "Status") + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", strings.Repeat("-", len(KabStacksHeader)), "-------", "------") + + for i := 0; i < len(data.NewStack); i++ { + for j := 0; j < len(data.NewStack[i].Versions); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.NewStack[i].Name, data.NewStack[i].Versions[j].Version, "added to Kabanero") + } } - for i := 0; i < len(data.KabColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.KabColl[i].Name, data.KabColl[i].Version, data.KabColl[i].Status) + for i := 0; i < len(data.ActivateStack); i++ { + for j := 0; j < len(data.ActivateStack[i].Versions); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ActivateStack[i].Name, data.ActivateStack[i].Versions[j].Version, "inactive ==> active") + } } - for i := 0; i < len(data.ObsoleteColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ObsoleteColl[i].Name, data.ObsoleteColl[i].Version, "deactivated") + for i := 0; i < len(data.KabStack); i++ { + for j := 0; j < len(data.KabStack[i].Status); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.KabStack[i].Name, data.KabStack[i].Status[j].Version, data.KabStack[i].Status[j].Status) + } } - for i := 0; i < len(data.VChangeColl); i++ { - fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.VChangeColl[i].Name, data.VChangeColl[i].Version, "version changed") + for i := 0; i < len(data.ObsoleteStack); i++ { + for j := 0; j < len(data.ObsoleteStack[i].Versions); j++ { + fmt.Fprintf(tWriter, "\n%s\t%s\t%s", data.ObsoleteStack[i].Name, data.ObsoleteStack[i].Versions[j].Version, "deactivated") + } } + fmt.Fprintln(tWriter) tWriter.Flush() - } return nil }, diff --git a/vendor/github.com/spf13/viper/go.mod b/vendor/github.com/spf13/viper/go.mod index 86e801c..439d2d8 100644 --- a/vendor/github.com/spf13/viper/go.mod +++ b/vendor/github.com/spf13/viper/go.mod @@ -22,3 +22,5 @@ require ( golang.org/x/text v0.3.0 // indirect gopkg.in/yaml.v2 v2.2.2 ) + +go 1.13