github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/stack/kubernetes/services.go (about) 1 package kubernetes 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/cli/cli/command/formatter" 8 "github.com/docker/cli/cli/command/stack/options" 9 "github.com/docker/cli/kubernetes/labels" 10 "github.com/docker/docker/api/types/filters" 11 "github.com/docker/docker/api/types/swarm" 12 appsv1beta2 "k8s.io/api/apps/v1beta2" 13 corev1 "k8s.io/api/core/v1" 14 apierrs "k8s.io/apimachinery/pkg/api/errors" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 ) 17 18 var supportedServicesFilters = map[string]bool{ 19 "mode": true, 20 "name": true, 21 "label": true, 22 } 23 24 func generateSelector(labels map[string][]string) []string { 25 var result []string 26 for k, v := range labels { 27 for _, val := range v { 28 result = append(result, fmt.Sprintf("%s=%s", k, val)) 29 } 30 if len(v) == 0 { 31 result = append(result, k) 32 } 33 } 34 return result 35 } 36 37 func parseLabelFilters(rawFilters []string) map[string][]string { 38 labels := map[string][]string{} 39 for _, rawLabel := range rawFilters { 40 v := strings.SplitN(rawLabel, "=", 2) 41 key := v[0] 42 if len(v) > 1 { 43 labels[key] = append(labels[key], v[1]) 44 } else if _, ok := labels[key]; !ok { 45 labels[key] = []string{} 46 } 47 } 48 return labels 49 } 50 51 func generateLabelSelector(f filters.Args, stackName string) string { 52 selectors := append(generateSelector(parseLabelFilters(f.Get("label"))), labels.SelectorForStack(stackName)) 53 return strings.Join(selectors, ",") 54 } 55 56 func getResourcesForServiceList(dockerCli *KubeCli, filters filters.Args, labelSelector string) (*appsv1beta2.ReplicaSetList, *appsv1beta2.DaemonSetList, *corev1.ServiceList, error) { 57 client, err := dockerCli.composeClient() 58 if err != nil { 59 return nil, nil, nil, err 60 } 61 modes := filters.Get("mode") 62 replicas := &appsv1beta2.ReplicaSetList{} 63 if len(modes) == 0 || filters.ExactMatch("mode", "replicated") { 64 if replicas, err = client.ReplicaSets().List(metav1.ListOptions{LabelSelector: labelSelector}); err != nil { 65 return nil, nil, nil, err 66 } 67 } 68 daemons := &appsv1beta2.DaemonSetList{} 69 if len(modes) == 0 || filters.ExactMatch("mode", "global") { 70 if daemons, err = client.DaemonSets().List(metav1.ListOptions{LabelSelector: labelSelector}); err != nil { 71 return nil, nil, nil, err 72 } 73 } 74 services, err := client.Services().List(metav1.ListOptions{LabelSelector: labelSelector}) 75 if err != nil { 76 return nil, nil, nil, err 77 } 78 return replicas, daemons, services, nil 79 } 80 81 // RunServices is the kubernetes implementation of docker stack services 82 func RunServices(dockerCli *KubeCli, opts options.Services) error { 83 filters := opts.Filter.Value() 84 if err := filters.Validate(supportedServicesFilters); err != nil { 85 return err 86 } 87 client, err := dockerCli.composeClient() 88 if err != nil { 89 return nil 90 } 91 stacks, err := client.Stacks(false) 92 if err != nil { 93 return nil 94 } 95 stackName := opts.Namespace 96 _, err = stacks.Get(stackName) 97 if apierrs.IsNotFound(err) { 98 return fmt.Errorf("nothing found in stack: %s", stackName) 99 } 100 if err != nil { 101 return err 102 } 103 104 labelSelector := generateLabelSelector(filters, stackName) 105 replicasList, daemonsList, servicesList, err := getResourcesForServiceList(dockerCli, filters, labelSelector) 106 if err != nil { 107 return err 108 } 109 110 // Convert Replicas sets and kubernetes services to swarm services and formatter information 111 services, info, err := convertToServices(replicasList, daemonsList, servicesList) 112 if err != nil { 113 return err 114 } 115 services = filterServicesByName(services, filters.Get("name"), stackName) 116 117 if opts.Quiet { 118 info = map[string]formatter.ServiceListInfo{} 119 } 120 121 format := opts.Format 122 if len(format) == 0 { 123 if len(dockerCli.ConfigFile().ServicesFormat) > 0 && !opts.Quiet { 124 format = dockerCli.ConfigFile().ServicesFormat 125 } else { 126 format = formatter.TableFormatKey 127 } 128 } 129 130 servicesCtx := formatter.Context{ 131 Output: dockerCli.Out(), 132 Format: formatter.NewServiceListFormat(format, opts.Quiet), 133 } 134 return formatter.ServiceListWrite(servicesCtx, services, info) 135 } 136 137 func filterServicesByName(services []swarm.Service, names []string, stackName string) []swarm.Service { 138 if len(names) == 0 { 139 return services 140 } 141 prefix := stackName + "_" 142 // Accepts unprefixed service name (for compatibility with existing swarm scripts where service names are prefixed by stack names) 143 for i, n := range names { 144 if !strings.HasPrefix(n, prefix) { 145 names[i] = stackName + "_" + n 146 } 147 } 148 // Filter services 149 result := []swarm.Service{} 150 for _, s := range services { 151 for _, n := range names { 152 if strings.HasPrefix(s.Spec.Name, n) { 153 result = append(result, s) 154 } 155 } 156 } 157 return result 158 }