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