"Fossies" - the Fresh Open Source Software Archive

Member "istio-1.6.5/pkg/test/kube/accessor.go" (8 Jul 2020, 25118 Bytes) of package /linux/misc/istio-1.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "accessor.go": 1.5.4_vs_1.6.0.

    1 //  Copyright 2018 Istio Authors
    2 //
    3 //  Licensed under the Apache License, Version 2.0 (the "License");
    4 //  you may not use this file except in compliance with the License.
    5 //  You may obtain a copy of the License at
    6 //
    7 //      http://www.apache.org/licenses/LICENSE-2.0
    8 //
    9 //  Unless required by applicable law or agreed to in writing, software
   10 //  distributed under the License is distributed on an "AS IS" BASIS,
   11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12 //  See the License for the specific language governing permissions and
   13 //  limitations under the License.
   14 
   15 package kube
   16 
   17 import (
   18     "context"
   19     "fmt"
   20     "strings"
   21     "time"
   22 
   23     multierror "github.com/hashicorp/go-multierror"
   24     "k8s.io/apimachinery/pkg/version"
   25 
   26     istioKube "istio.io/istio/pkg/kube"
   27     "istio.io/istio/pkg/test/scopes"
   28     "istio.io/istio/pkg/test/util/retry"
   29 
   30     kubeApiAdmissions "k8s.io/api/admissionregistration/v1beta1"
   31     appsv1 "k8s.io/api/apps/v1"
   32     "k8s.io/api/autoscaling/v2beta1"
   33     kubeApiCore "k8s.io/api/core/v1"
   34     "k8s.io/api/policy/v1beta1"
   35     v1 "k8s.io/api/rbac/v1"
   36     kubeApiExt "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
   37     kubeExtClient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
   38     "k8s.io/apimachinery/pkg/api/errors"
   39     kubeApiMeta "k8s.io/apimachinery/pkg/apis/meta/v1"
   40     "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
   41     "k8s.io/apimachinery/pkg/runtime/schema"
   42     "k8s.io/apimachinery/pkg/runtime/serializer"
   43     "k8s.io/client-go/dynamic"
   44     kubeClient "k8s.io/client-go/kubernetes"
   45     "k8s.io/client-go/kubernetes/scheme"
   46     kubeClientCore "k8s.io/client-go/kubernetes/typed/core/v1"
   47     _ "k8s.io/client-go/plugin/pkg/client/auth" // Needed for auth
   48     "k8s.io/client-go/rest"
   49 )
   50 
   51 const (
   52     workDirPrefix = "istio-kube-accessor-"
   53 )
   54 
   55 var (
   56     defaultRetryTimeout = retry.Timeout(time.Minute * 10)
   57     defaultRetryDelay   = retry.Delay(time.Second * 1)
   58 )
   59 
   60 // Accessor is a helper for accessing Kubernetes programmatically. It bundles some of the high-level
   61 // operations that is frequently used by the test framework.
   62 type Accessor struct {
   63     restConfig *rest.Config
   64     ctl        *kubectl
   65     set        *kubeClient.Clientset
   66     extSet     *kubeExtClient.Clientset
   67     dynClient  dynamic.Interface
   68 }
   69 
   70 // NewAccessor returns a new instance of an accessor.
   71 func NewAccessor(kubeConfig string, baseWorkDir string) (*Accessor, error) {
   72     restConfig, err := istioKube.BuildClientConfig(kubeConfig, "")
   73     if err != nil {
   74         return nil, fmt.Errorf("failed to create rest config. %v", err)
   75     }
   76     restConfig.APIPath = "/api"
   77     restConfig.GroupVersion = &kubeApiCore.SchemeGroupVersion
   78     restConfig.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: scheme.Codecs}
   79 
   80     set, err := kubeClient.NewForConfig(restConfig)
   81     if err != nil {
   82         return nil, err
   83     }
   84 
   85     extSet, err := kubeExtClient.NewForConfig(restConfig)
   86     if err != nil {
   87         return nil, err
   88     }
   89 
   90     dynClient, err := dynamic.NewForConfig(restConfig)
   91     if err != nil {
   92         return nil, fmt.Errorf("failed to create dynamic client: %v", err)
   93     }
   94 
   95     return &Accessor{
   96         restConfig: restConfig,
   97         ctl: &kubectl{
   98             kubeConfig: kubeConfig,
   99             baseDir:    baseWorkDir,
  100         },
  101         set:       set,
  102         extSet:    extSet,
  103         dynClient: dynClient,
  104     }, nil
  105 }
  106 
  107 // NewPortForwarder creates a new port forwarder.
  108 func (a *Accessor) NewPortForwarder(pod kubeApiCore.Pod, localPort, remotePort uint16) (PortForwarder, error) {
  109     return newPortForwarder(a.restConfig, pod, localPort, remotePort)
  110 }
  111 
  112 // GetPods returns pods in the given namespace, based on the selectors. If no selectors are given, then
  113 // all pods are returned.
  114 func (a *Accessor) GetPods(namespace string, selectors ...string) ([]kubeApiCore.Pod, error) {
  115     s := strings.Join(selectors, ",")
  116     list, err := a.set.CoreV1().Pods(namespace).List(context.TODO(), kubeApiMeta.ListOptions{LabelSelector: s})
  117 
  118     if err != nil {
  119         return []kubeApiCore.Pod{}, err
  120     }
  121 
  122     return list.Items, nil
  123 }
  124 
  125 func (a *Accessor) GetDeployments(namespace string, selectors ...string) ([]appsv1.Deployment, error) {
  126     s := strings.Join(selectors, ",")
  127     list, err := a.set.AppsV1().Deployments(namespace).List(context.TODO(), kubeApiMeta.ListOptions{LabelSelector: s})
  128 
  129     if err != nil {
  130         return []appsv1.Deployment{}, err
  131     }
  132 
  133     return list.Items, nil
  134 }
  135 
  136 // GetEvents returns events in the given namespace, based on the involvedObject.
  137 func (a *Accessor) GetEvents(namespace string, involvedObject string) ([]kubeApiCore.Event, error) {
  138     s := "involvedObject.name=" + involvedObject
  139     list, err := a.set.CoreV1().Events(namespace).List(context.TODO(), kubeApiMeta.ListOptions{FieldSelector: s})
  140 
  141     if err != nil {
  142         return []kubeApiCore.Event{}, err
  143     }
  144 
  145     return list.Items, nil
  146 }
  147 
  148 // GetPod returns the pod with the given namespace and name.
  149 func (a *Accessor) GetPod(namespace, name string) (kubeApiCore.Pod, error) {
  150     v, err := a.set.CoreV1().
  151         Pods(namespace).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  152     if err != nil {
  153         return kubeApiCore.Pod{}, err
  154     }
  155     return *v, nil
  156 }
  157 
  158 // DeletePod deletes the given pod.
  159 func (a *Accessor) DeletePod(namespace, name string) error {
  160     return a.set.CoreV1().Pods(namespace).Delete(context.TODO(), name, kubeApiMeta.DeleteOptions{})
  161 }
  162 
  163 // FindPodBySelectors returns the first matching pod, given a namespace and a set of selectors.
  164 func (a *Accessor) FindPodBySelectors(namespace string, selectors ...string) (kubeApiCore.Pod, error) {
  165     list, err := a.GetPods(namespace, selectors...)
  166     if err != nil {
  167         return kubeApiCore.Pod{}, err
  168     }
  169 
  170     if len(list) == 0 {
  171         return kubeApiCore.Pod{}, fmt.Errorf("no matching pod found for selectors: %v", selectors)
  172     }
  173 
  174     if len(list) > 1 {
  175         scopes.Framework.Warnf("More than one pod found matching selectors: %v", selectors)
  176     }
  177 
  178     return list[0], nil
  179 }
  180 
  181 // PodFetchFunc fetches pods from the Accessor.
  182 type PodFetchFunc func() ([]kubeApiCore.Pod, error)
  183 
  184 // NewPodFetch creates a new PodFetchFunction that fetches all pods matching the namespace and label selectors.
  185 func (a *Accessor) NewPodFetch(namespace string, selectors ...string) PodFetchFunc {
  186     return func() ([]kubeApiCore.Pod, error) {
  187         return a.GetPods(namespace, selectors...)
  188     }
  189 }
  190 
  191 // NewSinglePodFetch creates a new PodFetchFunction that fetches a single pod matching the given label selectors.
  192 func (a *Accessor) NewSinglePodFetch(namespace string, selectors ...string) PodFetchFunc {
  193     return func() ([]kubeApiCore.Pod, error) {
  194         pod, err := a.FindPodBySelectors(namespace, selectors...)
  195         if err != nil {
  196             return nil, err
  197         }
  198         return []kubeApiCore.Pod{pod}, nil
  199     }
  200 }
  201 
  202 // WaitUntilPodsAreReady waits until the pod with the name/namespace is in ready state.
  203 func (a *Accessor) WaitUntilPodsAreReady(fetchFunc PodFetchFunc, opts ...retry.Option) ([]kubeApiCore.Pod, error) {
  204     var pods []kubeApiCore.Pod
  205     _, err := retry.Do(func() (interface{}, bool, error) {
  206 
  207         scopes.CI.Infof("Checking pods ready...")
  208 
  209         fetched, err := a.CheckPodsAreReady(fetchFunc)
  210         if err != nil {
  211             return nil, false, err
  212         }
  213         pods = fetched
  214         return nil, true, nil
  215     }, newRetryOptions(opts...)...)
  216 
  217     return pods, err
  218 }
  219 
  220 // CheckPodsAreReady checks whether the pods that are selected by the given function is in ready state or not.
  221 func (a *Accessor) CheckPodsAreReady(fetchFunc PodFetchFunc) ([]kubeApiCore.Pod, error) {
  222     scopes.CI.Infof("Checking pods ready...")
  223 
  224     fetched, err := fetchFunc()
  225     if err != nil {
  226         scopes.CI.Infof("Failed retrieving pods: %v", err)
  227         return nil, err
  228     }
  229 
  230     for i, p := range fetched {
  231         msg := "Ready"
  232         if e := CheckPodReady(&p); e != nil {
  233             msg = e.Error()
  234             err = multierror.Append(err, fmt.Errorf("%s/%s: %s", p.Namespace, p.Name, msg))
  235         }
  236         scopes.CI.Infof("  [%2d] %45s %15s (%v)", i, p.Name, p.Status.Phase, msg)
  237     }
  238 
  239     if err != nil {
  240         return nil, err
  241     }
  242 
  243     return fetched, nil
  244 }
  245 
  246 // WaitUntilPodsAreDeleted waits until the pod with the name/namespace no longer exist.
  247 func (a *Accessor) WaitUntilPodsAreDeleted(fetchFunc PodFetchFunc, opts ...retry.Option) error {
  248     _, err := retry.Do(func() (interface{}, bool, error) {
  249 
  250         pods, err := fetchFunc()
  251         if err != nil {
  252             scopes.CI.Infof("Failed retrieving pods: %v", err)
  253             return nil, false, err
  254         }
  255 
  256         if len(pods) == 0 {
  257             // All pods have been deleted.
  258             return nil, true, nil
  259         }
  260 
  261         return nil, false, fmt.Errorf("failed waiting to delete pod %s/%s", pods[0].Namespace, pods[0].Name)
  262     }, newRetryOptions(opts...)...)
  263 
  264     return err
  265 }
  266 
  267 // DeleteDeployment deletes the given deployment.
  268 func (a *Accessor) DeleteDeployment(ns string, name string) error {
  269     return a.set.AppsV1().Deployments(ns).Delete(context.TODO(), name, *deleteOptionsForeground())
  270 }
  271 
  272 // WaitUntilDeploymentIsReady waits until the deployment with the name/namespace is in ready state.
  273 func (a *Accessor) WaitUntilDeploymentIsReady(ns string, name string, opts ...retry.Option) error {
  274     _, err := retry.Do(func() (interface{}, bool, error) {
  275 
  276         deployment, err := a.set.AppsV1().Deployments(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  277         if err != nil {
  278             if !errors.IsNotFound(err) {
  279                 return nil, true, err
  280             }
  281         }
  282 
  283         ready := deployment.Status.ReadyReplicas == deployment.Status.UnavailableReplicas+deployment.Status.AvailableReplicas
  284 
  285         return nil, ready, nil
  286     }, newRetryOptions(opts...)...)
  287 
  288     return err
  289 }
  290 
  291 // WaitUntilDaemonSetIsReady waits until the deployment with the name/namespace is in ready state.
  292 func (a *Accessor) WaitUntilDaemonSetIsReady(ns string, name string, opts ...retry.Option) error {
  293     _, err := retry.Do(func() (interface{}, bool, error) {
  294 
  295         daemonSet, err := a.set.AppsV1().DaemonSets(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  296         if err != nil {
  297             if !errors.IsNotFound(err) {
  298                 return nil, true, err
  299             }
  300         }
  301 
  302         ready := daemonSet.Status.NumberReady == daemonSet.Status.DesiredNumberScheduled
  303 
  304         return nil, ready, nil
  305     }, newRetryOptions(opts...)...)
  306 
  307     return err
  308 }
  309 
  310 // WaitUntilServiceEndpointsAreReady will wait until the service with the given name/namespace is present, and have at least
  311 // one usable endpoint.
  312 func (a *Accessor) WaitUntilServiceEndpointsAreReady(ns string, name string, opts ...retry.Option) (*kubeApiCore.Service, *kubeApiCore.Endpoints, error) {
  313     var service *kubeApiCore.Service
  314     var endpoints *kubeApiCore.Endpoints
  315     err := retry.UntilSuccess(func() error {
  316 
  317         s, err := a.GetService(ns, name)
  318         if err != nil {
  319             return err
  320         }
  321 
  322         eps, err := a.GetEndpoints(ns, name, kubeApiMeta.GetOptions{})
  323         if err != nil {
  324             return err
  325         }
  326         if len(eps.Subsets) == 0 {
  327             return fmt.Errorf("%s/%v endpoint not ready: no subsets", ns, name)
  328         }
  329 
  330         for _, subset := range eps.Subsets {
  331             if len(subset.Addresses) > 0 && len(subset.NotReadyAddresses) == 0 {
  332                 service = s
  333                 endpoints = eps
  334                 return nil
  335             }
  336         }
  337         return fmt.Errorf("%s/%v endpoint not ready: no ready addresses", ns, name)
  338     }, newRetryOptions(opts...)...)
  339 
  340     if err != nil {
  341         return nil, nil, err
  342     }
  343 
  344     return service, endpoints, nil
  345 }
  346 
  347 // DeleteMutatingWebhook deletes the mutating webhook with the given name.
  348 func (a *Accessor) DeleteMutatingWebhook(name string) error {
  349     return a.set.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(context.TODO(), name, *deleteOptionsForeground())
  350 }
  351 
  352 // DeleteValidatingWebhook deletes the validating webhook with the given name.
  353 func (a *Accessor) DeleteValidatingWebhook(name string) error {
  354     return a.set.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Delete(context.TODO(), name, *deleteOptionsForeground())
  355 }
  356 
  357 // WaitForValidatingWebhookDeletion waits for the validating webhook with the given name to be garbage collected by kubernetes.
  358 func (a *Accessor) WaitForValidatingWebhookDeletion(name string, opts ...retry.Option) error {
  359     _, err := retry.Do(func() (interface{}, bool, error) {
  360         if a.ValidatingWebhookConfigurationExists(name) {
  361             return nil, false, fmt.Errorf("validating webhook not deleted: %s", name)
  362         }
  363 
  364         // It no longer exists ... success.
  365         return nil, true, nil
  366     }, newRetryOptions(opts...)...)
  367 
  368     return err
  369 }
  370 
  371 // ValidatingWebhookConfigurationExists indicates whether a validating webhook with the given name exists.
  372 func (a *Accessor) ValidatingWebhookConfigurationExists(name string) bool {
  373     _, err := a.set.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  374     return err == nil
  375 }
  376 
  377 // MutatingWebhookConfigurationExists indicates whether a mutating webhook with the given name exists.
  378 func (a *Accessor) MutatingWebhookConfigurationExists(name string) bool {
  379     _, err := a.set.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  380     return err == nil
  381 }
  382 
  383 // GetValidatingWebhookConfiguration returns the specified ValidatingWebhookConfiguration.
  384 func (a *Accessor) GetValidatingWebhookConfiguration(name string) (*kubeApiAdmissions.ValidatingWebhookConfiguration, error) {
  385     whc, err := a.set.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  386     if err != nil {
  387         return nil, fmt.Errorf("could not get validating webhook config: %s", name)
  388     }
  389     return whc, nil
  390 }
  391 
  392 // UpdateValidatingWebhookConfiguration updates the specified ValidatingWebhookConfiguration.
  393 func (a *Accessor) UpdateValidatingWebhookConfiguration(config *kubeApiAdmissions.ValidatingWebhookConfiguration) error {
  394     if _, err := a.set.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations().Update(context.TODO(), config, kubeApiMeta.UpdateOptions{}); err != nil {
  395         return fmt.Errorf("could not update validating webhook config: %s", config.Name)
  396     }
  397     return nil
  398 }
  399 
  400 // GetCustomResourceDefinitions gets the CRDs
  401 func (a *Accessor) GetCustomResourceDefinitions() ([]kubeApiExt.CustomResourceDefinition, error) {
  402     crd, err := a.extSet.ApiextensionsV1beta1().CustomResourceDefinitions().List(context.TODO(), kubeApiMeta.ListOptions{})
  403     if err != nil {
  404         return nil, err
  405     }
  406     return crd.Items, nil
  407 }
  408 
  409 // GetCustomResourceDefinition gets the CRD with the given name
  410 func (a *Accessor) GetCustomResourceDefinition(name string) (*kubeApiExt.CustomResourceDefinition, error) {
  411     return a.extSet.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  412 }
  413 
  414 // DeleteCustomResourceDefinitions deletes the CRD with the given name.
  415 func (a *Accessor) DeleteCustomResourceDefinitions(name string) error {
  416     return a.extSet.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(context.TODO(), name, *deleteOptionsForeground())
  417 }
  418 
  419 // GetPodDisruptionBudget gets the PodDisruptionBudget with the given name
  420 func (a *Accessor) GetPodDisruptionBudget(ns, name string) (*v1beta1.PodDisruptionBudget, error) {
  421     return a.set.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  422 }
  423 
  424 // GetHorizontalPodAutoscaler gets the HorizontalPodAutoscaler with the given name
  425 func (a *Accessor) GetHorizontalPodAutoscaler(ns, name string) (*v2beta1.HorizontalPodAutoscaler, error) {
  426     return a.set.AutoscalingV2beta1().HorizontalPodAutoscalers(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  427 }
  428 
  429 // GetService returns the service entry with the given name/namespace.
  430 func (a *Accessor) GetService(ns string, name string) (*kubeApiCore.Service, error) {
  431     return a.set.CoreV1().Services(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  432 }
  433 
  434 // GetDeployment returns the deployment with the given name/namespace.
  435 func (a *Accessor) GetDeployment(ns string, name string) (*appsv1.Deployment, error) {
  436     return a.set.AppsV1().Deployments(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  437 }
  438 
  439 // GetSecret returns secret resource with the given namespace.
  440 func (a *Accessor) GetSecret(ns string) kubeClientCore.SecretInterface {
  441     return a.set.CoreV1().Secrets(ns)
  442 }
  443 
  444 // GetConfigMap returns the config resource with the given name and namespace.
  445 func (a *Accessor) GetConfigMap(name, ns string) (*kubeApiCore.ConfigMap, error) {
  446     return a.set.CoreV1().ConfigMaps(ns).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  447 }
  448 
  449 // DeleteConfigMap deletes the config resource with the given name and namespace.
  450 func (a *Accessor) DeleteConfigMap(name, ns string) error {
  451     return a.set.CoreV1().ConfigMaps(ns).Delete(context.TODO(), name, kubeApiMeta.DeleteOptions{})
  452 }
  453 
  454 // CreateSecret takes the representation of a secret and creates it in the given namespace.
  455 // Returns an error if there is any.
  456 func (a *Accessor) CreateSecret(namespace string, secret *kubeApiCore.Secret) (err error) {
  457     _, err = a.set.CoreV1().Secrets(namespace).Create(context.TODO(), secret, kubeApiMeta.CreateOptions{})
  458     return err
  459 }
  460 
  461 // DeleteSecret deletes secret by name in namespace.
  462 func (a *Accessor) DeleteSecret(namespace, name string) (err error) {
  463     var immediate int64
  464     err = a.set.CoreV1().Secrets(namespace).Delete(context.TODO(), name, kubeApiMeta.DeleteOptions{GracePeriodSeconds: &immediate})
  465     return err
  466 }
  467 
  468 func (a *Accessor) GetServiceAccount(namespace, name string) (*kubeApiCore.ServiceAccount, error) {
  469     return a.set.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  470 }
  471 
  472 // GetKubernetesVersion returns the Kubernetes server version
  473 func (a *Accessor) GetKubernetesVersion() (*version.Info, error) {
  474     return a.extSet.ServerVersion()
  475 }
  476 
  477 // GetEndpoints returns the endpoints for the given service.
  478 func (a *Accessor) GetEndpoints(ns, service string, options kubeApiMeta.GetOptions) (*kubeApiCore.Endpoints, error) {
  479     return a.set.CoreV1().Endpoints(ns).Get(context.TODO(), service, options)
  480 }
  481 
  482 // CreateNamespace with the given name. Also adds an "istio-testing" annotation.
  483 func (a *Accessor) CreateNamespace(ns string, istioTestingAnnotation string) error {
  484     scopes.Framework.Debugf("Creating namespace: %s", ns)
  485 
  486     n := a.newNamespace(ns, istioTestingAnnotation)
  487 
  488     _, err := a.set.CoreV1().Namespaces().Create(context.TODO(), &n, kubeApiMeta.CreateOptions{})
  489     return err
  490 }
  491 
  492 // CreateNamespaceWithLabels with the specified name, sidecar-injection behavior, and labels
  493 func (a *Accessor) CreateNamespaceWithLabels(ns string, istioTestingAnnotation string, labels map[string]string) error {
  494     scopes.Framework.Debugf("Creating namespace %s ns with labels %v", ns, labels)
  495 
  496     n := a.newNamespaceWithLabels(ns, istioTestingAnnotation, labels)
  497     _, err := a.set.CoreV1().Namespaces().Create(context.TODO(), &n, kubeApiMeta.CreateOptions{})
  498     return err
  499 }
  500 
  501 func (a *Accessor) newNamespace(ns string, istioTestingAnnotation string) kubeApiCore.Namespace {
  502     n := a.newNamespaceWithLabels(ns, istioTestingAnnotation, make(map[string]string))
  503     return n
  504 }
  505 
  506 func (a *Accessor) newNamespaceWithLabels(ns string, istioTestingAnnotation string, labels map[string]string) kubeApiCore.Namespace {
  507     n := kubeApiCore.Namespace{
  508         ObjectMeta: kubeApiMeta.ObjectMeta{
  509             Name:   ns,
  510             Labels: labels,
  511         },
  512     }
  513     if istioTestingAnnotation != "" {
  514         n.ObjectMeta.Labels["istio-testing"] = istioTestingAnnotation
  515     }
  516     return n
  517 }
  518 
  519 // NamespaceExists returns true if the given namespace exists.
  520 func (a *Accessor) NamespaceExists(ns string) bool {
  521     allNs, err := a.set.CoreV1().Namespaces().List(context.TODO(), kubeApiMeta.ListOptions{})
  522     if err != nil {
  523         return false
  524     }
  525     for _, n := range allNs.Items {
  526         if n.Name == ns {
  527             return true
  528         }
  529     }
  530     return false
  531 }
  532 
  533 // DeleteNamespace with the given name
  534 func (a *Accessor) DeleteNamespace(ns string) error {
  535     scopes.Framework.Debugf("Deleting namespace: %s", ns)
  536     return a.set.CoreV1().Namespaces().Delete(context.TODO(), ns, *deleteOptionsForeground())
  537 }
  538 
  539 // WaitForNamespaceDeletion waits until a namespace is deleted.
  540 func (a *Accessor) WaitForNamespaceDeletion(ns string, opts ...retry.Option) error {
  541     _, err := retry.Do(func() (interface{}, bool, error) {
  542         _, err2 := a.set.CoreV1().Namespaces().Get(context.TODO(), ns, kubeApiMeta.GetOptions{})
  543         if err2 == nil {
  544             return nil, false, nil
  545         }
  546 
  547         if errors.IsNotFound(err2) {
  548             return nil, true, nil
  549         }
  550 
  551         return nil, false, err2
  552     }, newRetryOptions(opts...)...)
  553 
  554     return err
  555 }
  556 
  557 // GetNamespace returns the K8s namespaceresource with the given name.
  558 func (a *Accessor) GetNamespace(ns string) (*kubeApiCore.Namespace, error) {
  559     n, err := a.set.CoreV1().Namespaces().Get(context.TODO(), ns, kubeApiMeta.GetOptions{})
  560     if err != nil {
  561         return nil, err
  562     }
  563 
  564     return n, nil
  565 }
  566 
  567 // DeleteClusterRole deletes a ClusterRole with the given name
  568 func (a *Accessor) DeleteClusterRole(role string) error {
  569     scopes.Framework.Debugf("Deleting ClusterRole: %s", role)
  570     return a.set.RbacV1().ClusterRoles().Delete(context.TODO(), role, *deleteOptionsForeground())
  571 }
  572 
  573 // GetClusterRole gets a ClusterRole with the given name
  574 func (a *Accessor) GetClusterRole(role string) (*v1.ClusterRole, error) {
  575     return a.set.RbacV1().ClusterRoles().Get(context.TODO(), role, kubeApiMeta.GetOptions{})
  576 }
  577 
  578 // GetClusterRoleBinding gets a ClusterRoleBinding with the given name
  579 func (a *Accessor) GetClusterRoleBinding(role string) (*v1.ClusterRoleBinding, error) {
  580     return a.set.RbacV1().ClusterRoleBindings().Get(context.TODO(), role, kubeApiMeta.GetOptions{})
  581 }
  582 
  583 // GetUnstructured returns an unstructured k8s resource object based on the provided schema, namespace, and name.
  584 func (a *Accessor) GetUnstructured(gvr schema.GroupVersionResource, namespace, name string) (*unstructured.Unstructured, error) {
  585     u, err := a.dynClient.Resource(gvr).Namespace(namespace).Get(context.TODO(), name, kubeApiMeta.GetOptions{})
  586     if err != nil {
  587         return nil, fmt.Errorf("failed to get resource %v of type %v: %v", name, gvr, err)
  588     }
  589 
  590     return u, nil
  591 }
  592 
  593 // DeleteUnstructured deletes an unstructured k8s resource object based on the provided schema, namespace, and name.
  594 func (a *Accessor) DeleteUnstructured(gvr schema.GroupVersionResource, namespace, name string) error {
  595     if err := a.dynClient.Resource(gvr).Namespace(namespace).Delete(context.TODO(), name, kubeApiMeta.DeleteOptions{}); err != nil {
  596         return fmt.Errorf("failed to delete resource %v of type %v: %v", name, gvr, err)
  597     }
  598     return nil
  599 }
  600 
  601 // ApplyContents applies the given config contents using kubectl.
  602 func (a *Accessor) ApplyContents(namespace string, contents string) ([]string, error) {
  603     return a.ctl.applyContents(namespace, contents, false)
  604 }
  605 
  606 // ApplyContentsDryRun applies the given config contents using kubectl with DryRun mode.
  607 func (a *Accessor) ApplyContentsDryRun(namespace string, contents string) ([]string, error) {
  608     return a.ctl.applyContents(namespace, contents, true)
  609 }
  610 
  611 // Apply applies the config in the given filename using kubectl.
  612 func (a *Accessor) Apply(namespace string, filename string) error {
  613     return a.ctl.apply(namespace, filename, false)
  614 }
  615 
  616 // ApplyDryRun applies the config in the given filename using kubectl with DryRun mode.
  617 func (a *Accessor) ApplyDryRun(namespace string, filename string) error {
  618     return a.ctl.apply(namespace, filename, true)
  619 }
  620 
  621 // DeleteContents deletes the given config contents using kubectl.
  622 func (a *Accessor) DeleteContents(namespace string, contents string) error {
  623     return a.ctl.deleteContents(namespace, contents)
  624 }
  625 
  626 // Delete the config in the given filename using kubectl.
  627 func (a *Accessor) Delete(namespace string, filename string) error {
  628     return a.ctl.delete(namespace, filename)
  629 }
  630 
  631 // Logs calls the logs command for the specified pod, with -c, if container is specified.
  632 func (a *Accessor) Logs(namespace string, pod string, container string, previousLog bool) (string, error) {
  633     return a.ctl.logs(namespace, pod, container, previousLog)
  634 }
  635 
  636 // Exec executes the provided command on the specified pod/container.
  637 func (a *Accessor) Exec(namespace, pod, container, command string) (string, error) {
  638     return a.ctl.exec(namespace, pod, container, command)
  639 }
  640 
  641 // ScaleDeployment scales a deployment to the specified number of replicas.
  642 func (a *Accessor) ScaleDeployment(namespace, deployment string, replicas int) error {
  643     return a.ctl.scale(namespace, deployment, replicas)
  644 }
  645 
  646 // CheckPodReady returns nil if the given pod and all of its containers are ready.
  647 func CheckPodReady(pod *kubeApiCore.Pod) error {
  648     switch pod.Status.Phase {
  649     case kubeApiCore.PodSucceeded:
  650         return nil
  651     case kubeApiCore.PodRunning:
  652         // Wait until all containers are ready.
  653         for _, containerStatus := range pod.Status.ContainerStatuses {
  654             if !containerStatus.Ready {
  655                 return fmt.Errorf("container not ready: '%s'", containerStatus.Name)
  656             }
  657         }
  658         if len(pod.Status.Conditions) > 0 {
  659             for _, condition := range pod.Status.Conditions {
  660                 if condition.Type == kubeApiCore.PodReady && condition.Status != kubeApiCore.ConditionTrue {
  661                     return fmt.Errorf("pod not ready, condition message: %v", condition.Message)
  662                 }
  663             }
  664         }
  665         return nil
  666     default:
  667         return fmt.Errorf("%s", pod.Status.Phase)
  668     }
  669 }
  670 
  671 func deleteOptionsForeground() *kubeApiMeta.DeleteOptions {
  672     propagationPolicy := kubeApiMeta.DeletePropagationForeground
  673     gracePeriod := int64(0)
  674     return &kubeApiMeta.DeleteOptions{
  675         PropagationPolicy:  &propagationPolicy,
  676         GracePeriodSeconds: &gracePeriod,
  677     }
  678 }
  679 
  680 func newRetryOptions(opts ...retry.Option) []retry.Option {
  681     out := make([]retry.Option, 0, 2+len(opts))
  682     out = append(out, defaultRetryTimeout, defaultRetryDelay)
  683     out = append(out, opts...)
  684     return out
  685 }