github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/stack/kubernetes/stackclient.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"fmt"
     5  
     6  	composev1beta1 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta1"
     7  	composev1beta2 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta2"
     8  	"github.com/docker/cli/kubernetes/labels"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
    11  	"k8s.io/client-go/rest"
    12  )
    13  
    14  // StackClient talks to a kubernetes compose component.
    15  type StackClient interface {
    16  	StackConverter
    17  	CreateOrUpdate(s Stack) error
    18  	Delete(name string) error
    19  	Get(name string) (Stack, error)
    20  	List(opts metav1.ListOptions) ([]Stack, error)
    21  	IsColliding(servicesClient corev1.ServiceInterface, s Stack) error
    22  }
    23  
    24  // stackV1Beta1 implements stackClient interface and talks to compose component v1beta1.
    25  type stackV1Beta1 struct {
    26  	stackV1Beta1Converter
    27  	stacks composev1beta1.StackInterface
    28  }
    29  
    30  func newStackV1Beta1(config *rest.Config, namespace string) (*stackV1Beta1, error) {
    31  	client, err := composev1beta1.NewForConfig(config)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	return &stackV1Beta1{stacks: client.Stacks(namespace)}, nil
    36  }
    37  
    38  func (s *stackV1Beta1) CreateOrUpdate(internalStack Stack) error {
    39  	// If it already exists, update the stack
    40  	if stackBeta1, err := s.stacks.Get(internalStack.Name, metav1.GetOptions{}); err == nil {
    41  		stackBeta1.Spec.ComposeFile = internalStack.ComposeFile
    42  		_, err := s.stacks.Update(stackBeta1)
    43  		return err
    44  	}
    45  	// Or create it
    46  	_, err := s.stacks.Create(stackToV1beta1(internalStack))
    47  	return err
    48  }
    49  
    50  func (s *stackV1Beta1) Delete(name string) error {
    51  	return s.stacks.Delete(name, &metav1.DeleteOptions{})
    52  }
    53  
    54  func (s *stackV1Beta1) Get(name string) (Stack, error) {
    55  	stackBeta1, err := s.stacks.Get(name, metav1.GetOptions{})
    56  	if err != nil {
    57  		return Stack{}, err
    58  	}
    59  	return stackFromV1beta1(stackBeta1)
    60  }
    61  
    62  func (s *stackV1Beta1) List(opts metav1.ListOptions) ([]Stack, error) {
    63  	list, err := s.stacks.List(opts)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	stacks := make([]Stack, len(list.Items))
    68  	for i := range list.Items {
    69  		stack, err := stackFromV1beta1(&list.Items[i])
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  		stacks[i] = stack
    74  	}
    75  	return stacks, nil
    76  }
    77  
    78  // IsColliding verifies that services defined in the stack collides with already deployed services
    79  func (s *stackV1Beta1) IsColliding(servicesClient corev1.ServiceInterface, st Stack) error {
    80  	for _, srv := range st.getServices() {
    81  		if err := verify(servicesClient, st.Name, srv); err != nil {
    82  			return err
    83  		}
    84  	}
    85  	return nil
    86  }
    87  
    88  // verify checks whether the service is already present in kubernetes.
    89  // If we find the service by name but it doesn't have our label or it has a different value
    90  // than the stack name for the label, we fail (i.e. it will collide)
    91  func verify(services corev1.ServiceInterface, stackName string, service string) error {
    92  	svc, err := services.Get(service, metav1.GetOptions{})
    93  	if err == nil {
    94  		if key, ok := svc.ObjectMeta.Labels[labels.ForStackName]; ok {
    95  			if key != stackName {
    96  				return fmt.Errorf("service %s already present in stack named %s", service, key)
    97  			}
    98  			return nil
    99  		}
   100  		return fmt.Errorf("service %s already present in the cluster", service)
   101  	}
   102  	return nil
   103  }
   104  
   105  // stackV1Beta2 implements stackClient interface and talks to compose component v1beta2.
   106  type stackV1Beta2 struct {
   107  	stackV1Beta2Converter
   108  	stacks composev1beta2.StackInterface
   109  }
   110  
   111  func newStackV1Beta2(config *rest.Config, namespace string) (*stackV1Beta2, error) {
   112  	client, err := composev1beta2.NewForConfig(config)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	return &stackV1Beta2{stacks: client.Stacks(namespace)}, nil
   117  }
   118  
   119  func (s *stackV1Beta2) CreateOrUpdate(internalStack Stack) error {
   120  	// If it already exists, update the stack
   121  	if stackBeta2, err := s.stacks.Get(internalStack.Name, metav1.GetOptions{}); err == nil {
   122  		stackBeta2.Spec = internalStack.Spec
   123  		_, err := s.stacks.Update(stackBeta2)
   124  		return err
   125  	}
   126  	// Or create it
   127  	_, err := s.stacks.Create(stackToV1beta2(internalStack))
   128  	return err
   129  }
   130  
   131  func (s *stackV1Beta2) Delete(name string) error {
   132  	return s.stacks.Delete(name, &metav1.DeleteOptions{})
   133  }
   134  
   135  func (s *stackV1Beta2) Get(name string) (Stack, error) {
   136  	stackBeta2, err := s.stacks.Get(name, metav1.GetOptions{})
   137  	if err != nil {
   138  		return Stack{}, err
   139  	}
   140  	return stackFromV1beta2(stackBeta2), nil
   141  }
   142  
   143  func (s *stackV1Beta2) List(opts metav1.ListOptions) ([]Stack, error) {
   144  	list, err := s.stacks.List(opts)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	stacks := make([]Stack, len(list.Items))
   149  	for i := range list.Items {
   150  		stacks[i] = stackFromV1beta2(&list.Items[i])
   151  	}
   152  	return stacks, nil
   153  }
   154  
   155  // IsColliding is handle server side with the compose api v1beta2, so nothing to do here
   156  func (s *stackV1Beta2) IsColliding(servicesClient corev1.ServiceInterface, st Stack) error {
   157  	return nil
   158  }