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  }