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  }