package stack import ( "context" "errors" "fmt" "strings" "unicode" abraClient "coopcloud.tech/abra/client" "coopcloud.tech/abra/client/convert" "github.com/docker/cli/opts" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" ) type StackStatus struct { Services []swarm.Service Err error } func getStackFilter(namespace string) filters.Args { filter := filters.NewArgs() filter.Add("label", convert.LabelNamespace+"="+namespace) return filter } func getStackServiceFilter(namespace string) filters.Args { return getStackFilter(namespace) } func getStackFilterFromOpt(namespace string, opt opts.FilterOpt) filters.Args { filter := opt.Value() filter.Add("label", convert.LabelNamespace+"="+namespace) return filter } func getAllStacksFilter() filters.Args { filter := filters.NewArgs() filter.Add("label", convert.LabelNamespace) return filter } func getStackServices(ctx context.Context, apiclient client.APIClient, namespace string) ([]swarm.Service, error) { return apiclient.ServiceList(ctx, types.ServiceListOptions{Filters: getStackServiceFilter(namespace)}) } func GetAllDeployedServices(contextName string) StackStatus { cl, err := abraClient.NewClientWithContext(contextName) if err != nil { if strings.Contains(err.Error(), "does not exist") { // No local context found, bail out gracefully return StackStatus{[]swarm.Service{}, nil} } return StackStatus{[]swarm.Service{}, err} } ctx := context.Background() services, err := cl.ServiceList(ctx, types.ServiceListOptions{Filters: getAllStacksFilter()}) if err != nil { return StackStatus{[]swarm.Service{}, err} } return StackStatus{services, nil} } func checkDaemonIsSwarmManager(contextName string) error { cl, err := abraClient.NewClientWithContext(contextName) if err != nil { return err } info, err := cl.Info(context.Background()) if err != nil { return err } if !info.Swarm.ControlAvailable { return errors.New("this server is not a swarm manager. Did you run \"abra server init\"?") } return nil } // validateStackName checks if the provided string is a valid stack name (namespace). // It currently only does a rudimentary check if the string is empty, or consists // of only whitespace and quoting characters. func validateStackName(namespace string) error { v := strings.TrimFunc(namespace, quotesOrWhitespace) if v == "" { return fmt.Errorf("invalid stack name: %q", namespace) } return nil } func quotesOrWhitespace(r rune) bool { return unicode.IsSpace(r) || r == '"' || r == '\'' } func DeployStack(namespace string) { } // TODO: Prune services from stack func pruneServices() error { return nil }