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  }