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