psu/cmd/stackList.go
2019-08-26 09:10:28 -04:00

136 lines
4.1 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"os"
"text/template"
"github.com/greenled/portainer-stack-utils/client"
portainer "github.com/portainer/portainer/api"
"github.com/sirupsen/logrus"
"github.com/greenled/portainer-stack-utils/common"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// stackListCmd represents the remove command
var stackListCmd = &cobra.Command{
Use: "list",
Short: "List stacks",
Aliases: []string{"ls"},
Example: ` Print stacks in endpoint with name=primary in a table format:
psu stack ls --endpoint primary
Print names of stacks in endpoint with name=primary:
psu stack ls --endpoint primary --format "{{ .Name }}"
Print environment variables of stacks in all endpoints:
psu stack ls --format "{{ .Name }}: {{ range .Env }}{{ .Name }}=\"{{ .Value }}\" {{ end }}"`,
Run: func(cmd *cobra.Command, args []string) {
portainerClient, err := common.GetClient()
common.CheckError(err)
endpoints, endpointsRetrievalErr := portainerClient.EndpointList()
common.CheckError(endpointsRetrievalErr)
var endpointSwarmClusterID string
var stacks []portainer.Stack
if endpointName := viper.GetString("stack.list.endpoint"); endpointName != "" {
// Get endpoint by name
endpoint, endpointRetrievalErr := common.GetEndpointFromListByName(endpoints, endpointName)
common.CheckError(endpointRetrievalErr)
logrus.WithFields(logrus.Fields{
"endpoint": endpoint.Name,
}).Debug("Getting endpoint's Docker info")
var selectionErr error
endpointSwarmClusterID, selectionErr = common.GetEndpointSwarmClusterID(endpoint.ID)
if selectionErr == nil {
// It's a swarm cluster
logrus.WithFields(logrus.Fields{
"endpoint": endpoint.Name,
}).Debug("Getting stacks")
stacks, err = portainerClient.StackList(client.StackListOptions{
Filter: client.StackListFilter{
SwarmID: endpointSwarmClusterID,
EndpointID: endpoint.ID,
},
})
common.CheckError(err)
} else if selectionErr == common.ErrStackClusterNotFound {
// It's not a swarm cluster
logrus.WithFields(logrus.Fields{
"endpoint": endpoint.Name,
}).Debug("Getting stacks")
stacks, err = portainerClient.StackList(client.StackListOptions{
Filter: client.StackListFilter{
EndpointID: endpoint.ID,
},
})
common.CheckError(err)
} else {
// Something else happened
common.CheckError(selectionErr)
}
} else {
logrus.Debug("Getting stacks")
stacks, err = portainerClient.StackList(client.StackListOptions{})
common.CheckError(err)
}
switch viper.GetString("stack.list.format") {
case "table":
// Print stacks in a table format
writer, err := common.NewTabWriter([]string{
"ID",
"NAME",
"TYPE",
"ENDPOINT",
})
common.CheckError(err)
for _, s := range stacks {
stackEndpoint, err := common.GetEndpointFromListByID(endpoints, s.EndpointID)
common.CheckError(err)
_, err = fmt.Fprintln(writer, fmt.Sprintf(
"%v\t%s\t%v\t%s",
s.ID,
s.Name,
client.GetTranslatedStackType(s.Type),
stackEndpoint.Name,
))
common.CheckError(err)
}
flushErr := writer.Flush()
common.CheckError(flushErr)
case "json":
// Print stacks in a json format
stacksJSONBytes, err := json.Marshal(stacks)
common.CheckError(err)
fmt.Println(string(stacksJSONBytes))
default:
// Print stacks in a custom format
template, templateParsingErr := template.New("stackTpl").Parse(viper.GetString("stack.list.format"))
common.CheckError(templateParsingErr)
for _, s := range stacks {
templateExecutionErr := template.Execute(os.Stdout, s)
common.CheckError(templateExecutionErr)
fmt.Println()
}
}
},
}
func init() {
stackCmd.AddCommand(stackListCmd)
stackListCmd.Flags().String("endpoint", "", "Filter by endpoint name.")
stackListCmd.Flags().String("format", "table", `Output format. Can be "table", "json" or a Go template.`)
viper.BindPFlag("stack.list.endpoint", stackListCmd.Flags().Lookup("endpoint"))
viper.BindPFlag("stack.list.format", stackListCmd.Flags().Lookup("format"))
stackListCmd.SetUsageTemplate(stackListCmd.UsageTemplate() + common.GetFormatHelp(portainer.Stack{}))
}