github.com/docker/compose-on-kubernetes@v0.5.0/internal/e2e/cluster/types.go (about)

     1  package cluster
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  
     9  	composev1alpha3 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1alpha3"
    10  	composev1beta1 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta1"
    11  	composev1beta2 "github.com/docker/compose-on-kubernetes/api/client/clientset/typed/compose/v1beta2"
    12  	"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
    13  	"github.com/docker/compose-on-kubernetes/api/compose/v1beta1"
    14  	"github.com/docker/compose-on-kubernetes/api/compose/v1beta2"
    15  	"github.com/docker/compose-on-kubernetes/internal/conversions"
    16  	"github.com/docker/compose-on-kubernetes/internal/parsing"
    17  	"github.com/docker/compose-on-kubernetes/internal/patch"
    18  	"github.com/pkg/errors"
    19  	appsv1 "k8s.io/api/apps/v1"
    20  	apiv1 "k8s.io/api/core/v1"
    21  	storagetypes "k8s.io/api/storage/v1"
    22  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	apitypes "k8s.io/apimachinery/pkg/types"
    25  	"k8s.io/apimachinery/pkg/util/wait"
    26  	typesappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
    27  	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
    28  	storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1"
    29  	"k8s.io/client-go/rest"
    30  )
    31  
    32  // Namespace is a test dedicated namespace
    33  type Namespace struct {
    34  	name              string
    35  	stackRESTv1beta2  rest.Interface
    36  	stackRESTv1alpha3 rest.Interface
    37  	stacks            composev1beta2.StackInterface
    38  	stacksv1alpha3    composev1alpha3.StackInterface
    39  	stacks1           composev1beta1.StackInterface
    40  	pods              corev1.PodInterface
    41  	deployments       typesappsv1.DeploymentInterface
    42  	services          corev1.ServiceInterface
    43  	nodes             corev1.NodeInterface
    44  	servicesSupplier  func() *rest.Request
    45  	storageClasses    storagev1.StorageClassInterface
    46  	configMaps        corev1.ConfigMapInterface
    47  	secrets           corev1.SecretInterface
    48  	config            *rest.Config
    49  }
    50  
    51  // StackOperationStrategy is the strategy for a stack create/update
    52  type StackOperationStrategy int
    53  
    54  const (
    55  	//StackOperationV1beta1 will use v1beta1 API
    56  	StackOperationV1beta1 StackOperationStrategy = iota
    57  	//StackOperationV1beta2Compose will use v1beta2 composefile subresource
    58  	StackOperationV1beta2Compose
    59  	//StackOperationV1beta2Stack will use v1beta2 structured stack
    60  	StackOperationV1beta2Stack
    61  	//StackOperationV1alpha3 will use a v1alpha3 structured stack
    62  	StackOperationV1alpha3
    63  )
    64  
    65  // PodPredicate returns true when a predicate is verified on a pod and an optional message indicating why the predicate is false
    66  type PodPredicate func(pod apiv1.Pod) (bool, string)
    67  
    68  func newNamespace(config *rest.Config, namespace string) (*Namespace, error) {
    69  	composeClientSet, err := composev1beta2.NewForConfig(config)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	composeClientSet1, err := composev1beta1.NewForConfig(config)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	composeClientSetv1alpha3, err := composev1alpha3.NewForConfig(config)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	coreClientSet, err := corev1.NewForConfig(config)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	storageClientSet, err := storagev1.NewForConfig(config)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	appsClientSet, err := typesappsv1.NewForConfig(config)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	return &Namespace{
    97  		name:              namespace,
    98  		stackRESTv1beta2:  composeClientSet.RESTClient(),
    99  		stackRESTv1alpha3: composeClientSetv1alpha3.RESTClient(),
   100  		stacks:            composeClientSet.Stacks(namespace),
   101  		stacks1:           composeClientSet1.Stacks(namespace),
   102  		stacksv1alpha3:    composeClientSetv1alpha3.Stacks(namespace),
   103  		pods:              coreClientSet.Pods(namespace),
   104  		deployments:       appsClientSet.Deployments(namespace),
   105  		services:          coreClientSet.Services(namespace),
   106  		nodes:             coreClientSet.Nodes(),
   107  		storageClasses:    storageClientSet.StorageClasses(),
   108  		servicesSupplier: func() *rest.Request {
   109  			return coreClientSet.RESTClient().Get().Resource("services").Namespace(namespace)
   110  		},
   111  		secrets:    coreClientSet.Secrets(namespace),
   112  		configMaps: coreClientSet.ConfigMaps(namespace),
   113  		config:     config,
   114  	}, nil
   115  }
   116  
   117  // HasStorageClass returns true if cluster has at least one StorageClass defined
   118  func (ns *Namespace) HasStorageClass() (bool, error) {
   119  	storageClasses, err := ns.storageClasses.List(metav1.ListOptions{})
   120  	if err != nil {
   121  		return false, err
   122  	}
   123  	sc := defaultStorageClass(storageClasses.Items)
   124  	if sc == nil || sc.Provisioner == "kubernetes.io/host-path" {
   125  		return false, nil
   126  	}
   127  	return true, nil
   128  }
   129  
   130  func defaultStorageClass(classes []storagetypes.StorageClass) *storagetypes.StorageClass {
   131  	for _, c := range classes {
   132  		if c.Annotations != nil && c.Annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true" {
   133  			return &c
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  // RESTClientV1beta2 returns a RESTClient for the stacks
   140  func (ns *Namespace) RESTClientV1beta2() rest.Interface {
   141  	return ns.stackRESTv1beta2
   142  }
   143  
   144  // RESTClientV1alpha3 returns a RESTClient for the stacks
   145  func (ns *Namespace) RESTClientV1alpha3() rest.Interface {
   146  	return ns.stackRESTv1alpha3
   147  }
   148  
   149  // Name returns the name of the namespace.
   150  func (ns *Namespace) Name() string {
   151  	return ns.name
   152  }
   153  
   154  // Deployments returns a DeploymentInterface
   155  func (ns *Namespace) Deployments() typesappsv1.DeploymentInterface {
   156  	return ns.deployments
   157  }
   158  
   159  // Pods returns a PodInterface
   160  func (ns *Namespace) Pods() corev1.PodInterface {
   161  	return ns.pods
   162  }
   163  
   164  // StacksV1beta1 returns a v1beta1 client
   165  func (ns *Namespace) StacksV1beta1() composev1beta1.StackInterface {
   166  	return ns.stacks1
   167  }
   168  
   169  // StacksV1alpha3 returns a v1alpha3 client
   170  func (ns *Namespace) StacksV1alpha3() composev1alpha3.StackInterface {
   171  	return ns.stacksv1alpha3
   172  }
   173  
   174  // CreatePullSecret creates a pull secret
   175  func (ns *Namespace) CreatePullSecret(name, server, username, password string) error {
   176  	data, err := generatePullSecretData(server, username, password)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	s := &apiv1.Secret{
   181  		ObjectMeta: metav1.ObjectMeta{
   182  			Namespace: ns.name,
   183  			Name:      name,
   184  		},
   185  		Type: apiv1.SecretTypeDockerConfigJson,
   186  		Data: map[string][]byte{
   187  			apiv1.DockerConfigJsonKey: data,
   188  		},
   189  	}
   190  	_, err = ns.Secrets().Create(s)
   191  	return err
   192  }
   193  
   194  func generatePullSecretData(server, username, password string) ([]byte, error) {
   195  	e := dockerConfigEntry{
   196  		Username: username,
   197  		Password: password,
   198  		Auth:     base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password))),
   199  	}
   200  	cfg := dockerConfigJSON{
   201  		Auths: map[string]dockerConfigEntry{
   202  			server: e,
   203  		},
   204  	}
   205  	return json.Marshal(&cfg)
   206  }
   207  
   208  type dockerConfigJSON struct {
   209  	Auths map[string]dockerConfigEntry `json:"auths"`
   210  }
   211  type dockerConfigEntry struct {
   212  	Username string `json:"username,omitempty"`
   213  	Password string `json:"password,omitempty"`
   214  	Email    string `json:"email,omitempty"`
   215  	Auth     string `json:"auth,omitempty"`
   216  }
   217  
   218  // CreateStack creates a stack.
   219  func (ns *Namespace) CreateStack(strategy StackOperationStrategy, name, composeFile string) (*v1alpha3.Stack, error) {
   220  	switch strategy {
   221  	case StackOperationV1beta2Compose:
   222  		compose := &v1beta2.ComposeFile{
   223  			ObjectMeta: metav1.ObjectMeta{
   224  				Name: name,
   225  			},
   226  			ComposeFile: composeFile,
   227  		}
   228  		return nil, ns.stackRESTv1beta2.Post().Namespace(ns.name).Name(name).Resource("stacks").SubResource("composefile").Body(compose).Do().Error()
   229  	case StackOperationV1beta2Stack:
   230  		var stack *v1beta2.Stack
   231  		var err error
   232  		config, err := parsing.LoadStackData([]byte(composeFile), map[string]string{})
   233  		if err != nil {
   234  			return nil, err
   235  		}
   236  		stack = &v1beta2.Stack{
   237  			ObjectMeta: metav1.ObjectMeta{
   238  				Name: name,
   239  			},
   240  			Spec: &v1beta2.StackSpec{},
   241  		}
   242  		spec := conversions.FromComposeConfig(config)
   243  		if err := v1alpha3.Convert_v1alpha3_StackSpec_To_v1beta2_StackSpec(spec, stack.Spec, nil); err != nil {
   244  			return nil, err
   245  		}
   246  		res, err := ns.stacks.Create(stack)
   247  		if err != nil {
   248  			return nil, err
   249  		}
   250  		var aslatest v1alpha3.Stack
   251  		err = v1alpha3.Convert_v1beta2_Stack_To_v1alpha3_Stack(res, &aslatest, nil)
   252  		return &aslatest, err
   253  	case StackOperationV1alpha3:
   254  		var stack *v1alpha3.Stack
   255  		var err error
   256  		config, err := parsing.LoadStackData([]byte(composeFile), map[string]string{})
   257  		if err != nil {
   258  			return nil, err
   259  		}
   260  		stack = &v1alpha3.Stack{
   261  			ObjectMeta: metav1.ObjectMeta{
   262  				Name: name,
   263  			},
   264  			Spec: conversions.FromComposeConfig(config),
   265  		}
   266  		return ns.stacksv1alpha3.Create(stack)
   267  	case StackOperationV1beta1:
   268  		stack := &v1beta1.Stack{
   269  			ObjectMeta: metav1.ObjectMeta{
   270  				Name: name,
   271  			},
   272  			Spec: v1beta1.StackSpec{
   273  				ComposeFile: composeFile,
   274  			},
   275  		}
   276  		_, err := ns.stacks1.Create(stack)
   277  		return nil, err
   278  	}
   279  	return nil, nil
   280  }
   281  
   282  // DeleteStacks deletes all stacks.
   283  func (ns *Namespace) DeleteStacks() error {
   284  	return ns.stacks.DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{})
   285  }
   286  
   287  // DeleteStack deletes a stack.
   288  func (ns *Namespace) DeleteStack(name string) error {
   289  	return ns.stacks.Delete(name, &metav1.DeleteOptions{})
   290  }
   291  
   292  // DeleteStackWithPropagation deletes a stack using the specified propagation.
   293  func (ns *Namespace) DeleteStackWithPropagation(name string, propagation metav1.DeletionPropagation) error {
   294  	return ns.stacks.Delete(name, &metav1.DeleteOptions{PropagationPolicy: &propagation})
   295  }
   296  
   297  // DeleteStacksv1 deletes all stacks.
   298  func (ns *Namespace) DeleteStacksv1() error {
   299  	return ns.stacks1.DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{})
   300  }
   301  
   302  // DeleteStackv1 deletes a stack.
   303  func (ns *Namespace) DeleteStackv1(name string) error {
   304  	return ns.stacks1.Delete(name, &metav1.DeleteOptions{})
   305  }
   306  
   307  // UpdateStack updates a stack.
   308  func (ns *Namespace) UpdateStack(strategy StackOperationStrategy, name, composeFile string) (*v1alpha3.Stack, error) {
   309  	switch strategy {
   310  	case StackOperationV1beta2Compose:
   311  		compose := &v1beta2.ComposeFile{
   312  			ObjectMeta: metav1.ObjectMeta{
   313  				Name: name,
   314  			},
   315  			ComposeFile: composeFile,
   316  		}
   317  		return nil, ns.stackRESTv1beta2.Put().Namespace(ns.name).Name(name).Resource("stacks").SubResource("composefile").Body(compose).Do().Error()
   318  	case StackOperationV1alpha3:
   319  		p := patch.New()
   320  		config, err := parsing.LoadStackData([]byte(composeFile), map[string]string{})
   321  		if err != nil {
   322  			return nil, err
   323  		}
   324  		newStack := &v1alpha3.Stack{
   325  			ObjectMeta: metav1.ObjectMeta{
   326  				Name: name,
   327  			},
   328  			Spec: conversions.FromComposeConfig(config),
   329  		}
   330  		if err != nil {
   331  			return nil, err
   332  		}
   333  		p = p.Replace("/spec", newStack.Spec)
   334  
   335  		buf, err := p.ToJSON()
   336  		if err != nil {
   337  			return nil, err
   338  		}
   339  		return ns.stacksv1alpha3.Patch(name, apitypes.JSONPatchType, buf)
   340  	case StackOperationV1beta2Stack:
   341  		p := patch.New()
   342  		config, err := parsing.LoadStackData([]byte(composeFile), map[string]string{})
   343  		if err != nil {
   344  			return nil, err
   345  		}
   346  		newStack := &v1beta2.Stack{
   347  			ObjectMeta: metav1.ObjectMeta{
   348  				Name: name,
   349  			},
   350  			Spec: &v1beta2.StackSpec{},
   351  		}
   352  		spec := conversions.FromComposeConfig(config)
   353  		if err := v1alpha3.Convert_v1alpha3_StackSpec_To_v1beta2_StackSpec(spec, newStack.Spec, nil); err != nil {
   354  			return nil, err
   355  		}
   356  		if err != nil {
   357  			return nil, err
   358  		}
   359  		p = p.Replace("/spec", newStack.Spec)
   360  
   361  		buf, err := p.ToJSON()
   362  		if err != nil {
   363  			return nil, err
   364  		}
   365  		res, err := ns.stacks.Patch(name, apitypes.JSONPatchType, buf)
   366  		if err != nil {
   367  			return nil, err
   368  		}
   369  		var aslatest v1alpha3.Stack
   370  		err = v1alpha3.Convert_v1beta2_Stack_To_v1alpha3_Stack(res, &aslatest, nil)
   371  		return &aslatest, err
   372  	case StackOperationV1beta1:
   373  		p := patch.New()
   374  		p = p.Replace("/spec/composeFile", composeFile)
   375  		buf, err := p.ToJSON()
   376  		if err != nil {
   377  			return nil, err
   378  		}
   379  		_, err = ns.stacks1.Patch(name, apitypes.JSONPatchType, buf)
   380  		return nil, err
   381  	}
   382  	return nil, nil
   383  }
   384  
   385  // UpdateStackFromSpec updates a stack from a Spec.
   386  func (ns *Namespace) UpdateStackFromSpec(name string, newStack *v1alpha3.Stack) (*v1alpha3.Stack, error) {
   387  	filtered := &v1alpha3.Stack{
   388  		Spec: newStack.Spec,
   389  	}
   390  	buf, err := json.Marshal(filtered)
   391  	if err != nil {
   392  		return nil, errors.Wrap(err, "stack marshaling error")
   393  	}
   394  	return ns.stacksv1alpha3.Patch(name, apitypes.MergePatchType, buf)
   395  }
   396  
   397  // GetStack gets a stack.
   398  func (ns *Namespace) GetStack(name string) (*v1alpha3.Stack, error) {
   399  	return ns.stacksv1alpha3.Get(name, metav1.GetOptions{})
   400  }
   401  
   402  // ListStacks lists the stacks.
   403  func (ns *Namespace) ListStacks() ([]v1alpha3.Stack, error) {
   404  	stacks, err := ns.stacksv1alpha3.List(metav1.ListOptions{})
   405  	if err != nil {
   406  		return nil, err
   407  	}
   408  
   409  	return stacks.Items, nil
   410  }
   411  
   412  // ContainsZeroStack is a poller that checks that no stack is created.
   413  func (ns *Namespace) ContainsZeroStack() wait.ConditionFunc {
   414  	return ns.ContainsNStacks(0)
   415  }
   416  
   417  // ContainsNStacks is a poller that checks how many stacks are created.
   418  func (ns *Namespace) ContainsNStacks(count int) wait.ConditionFunc {
   419  	return func() (bool, error) {
   420  		stacks, err := ns.ListStacks()
   421  		if err != nil {
   422  			return false, err
   423  		}
   424  
   425  		if len(stacks) != count {
   426  			return false, nil
   427  		}
   428  
   429  		return true, nil
   430  	}
   431  }
   432  
   433  // ContainsZeroPod is a poller that checks that no pod is created.
   434  func (ns *Namespace) ContainsZeroPod() wait.ConditionFunc {
   435  	return ns.ContainsNPods(0)
   436  }
   437  
   438  // ContainsNPods is a poller that checks how many pods are created.
   439  func (ns *Namespace) ContainsNPods(count int) wait.ConditionFunc {
   440  	return ns.ContainsNPodsMatchingSelector(count, "")
   441  }
   442  
   443  // PodIsActuallyRemoved is a poller that checks that a pod has been terminated
   444  func (ns *Namespace) PodIsActuallyRemoved(name string) wait.ConditionFunc {
   445  	return func() (bool, error) {
   446  		_, err := ns.pods.Get(name, metav1.GetOptions{})
   447  		if kerrors.IsNotFound(err) {
   448  			return true, nil
   449  		}
   450  		return false, err
   451  	}
   452  }
   453  
   454  // ContainsNPodsMatchingSelector is a poller that checks how many pods are created for given label selector.
   455  func (ns *Namespace) ContainsNPodsMatchingSelector(count int, labelSelector string) wait.ConditionFunc {
   456  	return func() (bool, error) {
   457  		pods, err := ns.ListPods(labelSelector)
   458  		if err != nil {
   459  			return false, err
   460  		}
   461  
   462  		if len(pods) != count {
   463  			return false, nil
   464  		}
   465  
   466  		return true, nil
   467  	}
   468  }
   469  
   470  // ContainsNPodsWithPredicate is a poller that checks how many pods matching the predicate are created.
   471  func (ns *Namespace) ContainsNPodsWithPredicate(count int, labelSelector string, predicate PodPredicate) wait.ConditionFunc {
   472  	return func() (bool, error) {
   473  		pods, err := ns.ListPods(labelSelector)
   474  		if err != nil {
   475  			return false, err
   476  		}
   477  
   478  		if len(pods) != count {
   479  			return false, nil
   480  		}
   481  
   482  		for _, pod := range pods {
   483  			if ok, _ := predicate(pod); !ok {
   484  				return false, nil
   485  			}
   486  		}
   487  
   488  		return true, nil
   489  	}
   490  }
   491  
   492  // IsStackAvailable is a poller that checks is a given stack is available.
   493  func (ns *Namespace) IsStackAvailable(name string) wait.ConditionFunc {
   494  	return func() (bool, error) {
   495  		stack, err := ns.GetStack(name)
   496  		if err != nil {
   497  			return false, err
   498  		}
   499  
   500  		if stack.Status == nil || stack.Status.Phase != v1alpha3.StackAvailable {
   501  			return false, nil
   502  		}
   503  
   504  		return true, nil
   505  	}
   506  }
   507  
   508  // IsStackFailed is a poller that checks if a given stack has failed with the correct error.
   509  func (ns *Namespace) IsStackFailed(name string, errorSubstr string) wait.ConditionFunc {
   510  	return func() (bool, error) {
   511  		stack, err := ns.GetStack(name)
   512  		if err != nil {
   513  			return false, err
   514  		}
   515  
   516  		if stack.Status == nil || stack.Status.Phase != v1alpha3.StackFailure {
   517  			return false, nil
   518  		}
   519  
   520  		if !strings.Contains(stack.Status.Message, errorSubstr) {
   521  			return false, fmt.Errorf("status message is %q. expected to contain %q", stack.Status.Message, errorSubstr)
   522  		}
   523  
   524  		return true, nil
   525  	}
   526  }
   527  
   528  // IsServicePresent is a poller that checks if a service is present.
   529  func (ns *Namespace) IsServicePresent(labelSelector string) wait.ConditionFunc {
   530  	return func() (bool, error) {
   531  		services, err := ns.services.List(metav1.ListOptions{
   532  			LabelSelector: labelSelector,
   533  		})
   534  		if err != nil {
   535  			return false, err
   536  		}
   537  
   538  		if len(services.Items) == 0 {
   539  			return false, nil
   540  		}
   541  
   542  		return true, nil
   543  	}
   544  }
   545  
   546  // ServiceCount is a poller that checks a number of services to be present.
   547  func (ns *Namespace) ServiceCount(labelSelector string, count int) wait.ConditionFunc {
   548  	return func() (bool, error) {
   549  		services, err := ns.services.List(metav1.ListOptions{
   550  			LabelSelector: labelSelector,
   551  		})
   552  		if err != nil {
   553  			return false, err
   554  		}
   555  
   556  		if len(services.Items) != count {
   557  			return false, nil
   558  		}
   559  
   560  		return true, nil
   561  	}
   562  }
   563  
   564  // IsServiceNotPresent is a poller that checks if a service is not present.
   565  func (ns *Namespace) IsServiceNotPresent(labelSelector string) wait.ConditionFunc {
   566  	return func() (bool, error) {
   567  		services, err := ns.services.List(metav1.ListOptions{
   568  			LabelSelector: labelSelector,
   569  		})
   570  		if err != nil {
   571  			return false, err
   572  		}
   573  
   574  		if len(services.Items) > 0 {
   575  			return false, nil
   576  		}
   577  
   578  		return true, nil
   579  	}
   580  }
   581  
   582  // IsServiceResponding is a poller that checks is responding with the expected
   583  // content text.
   584  func (ns *Namespace) IsServiceResponding(service string, url string, expectedText string) wait.ConditionFunc {
   585  	return func() (bool, error) {
   586  		resp, err := ns.servicesSupplier().
   587  			Name(service).
   588  			SubResource(strings.Split(url, "/")...).
   589  			DoRaw()
   590  		if err != nil {
   591  			return false, nil
   592  		}
   593  
   594  		if !strings.Contains(string(resp), expectedText) {
   595  			return false, nil
   596  		}
   597  
   598  		return true, nil
   599  	}
   600  }
   601  
   602  // ListPods lists the pods that match a given selector.
   603  func (ns *Namespace) ListPods(labelSelector string) ([]apiv1.Pod, error) {
   604  	pods, err := ns.pods.List(metav1.ListOptions{
   605  		LabelSelector: labelSelector,
   606  	})
   607  	if err != nil {
   608  		return nil, err
   609  	}
   610  
   611  	return pods.Items, nil
   612  }
   613  
   614  // ListAllPods lists all pods in the namespace.
   615  func (ns *Namespace) ListAllPods() ([]apiv1.Pod, error) {
   616  	return ns.ListPods("")
   617  }
   618  
   619  // ListDeployments lists the deployments that match a given selector.
   620  func (ns *Namespace) ListDeployments(labelSelector string) ([]appsv1.Deployment, error) {
   621  	deployments, err := ns.deployments.List(metav1.ListOptions{
   622  		LabelSelector: labelSelector,
   623  	})
   624  	if err != nil {
   625  		return nil, err
   626  	}
   627  
   628  	return deployments.Items, nil
   629  }
   630  
   631  // ListServices lists the services that match a given selector.
   632  func (ns *Namespace) ListServices(labelSelector string) ([]apiv1.Service, error) {
   633  	services, err := ns.services.List(metav1.ListOptions{
   634  		LabelSelector: labelSelector,
   635  	})
   636  	if err != nil {
   637  		return nil, err
   638  	}
   639  
   640  	return services.Items, nil
   641  }
   642  
   643  // ListNodes lists the nodes available in the cluster.
   644  func (ns *Namespace) ListNodes() ([]apiv1.Node, error) {
   645  	nodes, err := ns.nodes.List(metav1.ListOptions{})
   646  	if err != nil {
   647  		return nil, err
   648  	}
   649  	return nodes.Items, nil
   650  }
   651  
   652  // ConfigMaps returns a ConfigMaps client for the namespace
   653  func (ns *Namespace) ConfigMaps() corev1.ConfigMapInterface {
   654  	return ns.configMaps
   655  }
   656  
   657  // Secrets returns a Secrets client for the namespace
   658  func (ns *Namespace) Secrets() corev1.SecretInterface {
   659  	return ns.secrets
   660  }
   661  
   662  // Services returns a Services client for the namespace
   663  func (ns *Namespace) Services() corev1.ServiceInterface {
   664  	return ns.services
   665  }
   666  
   667  // As returns the same namespace with an impersonated config
   668  func (ns *Namespace) As(user rest.ImpersonationConfig) (*Namespace, error) {
   669  	cfg := *ns.config
   670  	cfg.Impersonate = user
   671  	return newNamespace(&cfg, ns.name)
   672  }