mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Refactors service catalog and discovery client code (#4272)
* Refactors service catalog and discovery client code and moves them into the kclient package. It also refactors the operator code. * Renames ListClusterServiceVersion() to ListClusterServiceVersions()
This commit is contained in:
@@ -59,7 +59,7 @@ func ListInProject(client *occlient.Client) ([]string, error) {
|
||||
// Get all ServiceInstances with the "app" label
|
||||
// Okay, so there is an edge-case here.. if Service Catalog is *not* enabled in the cluster, we shouldn't error out..
|
||||
// however, we should at least warn the user.
|
||||
serviceInstanceAppNames, err := client.GetServiceInstanceLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
serviceInstanceAppNames, err := client.GetKubeClient().ListServiceInstanceLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Unable to list Service Catalog instances: %s", err)
|
||||
} else {
|
||||
|
||||
@@ -298,7 +298,7 @@ func ListServices(client *occlient.Client) (ServiceTypeList, error) {
|
||||
// ListOperatorServices fetches a list of Operators from the cluster and
|
||||
// returns only those Operators which are successfully installed on the cluster
|
||||
func ListOperatorServices(client *kclient.Client) (*olm.ClusterServiceVersionList, error) {
|
||||
allCsvs, err := client.GetClusterServiceVersionList()
|
||||
allCsvs, err := client.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -345,12 +345,12 @@ func SearchService(client *occlient.Client, name string) (ServiceTypeList, error
|
||||
func getClusterCatalogServices(client *occlient.Client) ([]ServiceType, error) {
|
||||
var classNames []ServiceType
|
||||
|
||||
classes, err := client.GetClusterServiceClasses()
|
||||
classes, err := client.GetKubeClient().ListClusterServiceClasses()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get cluster service classes")
|
||||
}
|
||||
|
||||
planListItems, err := client.GetAllClusterServicePlans()
|
||||
planListItems, err := client.GetKubeClient().ListClusterServicePlans()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to get service plans")
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package kclient
|
||||
|
||||
import (
|
||||
fakeKubeClientset "k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
fakeServiceCatalogClientSet "github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/fake"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
fakeKubeClientset "k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
// FakeClientset holds fake ClientSets
|
||||
// this is returned by FakeNew to access methods of fake client sets
|
||||
type FakeClientset struct {
|
||||
Kubernetes *fakeKubeClientset.Clientset
|
||||
Kubernetes *fakeKubeClientset.Clientset
|
||||
ServiceCatalogClientSet *fakeServiceCatalogClientSet.Clientset
|
||||
}
|
||||
|
||||
// FakeNew creates new fake client for testing
|
||||
@@ -23,6 +24,9 @@ func FakeNew() (*Client, *FakeClientset) {
|
||||
fkclientset.Kubernetes = fakeKubeClientset.NewSimpleClientset()
|
||||
client.KubeClient = fkclientset.Kubernetes
|
||||
|
||||
fkclientset.ServiceCatalogClientSet = fakeServiceCatalogClientSet.NewSimpleClientset()
|
||||
client.serviceCatalogClient = fkclientset.ServiceCatalogClientSet.ServicecatalogV1beta1()
|
||||
|
||||
return &client, &fkclientset
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
servicecatalogclienset "github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/typed/servicecatalog/v1beta1"
|
||||
"github.com/openshift/odo/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
appsclientset "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
"k8s.io/klog"
|
||||
|
||||
@@ -33,16 +36,19 @@ Consult your Kubernetes distribution's documentation for more details
|
||||
|
||||
// Client is a collection of fields used for client configuration and interaction
|
||||
type Client struct {
|
||||
KubeClient kubernetes.Interface
|
||||
KubeConfig clientcmd.ClientConfig
|
||||
KubeClientConfig *rest.Config
|
||||
Namespace string
|
||||
OperatorClient *operatorsclientset.OperatorsV1alpha1Client
|
||||
appsClient appsclientset.AppsV1Interface
|
||||
KubeClient kubernetes.Interface
|
||||
KubeConfig clientcmd.ClientConfig
|
||||
KubeClientConfig *rest.Config
|
||||
Namespace string
|
||||
OperatorClient *operatorsclientset.OperatorsV1alpha1Client
|
||||
appsClient appsclientset.AppsV1Interface
|
||||
serviceCatalogClient servicecatalogclienset.ServicecatalogV1beta1Interface
|
||||
// DynamicClient interacts with client-go's `dynamic` package. It is used
|
||||
// to dynamically create service from an operator. It can take an arbitrary
|
||||
// yaml and create k8s/OpenShift resource from it.
|
||||
DynamicClient dynamic.Interface
|
||||
DynamicClient dynamic.Interface
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
supportedResources map[string]bool
|
||||
}
|
||||
|
||||
// New creates a new client
|
||||
@@ -93,6 +99,16 @@ func NewForConfig(config clientcmd.ClientConfig) (client *Client, err error) {
|
||||
}
|
||||
client.appsClient = appsClient
|
||||
|
||||
client.serviceCatalogClient, err = servicecatalogclienset.NewForConfig(client.KubeClientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.discoveryClient, err = discovery.NewDiscoveryClientForConfig(client.KubeClientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -178,3 +194,36 @@ func (c *Client) GeneratePortForwardReq(podName string) *rest.Request {
|
||||
Name(podName).
|
||||
SubResource("portforward")
|
||||
}
|
||||
|
||||
func (c *Client) SetDiscoveryInterface(client discovery.DiscoveryInterface) {
|
||||
c.discoveryClient = client
|
||||
}
|
||||
|
||||
func (c *Client) IsResourceSupported(apiGroup, apiVersion, resourceName string) (bool, error) {
|
||||
if c.supportedResources == nil {
|
||||
c.supportedResources = make(map[string]bool, 7)
|
||||
}
|
||||
groupVersion := metav1.GroupVersion{Group: apiGroup, Version: apiVersion}.String()
|
||||
|
||||
supported, found := c.supportedResources[groupVersion]
|
||||
if !found {
|
||||
list, err := c.discoveryClient.ServerResourcesForGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
supported = false
|
||||
} else {
|
||||
// don't record, just attempt again next time in case it's a transient error
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
for _, resources := range list.APIResources {
|
||||
if resources.Name == resourceName {
|
||||
supported = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
c.supportedResources[groupVersion] = supported
|
||||
}
|
||||
return supported, nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
olm "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
@@ -18,12 +19,25 @@ const (
|
||||
apiVersion = "odo.dev/v1alpha1"
|
||||
)
|
||||
|
||||
// GetClusterServiceVersionList returns a list of CSVs in the cluster
|
||||
// IsSBRSupported checks if resource of type service binding request present on the cluster
|
||||
func (c *Client) IsSBRSupported() (bool, error) {
|
||||
return c.IsResourceSupported("apps.openshift.io", "v1alpha1", "servicebindingrequests")
|
||||
}
|
||||
|
||||
// IsCSVSupported checks if resource of type service binding request present on the cluster
|
||||
func (c *Client) IsCSVSupported() (bool, error) {
|
||||
return c.IsResourceSupported("operators.coreos.com", "v1alpha1", "clusterserviceversions")
|
||||
}
|
||||
|
||||
// ListClusterServiceVersions returns a list of CSVs in the cluster
|
||||
// It is equivalent to doing `oc get csvs` using oc cli
|
||||
func (c *Client) GetClusterServiceVersionList() (*olm.ClusterServiceVersionList, error) {
|
||||
func (c *Client) ListClusterServiceVersions() (*olm.ClusterServiceVersionList, error) {
|
||||
klog.V(3).Infof("Fetching list of operators installed in cluster")
|
||||
csvs, err := c.OperatorClient.ClusterServiceVersions(c.Namespace).List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return &olm.ClusterServiceVersionList{}, ErrNoSuchOperator
|
||||
}
|
||||
return &olm.ClusterServiceVersionList{}, err
|
||||
}
|
||||
return csvs, nil
|
||||
@@ -31,16 +45,11 @@ func (c *Client) GetClusterServiceVersionList() (*olm.ClusterServiceVersionList,
|
||||
|
||||
// GetClusterServiceVersion returns a particular CSV from a list of CSVs
|
||||
func (c *Client) GetClusterServiceVersion(name string) (olm.ClusterServiceVersion, error) {
|
||||
csvs, err := c.GetClusterServiceVersionList()
|
||||
csv, err := c.OperatorClient.ClusterServiceVersions(c.Namespace).Get(name, v1.GetOptions{})
|
||||
if err != nil {
|
||||
return olm.ClusterServiceVersion{}, err
|
||||
}
|
||||
for _, item := range csvs.Items {
|
||||
if item.Name == name {
|
||||
return item, nil
|
||||
}
|
||||
}
|
||||
return olm.ClusterServiceVersion{}, ErrNoSuchOperator
|
||||
return *csv, nil
|
||||
}
|
||||
|
||||
// GetCustomResourcesFromCSV returns a list of CRs provided by an operator/CSV.
|
||||
@@ -53,7 +62,7 @@ func (c *Client) GetCustomResourcesFromCSV(csv *olm.ClusterServiceVersion) *[]ol
|
||||
// given keyword then return it
|
||||
func (c *Client) SearchClusterServiceVersionList(name string) (*olm.ClusterServiceVersionList, error) {
|
||||
var result []olm.ClusterServiceVersion
|
||||
csvs, err := c.GetClusterServiceVersionList()
|
||||
csvs, err := c.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return &olm.ClusterServiceVersionList{}, errors.Wrap(err, "unable to list services")
|
||||
}
|
||||
@@ -83,7 +92,7 @@ func (c *Client) SearchClusterServiceVersionList(name string) (*olm.ClusterServi
|
||||
// GetCustomResource returns the CR matching the name
|
||||
func (c *Client) GetCustomResource(customResource string) (*olm.CRDDescription, error) {
|
||||
// Get all csvs in the namespace
|
||||
csvs, err := c.GetClusterServiceVersionList()
|
||||
csvs, err := c.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return &olm.CRDDescription{}, err
|
||||
}
|
||||
@@ -105,7 +114,7 @@ func (c *Client) GetCustomResource(customResource string) (*olm.CRDDescription,
|
||||
|
||||
// GetCSVWithCR returns the CSV (Operator) that contains the CR (service)
|
||||
func (c *Client) GetCSVWithCR(name string) (*olm.ClusterServiceVersion, error) {
|
||||
csvs, err := c.GetClusterServiceVersionList()
|
||||
csvs, err := c.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return &olm.ClusterServiceVersion{}, errors.Wrap(err, "unable to list services")
|
||||
}
|
||||
|
||||
250
pkg/kclient/serviceCatalog.go
Normal file
250
pkg/kclient/serviceCatalog.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package kclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
scv1beta1 "github.com/kubernetes-sigs/service-catalog/pkg/apis/servicecatalog/v1beta1"
|
||||
"github.com/openshift/odo/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// serviceInstanceParameters converts a map of variable assignments to a byte encoded json document,
|
||||
// which is what the ServiceCatalog API consumes.
|
||||
func serviceInstanceParameters(params map[string]string) (*runtime.RawExtension, error) {
|
||||
paramsJSON, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &runtime.RawExtension{Raw: paramsJSON}, nil
|
||||
}
|
||||
|
||||
// CreateServiceInstance creates service instance from service catalog
|
||||
func (c *Client) CreateServiceInstance(serviceName string, serviceType string, servicePlan string, parameters map[string]string, labels map[string]string) error {
|
||||
serviceInstanceParameters, err := serviceInstanceParameters(parameters)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create the service instance parameters")
|
||||
}
|
||||
|
||||
_, err = c.serviceCatalogClient.ServiceInstances(c.Namespace).Create(
|
||||
&scv1beta1.ServiceInstance{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ServiceInstance",
|
||||
APIVersion: "servicecatalog.k8s.io/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: serviceName,
|
||||
Namespace: c.Namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: serviceType,
|
||||
ClusterServicePlanExternalName: servicePlan,
|
||||
},
|
||||
Parameters: serviceInstanceParameters,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to create the service instance %s for the service type %s and plan %s", serviceName, serviceType, servicePlan)
|
||||
}
|
||||
|
||||
// Create the secret containing the parameters of the plan selected.
|
||||
err = c.CreateServiceBinding(serviceName, c.Namespace, labels)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to create the secret %s for the service instance", serviceName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListServiceInstances returns list service instances
|
||||
func (c *Client) ListServiceInstances(selector string) ([]scv1beta1.ServiceInstance, error) {
|
||||
// List ServiceInstance according to given selectors
|
||||
svcList, err := c.serviceCatalogClient.ServiceInstances(c.Namespace).List(metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list ServiceInstances")
|
||||
}
|
||||
|
||||
return svcList.Items, nil
|
||||
}
|
||||
|
||||
// DeleteServiceInstance takes labels as a input and based on it, deletes respective service instance
|
||||
func (c *Client) DeleteServiceInstance(labels map[string]string) error {
|
||||
klog.V(3).Infof("Deleting Service Instance")
|
||||
|
||||
// convert labels to selector
|
||||
selector := util.ConvertLabelsToSelector(labels)
|
||||
klog.V(3).Infof("Selectors used for deletion: %s", selector)
|
||||
|
||||
// Listing out serviceInstance because `DeleteCollection` method don't work on serviceInstance
|
||||
serviceInstances, err := c.ListServiceInstances(selector)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to list service instance")
|
||||
}
|
||||
|
||||
// Iterating over serviceInstance List and deleting one by one
|
||||
for _, serviceInstance := range serviceInstances {
|
||||
// we need to delete the ServiceBinding before deleting the ServiceInstance
|
||||
err = c.serviceCatalogClient.ServiceBindings(c.Namespace).Delete(serviceInstance.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete serviceBinding")
|
||||
}
|
||||
// now we perform the actual deletion
|
||||
err = c.serviceCatalogClient.ServiceInstances(c.Namespace).Delete(serviceInstance.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete serviceInstance")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClusterServiceClass returns the required service class from the service name
|
||||
// serviceName is the name of the service
|
||||
// returns the required service class and the error
|
||||
func (c *Client) GetClusterServiceClass(serviceName string) (*scv1beta1.ClusterServiceClass, error) {
|
||||
opts := metav1.ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("spec.externalName", serviceName).String(),
|
||||
}
|
||||
searchResults, err := c.serviceCatalogClient.ClusterServiceClasses().List(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to search classes by name (%s)", err)
|
||||
}
|
||||
if len(searchResults.Items) == 0 {
|
||||
return nil, fmt.Errorf("class '%s' not found", serviceName)
|
||||
}
|
||||
if len(searchResults.Items) > 1 {
|
||||
return nil, fmt.Errorf("more than one matching class found for '%s'", serviceName)
|
||||
}
|
||||
return &searchResults.Items[0], nil
|
||||
}
|
||||
|
||||
// ListClusterServiceClasses queries the service service catalog to get available clusterServiceClasses
|
||||
func (c *Client) ListClusterServiceClasses() ([]scv1beta1.ClusterServiceClass, error) {
|
||||
classList, err := c.serviceCatalogClient.ClusterServiceClasses().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list cluster service classes")
|
||||
}
|
||||
return classList.Items, nil
|
||||
}
|
||||
|
||||
// ListServiceClassesByCategory retrieves a map associating category name to ClusterServiceClasses matching the category
|
||||
func (c *Client) ListServiceClassesByCategory() (categories map[string][]scv1beta1.ClusterServiceClass, err error) {
|
||||
categories = make(map[string][]scv1beta1.ClusterServiceClass)
|
||||
classes, err := c.ListClusterServiceClasses()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Should we replicate the classification performed in
|
||||
// https://github.com/openshift/console/blob/master/frontend/public/components/catalog/catalog-items.jsx?
|
||||
for _, class := range classes {
|
||||
tags := class.Spec.Tags
|
||||
category := "other"
|
||||
if len(tags) > 0 && len(tags[0]) > 0 {
|
||||
category = tags[0]
|
||||
}
|
||||
categories[category] = append(categories[category], class)
|
||||
}
|
||||
|
||||
return categories, err
|
||||
}
|
||||
|
||||
// ListClusterServicePlans returns list of available plans
|
||||
func (c *Client) ListClusterServicePlans() ([]scv1beta1.ClusterServicePlan, error) {
|
||||
planList, err := c.serviceCatalogClient.ClusterServicePlans().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get cluster service plan")
|
||||
}
|
||||
|
||||
return planList.Items, nil
|
||||
}
|
||||
|
||||
// ListClusterServicePlansByServiceName returns the plans associated with a service class
|
||||
// serviceName is the name (the actual id, NOT the external name) of the service class whose plans are required
|
||||
// returns array of ClusterServicePlans or error
|
||||
func (c *Client) ListClusterServicePlansByServiceName(serviceName string) ([]scv1beta1.ClusterServicePlan, error) {
|
||||
opts := metav1.ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("spec.clusterServiceClassRef.name", serviceName).String(),
|
||||
}
|
||||
|
||||
searchResults, err := c.serviceCatalogClient.ClusterServicePlans().List(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to search plans for service name '%s', (%s)", serviceName, err)
|
||||
}
|
||||
return searchResults.Items, nil
|
||||
}
|
||||
|
||||
// GetServiceBinding returns the ServiceBinding named serviceName in the namespace namespace
|
||||
func (c *Client) GetServiceBinding(serviceName string, namespace string) (*scv1beta1.ServiceBinding, error) {
|
||||
return c.serviceCatalogClient.ServiceBindings(namespace).Get(serviceName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// CreateServiceBinding creates a ServiceBinding (essentially a secret) within the namespace of the
|
||||
// service instance created using the service's parameters.
|
||||
func (c *Client) CreateServiceBinding(bindingName string, namespace string, labels map[string]string) error {
|
||||
_, err := c.serviceCatalogClient.ServiceBindings(namespace).Create(
|
||||
&scv1beta1.ServiceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bindingName,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: scv1beta1.ServiceBindingSpec{
|
||||
InstanceRef: scv1beta1.LocalObjectReference{
|
||||
Name: bindingName,
|
||||
},
|
||||
SecretName: bindingName,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Creation of the secret failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListMatchingPlans retrieves a map associating service plan name to service plan instance associated with the specified service
|
||||
// class
|
||||
func (c *Client) ListMatchingPlans(class scv1beta1.ClusterServiceClass) (plans map[string]scv1beta1.ClusterServicePlan, err error) {
|
||||
planList, err := c.serviceCatalogClient.ClusterServicePlans().List(metav1.ListOptions{
|
||||
FieldSelector: "spec.clusterServiceClassRef.name==" + class.Spec.ExternalID,
|
||||
})
|
||||
|
||||
plans = make(map[string]scv1beta1.ClusterServicePlan)
|
||||
for _, v := range planList.Items {
|
||||
plans[v.Spec.ExternalName] = v
|
||||
}
|
||||
return plans, err
|
||||
}
|
||||
|
||||
// ListServiceInstanceLabelValues get label values of given label from objects in project that match the selector
|
||||
func (c *Client) ListServiceInstanceLabelValues(label string, selector string) ([]string, error) {
|
||||
|
||||
// List ServiceInstance according to given selectors
|
||||
svcList, err := c.serviceCatalogClient.ServiceInstances(c.Namespace).List(metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list ServiceInstances")
|
||||
}
|
||||
|
||||
// Grab all the matched strings
|
||||
var values []string
|
||||
for _, elem := range svcList.Items {
|
||||
val, ok := elem.Labels[label]
|
||||
if ok {
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort alphabetically
|
||||
sort.Strings(values)
|
||||
|
||||
return values, nil
|
||||
}
|
||||
980
pkg/kclient/serviceCatalog_test.go
Normal file
980
pkg/kclient/serviceCatalog_test.go
Normal file
@@ -0,0 +1,980 @@
|
||||
package kclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
applabels "github.com/openshift/odo/pkg/application/labels"
|
||||
componentlabels "github.com/openshift/odo/pkg/component/labels"
|
||||
"github.com/openshift/odo/pkg/testingutil"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
scv1beta1 "github.com/kubernetes-sigs/service-catalog/pkg/apis/servicecatalog/v1beta1"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func fakePlanExternalMetaDataRaw() ([][]byte, error) {
|
||||
planExternalMetaData1 := make(map[string]string)
|
||||
planExternalMetaData1["displayName"] = "plan-name-1"
|
||||
|
||||
planExternalMetaData2 := make(map[string]string)
|
||||
planExternalMetaData2["displayName"] = "plan-name-2"
|
||||
|
||||
planExternalMetaDataRaw1, err := json.Marshal(planExternalMetaData1)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
|
||||
planExternalMetaDataRaw2, err := json.Marshal(planExternalMetaData2)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
|
||||
var data [][]byte
|
||||
data = append(data, planExternalMetaDataRaw1)
|
||||
data = append(data, planExternalMetaDataRaw2)
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func fakePlanInstanceCreateParameterSchemasRaw() ([][]byte, error) {
|
||||
planInstanceCreateParameterSchema1 := make(map[string][]string)
|
||||
planInstanceCreateParameterSchema1["required"] = []string{"PLAN_DATABASE_URI", "PLAN_DATABASE_USERNAME", "PLAN_DATABASE_PASSWORD"}
|
||||
|
||||
planInstanceCreateParameterSchema2 := make(map[string][]string)
|
||||
planInstanceCreateParameterSchema2["required"] = []string{"PLAN_DATABASE_USERNAME_2", "PLAN_DATABASE_PASSWORD"}
|
||||
|
||||
planInstanceCreateParameterSchemaRaw1, err := json.Marshal(planInstanceCreateParameterSchema1)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
}
|
||||
|
||||
planInstanceCreateParameterSchemaRaw2, err := json.Marshal(planInstanceCreateParameterSchema2)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "")
|
||||
}
|
||||
}
|
||||
|
||||
var data [][]byte
|
||||
data = append(data, planInstanceCreateParameterSchemaRaw1)
|
||||
data = append(data, planInstanceCreateParameterSchemaRaw2)
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func TestDeleteServiceInstance(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
serviceName string
|
||||
labels map[string]string
|
||||
serviceList scv1beta1.ServiceInstanceList
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Delete service instance",
|
||||
serviceName: "mongodb",
|
||||
labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "mongodb",
|
||||
},
|
||||
serviceList: scv1beta1.ServiceInstanceList{
|
||||
Items: []scv1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mongodb",
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "mongodb",
|
||||
componentlabels.ComponentTypeLabel: "mongodb-persistent",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fkclient, fkclientset := FakeNew()
|
||||
|
||||
//fake the services listing
|
||||
fkclientset.ServiceCatalogClientSet.PrependReactor("list", "serviceinstances", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &tt.serviceList, nil
|
||||
})
|
||||
|
||||
// Fake the servicebinding delete
|
||||
fkclientset.ServiceCatalogClientSet.PrependReactor("delete", "servicebindings", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
// Fake the serviceinstance delete
|
||||
fkclientset.ServiceCatalogClientSet.PrependReactor("delete", "serviceinstances", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
err := fkclient.DeleteServiceInstance(tt.labels)
|
||||
// Checks for error in positive cases
|
||||
if !tt.wantErr && (err != nil) {
|
||||
t.Errorf(" client.DeleteServiceInstance(labels) unexpected error %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
// Check for validating actions performed
|
||||
// deleting based on the labels means listing the services and then delete the instance and binding for each
|
||||
// thus we have 1 list action that always takes place, plus another 2 (delete instance, delete binding)
|
||||
// for each service
|
||||
expectedNumberOfServiceCatalogActions := 1 + (2 * len(tt.serviceList.Items))
|
||||
if len(fkclientset.ServiceCatalogClientSet.Actions()) != expectedNumberOfServiceCatalogActions && !tt.wantErr {
|
||||
t.Errorf("expected %d action in CreateServiceInstace got: %v",
|
||||
expectedNumberOfServiceCatalogActions, fkclientset.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
|
||||
// Check that the correct service binding was deleted
|
||||
DeletedServiceBinding := fkclientset.ServiceCatalogClientSet.Actions()[1].(ktesting.DeleteAction).GetName()
|
||||
if DeletedServiceBinding != tt.serviceName {
|
||||
t.Errorf("Delete action is performed with wrong ServiceBinding, expected: %s, got %s", tt.serviceName, DeletedServiceBinding)
|
||||
}
|
||||
|
||||
// Check that the correct service instance was deleted
|
||||
DeletedServiceInstance := fkclientset.ServiceCatalogClientSet.Actions()[2].(ktesting.DeleteAction).GetName()
|
||||
if DeletedServiceInstance != tt.serviceName {
|
||||
t.Errorf("Delete action is performed with wrong ServiceInstance, expected: %s, got %s", tt.serviceName, DeletedServiceInstance)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListServiceInstances(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
Project string
|
||||
Selector string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
serviceList scv1beta1.ServiceInstanceList
|
||||
output []scv1beta1.ServiceInstance
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test case 1",
|
||||
args: args{
|
||||
Project: "myproject",
|
||||
Selector: "app.kubernetes.io/instance=mysql-persistent,app.kubernetes.io/part-of=app",
|
||||
},
|
||||
serviceList: scv1beta1.ServiceInstanceList{
|
||||
Items: []scv1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mysql-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "mysql-persistent",
|
||||
componentlabels.ComponentTypeLabel: "mysql-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "mysql-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "jenkins-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "jenkins-persistent",
|
||||
componentlabels.ComponentTypeLabel: "jenkins-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "jenkins-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []scv1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mysql-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "mysql-persistent",
|
||||
componentlabels.ComponentTypeLabel: "mysql-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "mysql-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
client, fakeClientSet := FakeNew()
|
||||
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "serviceinstances", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
if !reflect.DeepEqual(action.(ktesting.ListAction).GetListRestrictions().Labels.String(), tt.args.Selector) {
|
||||
return true, nil, fmt.Errorf("labels not matching with expected values, expected:%s, got:%s", tt.args.Selector, action.(ktesting.ListAction).GetListRestrictions())
|
||||
}
|
||||
return true, &tt.serviceList, nil
|
||||
})
|
||||
|
||||
svcInstanceList, err := client.ListServiceInstances(tt.args.Selector)
|
||||
|
||||
if !reflect.DeepEqual(tt.output, svcInstanceList) {
|
||||
t.Errorf("expected output: %#v,got: %#v", tt.serviceList, svcInstanceList)
|
||||
}
|
||||
|
||||
if err == nil && !tt.wantErr {
|
||||
if (len(fakeClientSet.ServiceCatalogClientSet.Actions()) != 1) && (tt.wantErr != true) {
|
||||
t.Errorf("expected 1 action in ListServicecatalog got: %v", fakeClientSet.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
} else if err == nil && tt.wantErr {
|
||||
t.Error("test failed, expected: false, got true")
|
||||
} else if err != nil && !tt.wantErr {
|
||||
t.Errorf("test failed, expected: no error, got error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetClusterServiceClass(t *testing.T) {
|
||||
classExternalMetaData := make(map[string]interface{})
|
||||
classExternalMetaData["longDescription"] = "example long description"
|
||||
classExternalMetaData["dependencies"] = []string{"docker.io/centos/7", "docker.io/centos/8"}
|
||||
|
||||
classExternalMetaDataRaw, err := json.Marshal(classExternalMetaData)
|
||||
if err != nil {
|
||||
fmt.Printf("error occured %v during marshalling", err)
|
||||
return
|
||||
}
|
||||
|
||||
type args struct {
|
||||
serviceName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
returnedServicesClasses *scv1beta1.ClusterServiceClassList
|
||||
wantedServiceClass *scv1beta1.ClusterServiceClass
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test case 1: with one valid service class returned",
|
||||
args: args{
|
||||
serviceName: "class name",
|
||||
},
|
||||
returnedServicesClasses: &scv1beta1.ClusterServiceClassList{
|
||||
Items: []scv1beta1.ClusterServiceClass{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "1dda1477cace09730bd8ed7a6505607e"},
|
||||
Spec: scv1beta1.ClusterServiceClassSpec{
|
||||
CommonServiceClassSpec: scv1beta1.CommonServiceClassSpec{
|
||||
ExternalName: "class name",
|
||||
Bindable: false,
|
||||
Description: "example description",
|
||||
Tags: []string{"php", "java"},
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: classExternalMetaDataRaw},
|
||||
},
|
||||
ClusterServiceBrokerName: "broker name",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantedServiceClass: &scv1beta1.ClusterServiceClass{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "1dda1477cace09730bd8ed7a6505607e"},
|
||||
Spec: scv1beta1.ClusterServiceClassSpec{
|
||||
CommonServiceClassSpec: scv1beta1.CommonServiceClassSpec{
|
||||
ExternalName: "class name",
|
||||
Bindable: false,
|
||||
Description: "example description",
|
||||
Tags: []string{"php", "java"},
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: classExternalMetaDataRaw},
|
||||
},
|
||||
ClusterServiceBrokerName: "broker name",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "test case 2: with two service classes returned",
|
||||
args: args{
|
||||
serviceName: "class name",
|
||||
},
|
||||
returnedServicesClasses: &scv1beta1.ClusterServiceClassList{
|
||||
Items: []scv1beta1.ClusterServiceClass{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "1dda1477cace09730bd8ed7a6505607e"},
|
||||
Spec: scv1beta1.ClusterServiceClassSpec{
|
||||
CommonServiceClassSpec: scv1beta1.CommonServiceClassSpec{
|
||||
ExternalName: "class name",
|
||||
Bindable: false,
|
||||
Description: "example description",
|
||||
Tags: []string{"php", "java"},
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: classExternalMetaDataRaw},
|
||||
},
|
||||
ClusterServiceBrokerName: "broker name",
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "1dda1477cace09730bd8ed7a6505607e"},
|
||||
Spec: scv1beta1.ClusterServiceClassSpec{
|
||||
CommonServiceClassSpec: scv1beta1.CommonServiceClassSpec{
|
||||
ExternalName: "class name",
|
||||
Bindable: false,
|
||||
Description: "example description",
|
||||
Tags: []string{"java"},
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: classExternalMetaDataRaw},
|
||||
},
|
||||
ClusterServiceBrokerName: "broker name 1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantedServiceClass: &scv1beta1.ClusterServiceClass{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "test case 3: with no service classes returned",
|
||||
args: args{
|
||||
serviceName: "class name",
|
||||
},
|
||||
returnedServicesClasses: &scv1beta1.ClusterServiceClassList{
|
||||
Items: []scv1beta1.ClusterServiceClass{},
|
||||
},
|
||||
wantedServiceClass: &scv1beta1.ClusterServiceClass{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
client, fakeClientSet := FakeNew()
|
||||
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "clusterserviceclasses", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
if action.(ktesting.ListAction).GetListRestrictions().Fields.String() != fmt.Sprintf("spec.externalName=%v", tt.args.serviceName) {
|
||||
t.Errorf("got a different service name got: %v , expected: %v", action.(ktesting.ListAction).GetListRestrictions().Fields.String(), fmt.Sprintf("spec.externalName=%v", tt.args.serviceName))
|
||||
}
|
||||
return true, tt.returnedServicesClasses, nil
|
||||
})
|
||||
|
||||
gotServiceClass, err := client.GetClusterServiceClass(tt.args.serviceName)
|
||||
if err == nil && !tt.wantErr {
|
||||
if len(fakeClientSet.ServiceCatalogClientSet.Actions()) != 1 {
|
||||
t.Errorf("expected 1 action in GetServiceClassAndPlans got: %v", fakeClientSet.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(gotServiceClass.Spec, tt.wantedServiceClass.Spec) {
|
||||
t.Errorf("different service class spec value expected: %v", pretty.Compare(gotServiceClass.Spec, tt.wantedServiceClass.Spec))
|
||||
}
|
||||
if !reflect.DeepEqual(gotServiceClass.Name, tt.wantedServiceClass.Name) {
|
||||
t.Errorf("different service class name value expected got: %v , expected: %v", gotServiceClass.Name, tt.wantedServiceClass.Name)
|
||||
}
|
||||
} else if err == nil && tt.wantErr {
|
||||
t.Error("test failed, expected: false, got true")
|
||||
} else if err != nil && !tt.wantErr {
|
||||
t.Errorf("test failed, expected: no error, got error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestListClusterServicePlansByServiceName(t *testing.T) {
|
||||
planExternalMetaDataRaw, err := fakePlanExternalMetaDataRaw()
|
||||
if err != nil {
|
||||
fmt.Printf("error occured %v during marshalling", err)
|
||||
return
|
||||
}
|
||||
|
||||
planInstanceCreateParameterSchemasRaw, err := fakePlanInstanceCreateParameterSchemasRaw()
|
||||
if err != nil {
|
||||
fmt.Printf("error occured %v during marshalling", err)
|
||||
return
|
||||
}
|
||||
|
||||
type args struct {
|
||||
serviceClassName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []scv1beta1.ClusterServicePlan
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test case 1 : plans found for the service class",
|
||||
args: args{serviceClassName: "1dda1477cace09730bd8ed7a6505607e"},
|
||||
wantErr: false,
|
||||
want: []scv1beta1.ClusterServicePlan{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "67042296c7c95e84142f21f58da2ebfe",
|
||||
},
|
||||
Spec: scv1beta1.ClusterServicePlanSpec{
|
||||
ClusterServiceClassRef: scv1beta1.ClusterObjectReference{
|
||||
Name: "1dda1477cace09730bd8ed7a6505607e",
|
||||
},
|
||||
CommonServicePlanSpec: scv1beta1.CommonServicePlanSpec{
|
||||
ExternalName: "dev",
|
||||
Description: "this is a example description 1",
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: planExternalMetaDataRaw[0]},
|
||||
InstanceCreateParameterSchema: &runtime.RawExtension{Raw: planInstanceCreateParameterSchemasRaw[0]},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "7f88be6129622f72554c20af879a8ce0",
|
||||
},
|
||||
Spec: scv1beta1.ClusterServicePlanSpec{
|
||||
ClusterServiceClassRef: scv1beta1.ClusterObjectReference{
|
||||
Name: "1dda1477cace09730bd8ed7a6505607e",
|
||||
},
|
||||
CommonServicePlanSpec: scv1beta1.CommonServicePlanSpec{
|
||||
ExternalName: "prod",
|
||||
Description: "this is a example description 2",
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: planExternalMetaDataRaw[1]},
|
||||
InstanceCreateParameterSchema: &runtime.RawExtension{Raw: planInstanceCreateParameterSchemasRaw[1]},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test case 2 : no plans found for the service class",
|
||||
args: args{serviceClassName: "1dda1477cace09730bd8"},
|
||||
wantErr: false,
|
||||
want: []scv1beta1.ClusterServicePlan{},
|
||||
},
|
||||
}
|
||||
|
||||
planList := scv1beta1.ClusterServicePlanList{
|
||||
Items: []scv1beta1.ClusterServicePlan{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "67042296c7c95e84142f21f58da2ebfe",
|
||||
},
|
||||
Spec: scv1beta1.ClusterServicePlanSpec{
|
||||
ClusterServiceClassRef: scv1beta1.ClusterObjectReference{
|
||||
Name: "1dda1477cace09730bd8ed7a6505607e",
|
||||
},
|
||||
CommonServicePlanSpec: scv1beta1.CommonServicePlanSpec{
|
||||
ExternalName: "dev",
|
||||
Description: "this is a example description 1",
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: planExternalMetaDataRaw[0]},
|
||||
InstanceCreateParameterSchema: &runtime.RawExtension{Raw: planInstanceCreateParameterSchemasRaw[0]},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "7f88be6129622f72554c20af879a8ce0",
|
||||
},
|
||||
Spec: scv1beta1.ClusterServicePlanSpec{
|
||||
ClusterServiceClassRef: scv1beta1.ClusterObjectReference{
|
||||
Name: "1dda1477cace09730bd8ed7a6505607e",
|
||||
},
|
||||
CommonServicePlanSpec: scv1beta1.CommonServicePlanSpec{
|
||||
ExternalName: "prod",
|
||||
Description: "this is a example description 2",
|
||||
ExternalMetadata: &runtime.RawExtension{Raw: planExternalMetaDataRaw[1]},
|
||||
InstanceCreateParameterSchema: &runtime.RawExtension{Raw: planInstanceCreateParameterSchemasRaw[1]},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client, fakeClientSet := FakeNew()
|
||||
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "clusterserviceplans", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
var pList []scv1beta1.ClusterServicePlan
|
||||
for _, plan := range planList.Items {
|
||||
if plan.Spec.ClusterServiceClassRef.Name == strings.Split(action.(ktesting.ListAction).GetListRestrictions().Fields.String(), "=")[1] {
|
||||
pList = append(pList, plan)
|
||||
}
|
||||
}
|
||||
|
||||
return true, &scv1beta1.ClusterServicePlanList{Items: pList}, nil
|
||||
})
|
||||
|
||||
gotPlans, err := client.ListClusterServicePlansByServiceName(tt.args.serviceClassName)
|
||||
if err == nil && !tt.wantErr {
|
||||
if len(fakeClientSet.ServiceCatalogClientSet.Actions()) != 1 {
|
||||
t.Errorf("expected 2 actions in GetServiceClassAndPlans got: %v", fakeClientSet.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
|
||||
for _, wantedServicePlan := range tt.want {
|
||||
found := false
|
||||
for _, gotServicePlan := range gotPlans {
|
||||
if reflect.DeepEqual(wantedServicePlan.Spec.ExternalName, gotServicePlan.Spec.ExternalName) {
|
||||
found = true
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(wantedServicePlan.Name, gotServicePlan.Name) {
|
||||
t.Errorf("different plan name expected got: %v , expected: %v", wantedServicePlan.Name, gotServicePlan.Name)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(wantedServicePlan.Spec, gotServicePlan.Spec) {
|
||||
t.Errorf("different plan spec value expected: %v", pretty.Compare(wantedServicePlan.Spec, gotServicePlan.Spec))
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("service plan %v not found", wantedServicePlan.Spec.ExternalName)
|
||||
}
|
||||
}
|
||||
} else if err == nil && tt.wantErr {
|
||||
t.Error("test failed, expected: false, got true")
|
||||
} else if err != nil && !tt.wantErr {
|
||||
t.Errorf("test failed, expected: no error, got error: %s", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateServiceInstance(t *testing.T) {
|
||||
type args struct {
|
||||
serviceName string
|
||||
serviceType string
|
||||
labels map[string]string
|
||||
plan string
|
||||
parameters map[string]string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Create service instance",
|
||||
args: args{
|
||||
serviceName: "jenkins",
|
||||
serviceType: "jenkins",
|
||||
labels: map[string]string{
|
||||
"name": "mongodb",
|
||||
"namespace": "blog",
|
||||
},
|
||||
plan: "dev",
|
||||
parameters: map[string]string{},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fkclient, fkclientset := FakeNew()
|
||||
|
||||
err := fkclient.CreateServiceInstance(tt.args.serviceName, tt.args.serviceType, tt.args.plan, tt.args.parameters, tt.args.labels)
|
||||
// Checks for error in positive cases
|
||||
if tt.wantErr == false && (err != nil) {
|
||||
t.Errorf(" client.CreateServiceInstance(serviceName,serviceType, labels) unexpected error %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
// Check for validating actions performed
|
||||
// creating a service instance also means creating a serviceBinding
|
||||
// which is why we expect 2 actions
|
||||
if len(fkclientset.ServiceCatalogClientSet.Actions()) != 2 && !tt.wantErr {
|
||||
t.Errorf("expected 1 action in CreateServiceInstace got: %v", fkclientset.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
|
||||
createdServiceInstance := fkclientset.ServiceCatalogClientSet.Actions()[0].(ktesting.CreateAction).GetObject().(*scv1beta1.ServiceInstance)
|
||||
if !reflect.DeepEqual(createdServiceInstance.Labels, tt.args.labels) {
|
||||
t.Errorf("labels in created serviceInstance is not matching expected labels, expected: %v, got: %v", tt.args.labels, createdServiceInstance.Labels)
|
||||
}
|
||||
if createdServiceInstance.Name != tt.args.serviceName {
|
||||
t.Errorf("labels in created serviceInstance is not matching expected labels, expected: %v, got: %v", tt.args.serviceName, createdServiceInstance.Name)
|
||||
}
|
||||
if !reflect.DeepEqual(createdServiceInstance.Spec.ClusterServiceClassExternalName, tt.args.serviceType) {
|
||||
t.Errorf("labels in created serviceInstance is not matching expected labels, expected: %v, got: %v", tt.args.serviceType, createdServiceInstance.Spec.ClusterServiceClassExternalName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceBinding(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
namespace string
|
||||
serviceName string
|
||||
wantErr bool
|
||||
want *scv1beta1.ServiceBinding
|
||||
}{
|
||||
{
|
||||
name: "Case: Valid request for retrieving a service binding",
|
||||
namespace: "",
|
||||
serviceName: "foo",
|
||||
want: &scv1beta1.ServiceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Case: Invalid request for retrieving a service binding",
|
||||
namespace: "",
|
||||
serviceName: "foo2",
|
||||
want: &scv1beta1.ServiceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fakeClient, fakeClientSet := FakeNew()
|
||||
|
||||
// Fake getting Secret
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("get", "servicebindings", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
if tt.want.Name != tt.serviceName {
|
||||
return true, nil, fmt.Errorf("'get' called with a different serviebinding name")
|
||||
}
|
||||
return true, tt.want, nil
|
||||
})
|
||||
|
||||
returnValue, err := fakeClient.GetServiceBinding(tt.serviceName, tt.namespace)
|
||||
|
||||
// Check for validating return value
|
||||
if err == nil && returnValue != tt.want {
|
||||
t.Errorf("error in return value got: %v, expected %v", returnValue, tt.want)
|
||||
}
|
||||
|
||||
if !tt.wantErr == (err != nil) {
|
||||
t.Errorf("\nclient.GetServiceBinding(serviceName, namespace) unexpected error %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateServiceBinding(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
bindingNS string
|
||||
bindingName string
|
||||
labels map[string]string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Case: Valid request for creating a secret",
|
||||
bindingNS: "",
|
||||
bindingName: "foo",
|
||||
labels: map[string]string{"app": "app"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fakeClient, fakeClientSet := FakeNew()
|
||||
|
||||
err := fakeClient.CreateServiceBinding(tt.bindingName, tt.bindingNS, tt.labels)
|
||||
|
||||
if err == nil && !tt.wantErr {
|
||||
if len(fakeClientSet.ServiceCatalogClientSet.Actions()) != 1 {
|
||||
t.Errorf("expected 1 ServiceCatalogClientSet.Actions() in CreateServiceBinding, got: %v", fakeClientSet.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
createdBinding := fakeClientSet.ServiceCatalogClientSet.Actions()[0].(ktesting.CreateAction).GetObject().(*scv1beta1.ServiceBinding)
|
||||
if createdBinding.Name != tt.bindingName {
|
||||
t.Errorf("the name of servicebinding was not correct, expected: %s, got: %s", tt.bindingName, createdBinding.Name)
|
||||
}
|
||||
} else if err == nil && tt.wantErr {
|
||||
t.Error("error was expected, but no error was returned")
|
||||
} else if err != nil && !tt.wantErr {
|
||||
t.Errorf("test failed, no error was expected, but got unexpected error: %s", err)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListServiceClassesByCategory(t *testing.T) {
|
||||
t.Run("ListServiceClassesByCategory should work", func(t *testing.T) {
|
||||
client, fakeClientSet := FakeNew()
|
||||
foo := testingutil.FakeClusterServiceClass("foo", "footag", "footag2")
|
||||
bar := testingutil.FakeClusterServiceClass("bar", "")
|
||||
boo := testingutil.FakeClusterServiceClass("boo")
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "clusterserviceclasses", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &scv1beta1.ClusterServiceClassList{
|
||||
Items: []scv1beta1.ClusterServiceClass{
|
||||
foo,
|
||||
bar,
|
||||
boo,
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
|
||||
expected := map[string][]scv1beta1.ClusterServiceClass{"footag": {foo}, "other": {bar, boo}}
|
||||
categories, err := client.ListServiceClassesByCategory()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("test failed due to %s", err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, categories) {
|
||||
t.Errorf("test failed, expected %v, got %v", expected, categories)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestListMatchingPlans(t *testing.T) {
|
||||
t.Run("ListMatchingPlans should work", func(t *testing.T) {
|
||||
client, fakeClientSet := FakeNew()
|
||||
foo := testingutil.FakeClusterServiceClass("foo", "footag", "footag2")
|
||||
dev := testingutil.FakeClusterServicePlan("dev", 1)
|
||||
classId := foo.Spec.ExternalID
|
||||
dev.Spec.ClusterServiceClassRef.Name = classId
|
||||
prod := testingutil.FakeClusterServicePlan("prod", 2)
|
||||
prod.Spec.ClusterServiceClassRef.Name = classId
|
||||
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "clusterserviceplans", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
value, _ := action.(ktesting.ListAction).GetListRestrictions().Fields.RequiresExactMatch("spec.clusterServiceClassRef.name")
|
||||
if value != classId {
|
||||
t.Errorf("cluster service plans list should have been filtered on 'spec.clusterServiceClassRef.name==%s'", classId)
|
||||
}
|
||||
|
||||
return true, &scv1beta1.ClusterServicePlanList{
|
||||
Items: []scv1beta1.ClusterServicePlan{
|
||||
dev,
|
||||
prod,
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
|
||||
expected := map[string]scv1beta1.ClusterServicePlan{"dev": dev, "prod": prod}
|
||||
plans, err := client.ListMatchingPlans(foo)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("test failed due to %s", err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, plans) {
|
||||
t.Errorf("test failed, expected %v, got %v", expected, plans)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestListServiceInstanceLabelValues(t *testing.T) {
|
||||
type args struct {
|
||||
serviceList scv1beta1.ServiceInstanceList
|
||||
expectedOutput []string
|
||||
// dcBefore appsv1.DeploymentConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
actions int
|
||||
}{
|
||||
{
|
||||
name: "Case 1 - Retrieve list",
|
||||
args: args{
|
||||
expectedOutput: []string{"app", "app2"},
|
||||
serviceList: scv1beta1.ServiceInstanceList{
|
||||
Items: []scv1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mysql-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "mysql-persistent",
|
||||
componentlabels.ComponentTypeLabel: "mysql-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "mysql-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "jenkins-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app2",
|
||||
componentlabels.ComponentLabel: "jenkins-persistent",
|
||||
componentlabels.ComponentTypeLabel: "jenkins-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "jenkins-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
actions: 1,
|
||||
},
|
||||
{
|
||||
name: "Case 2 - Retrieve list, different order",
|
||||
args: args{
|
||||
expectedOutput: []string{"app", "app2"},
|
||||
serviceList: scv1beta1.ServiceInstanceList{
|
||||
Items: []scv1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mysql-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app2",
|
||||
componentlabels.ComponentLabel: "mysql-persistent",
|
||||
componentlabels.ComponentTypeLabel: "mysql-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "mysql-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "jenkins-persistent",
|
||||
Finalizers: []string{"kubernetes-incubator/service-catalog"},
|
||||
Labels: map[string]string{
|
||||
applabels.ApplicationLabel: "app",
|
||||
componentlabels.ComponentLabel: "jenkins-persistent",
|
||||
componentlabels.ComponentTypeLabel: "jenkins-persistent",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: "jenkins-persistent",
|
||||
ClusterServicePlanExternalName: "default",
|
||||
},
|
||||
},
|
||||
Status: scv1beta1.ServiceInstanceStatus{
|
||||
Conditions: []scv1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "ProvisionedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
actions: 1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
fakeClient, fakeClientSet := FakeNew()
|
||||
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "serviceinstances", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
return true, &tt.args.serviceList, nil
|
||||
})
|
||||
|
||||
// Run function ListServiceInstanceLabelValues
|
||||
list, err := fakeClient.ListServiceInstanceLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
|
||||
if err == nil && !tt.wantErr {
|
||||
|
||||
// Compare arrays
|
||||
if !reflect.DeepEqual(list, tt.args.expectedOutput) {
|
||||
t.Errorf("expected %s output, got %s", tt.args.expectedOutput, list)
|
||||
}
|
||||
|
||||
if (len(fakeClientSet.ServiceCatalogClientSet.Actions()) != tt.actions) && !tt.wantErr {
|
||||
t.Errorf("expected %v action(s) in ListServiceInstanceLabelValues got %v: %v", tt.actions, len(fakeClientSet.ServiceCatalogClientSet.Actions()), fakeClientSet.ServiceCatalogClientSet.Actions())
|
||||
}
|
||||
|
||||
} else if err == nil && tt.wantErr {
|
||||
t.Error("test failed, expected: false, got true")
|
||||
} else if err != nil && !tt.wantErr {
|
||||
t.Errorf("test failed, expected: no error, got error: %s", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ func (c *Client) IsDeploymentConfigSupported() (bool, error) {
|
||||
const Group = "apps.openshift.io"
|
||||
const Version = "v1"
|
||||
|
||||
return c.isResourceSupported(Group, Version, "deploymentconfigs")
|
||||
return c.GetKubeClient().IsResourceSupported(Group, Version, "deploymentconfigs")
|
||||
}
|
||||
|
||||
// GetDeploymentConfigFromName returns the Deployment Config resource given
|
||||
|
||||
@@ -92,7 +92,6 @@ func TestGetDeploymentConfigLabelValues(t *testing.T) {
|
||||
return true, &tt.args.deploymentConfigList, nil
|
||||
})
|
||||
|
||||
// Run function GetServiceInstanceLabelValues
|
||||
list, err := fakeClient.GetDeploymentConfigLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel)
|
||||
|
||||
if err == nil && !tt.wantErr {
|
||||
@@ -103,7 +102,7 @@ func TestGetDeploymentConfigLabelValues(t *testing.T) {
|
||||
}
|
||||
|
||||
if (len(fakeClientSet.AppsClientset.Actions()) != tt.actions) && !tt.wantErr {
|
||||
t.Errorf("expected %v action(s) in GetServiceInstanceLabelValues got %v: %v", tt.actions, len(fakeClientSet.AppsClientset.Actions()), fakeClientSet.AppsClientset.Actions())
|
||||
t.Errorf("expected %v action(s) in TestGetDeploymentConfigLabelValues got %v: %v", tt.actions, len(fakeClientSet.AppsClientset.Actions()), fakeClientSet.AppsClientset.Actions())
|
||||
}
|
||||
|
||||
} else if err == nil && tt.wantErr {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package occlient
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
fakeServiceCatalogClientSet "github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/fake"
|
||||
fakeAppsClientset "github.com/openshift/client-go/apps/clientset/versioned/fake"
|
||||
fakeBuildClientset "github.com/openshift/client-go/build/clientset/versioned/fake"
|
||||
@@ -13,8 +16,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery/fake"
|
||||
fakeKubeClientset "k8s.io/client-go/kubernetes/fake"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// FakeClientset holds fake ClientSets
|
||||
@@ -40,6 +41,7 @@ func FakeNew() (*Client, *FakeClientset) {
|
||||
kc, fkcs := kclient.FakeNew()
|
||||
client.kubeClient = kc
|
||||
fkclientset.Kubernetes = fkcs.Kubernetes
|
||||
fkclientset.ServiceCatalogClientSet = fkcs.ServiceCatalogClientSet
|
||||
|
||||
fkclientset.AppsClientset = fakeAppsClientset.NewSimpleClientset()
|
||||
client.appsClient = fkclientset.AppsClientset.AppsV1()
|
||||
@@ -59,14 +61,11 @@ func FakeNew() (*Client, *FakeClientset) {
|
||||
fkclientset.BuildClientset = fakeBuildClientset.NewSimpleClientset()
|
||||
client.buildClient = fkclientset.BuildClientset.BuildV1()
|
||||
|
||||
fkclientset.ServiceCatalogClientSet = fakeServiceCatalogClientSet.NewSimpleClientset()
|
||||
client.serviceCatalogClient = fkclientset.ServiceCatalogClientSet.ServicecatalogV1beta1()
|
||||
|
||||
if os.Getenv("KUBERNETES") != "true" {
|
||||
client.SetDiscoveryInterface(fakeDiscoveryWithRoute)
|
||||
client.SetDiscoveryInterface(fakeDiscoveryWithDeploymentConfig)
|
||||
client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithRoute)
|
||||
client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithDeploymentConfig)
|
||||
} else {
|
||||
client.SetDiscoveryInterface(&fakeDiscovery{
|
||||
client.GetKubeClient().SetDiscoveryInterface(&fakeDiscovery{
|
||||
resourceMap: map[string]*resourceMapEntry{},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
// IsImageStreamSupported checks if imagestream resource type is present on the cluster
|
||||
func (c *Client) IsImageStreamSupported() (bool, error) {
|
||||
|
||||
return c.isResourceSupported("image.openshift.io", "v1", "imagestreams")
|
||||
return c.GetKubeClient().IsResourceSupported("image.openshift.io", "v1", "imagestreams")
|
||||
}
|
||||
|
||||
// GetImageStream returns the imagestream using image details like imageNS, imageName and imageTag
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -22,7 +21,6 @@ import (
|
||||
"github.com/openshift/odo/pkg/util"
|
||||
|
||||
// api clientsets
|
||||
servicecatalogclienset "github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/typed/servicecatalog/v1beta1"
|
||||
appsclientset "github.com/openshift/client-go/apps/clientset/versioned/typed/apps/v1"
|
||||
buildclientset "github.com/openshift/client-go/build/clientset/versioned/typed/build/v1"
|
||||
imageclientset "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1"
|
||||
@@ -31,19 +29,14 @@ import (
|
||||
userclientset "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1"
|
||||
|
||||
// api resource types
|
||||
scv1beta1 "github.com/kubernetes-sigs/service-catalog/pkg/apis/servicecatalog/v1beta1"
|
||||
appsv1 "github.com/openshift/api/apps/v1"
|
||||
imagev1 "github.com/openshift/api/image/v1"
|
||||
oauthv1client "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
@@ -171,22 +164,15 @@ odo login https://mycluster.mydomain.com
|
||||
`
|
||||
|
||||
type Client struct {
|
||||
kubeClient *kclient.Client
|
||||
imageClient imageclientset.ImageV1Interface
|
||||
appsClient appsclientset.AppsV1Interface
|
||||
buildClient buildclientset.BuildV1Interface
|
||||
projectClient projectclientset.ProjectV1Interface
|
||||
serviceCatalogClient servicecatalogclienset.ServicecatalogV1beta1Interface
|
||||
routeClient routeclientset.RouteV1Interface
|
||||
userClient userclientset.UserV1Interface
|
||||
KubeConfig clientcmd.ClientConfig
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
Namespace string
|
||||
supportedResources map[string]bool
|
||||
}
|
||||
|
||||
func (c *Client) SetDiscoveryInterface(client discovery.DiscoveryInterface) {
|
||||
c.discoveryClient = client
|
||||
kubeClient *kclient.Client
|
||||
imageClient imageclientset.ImageV1Interface
|
||||
appsClient appsclientset.AppsV1Interface
|
||||
buildClient buildclientset.BuildV1Interface
|
||||
projectClient projectclientset.ProjectV1Interface
|
||||
routeClient routeclientset.RouteV1Interface
|
||||
userClient userclientset.UserV1Interface
|
||||
KubeConfig clientcmd.ClientConfig
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// New creates a new client
|
||||
@@ -223,11 +209,6 @@ func New() (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.serviceCatalogClient, err = servicecatalogclienset.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.projectClient, err = projectclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -243,11 +224,6 @@ func New() (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.discoveryClient, err = discovery.NewDiscoveryClientForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.Namespace, _, err = client.KubeConfig.Namespace()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1140,195 +1116,6 @@ func (c *Client) WaitForComponentDeletion(selector string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteServiceInstance takes labels as a input and based on it, deletes respective service instance
|
||||
func (c *Client) DeleteServiceInstance(labels map[string]string) error {
|
||||
klog.V(3).Infof("Deleting Service Instance")
|
||||
|
||||
// convert labels to selector
|
||||
selector := util.ConvertLabelsToSelector(labels)
|
||||
klog.V(3).Infof("Selectors used for deletion: %s", selector)
|
||||
|
||||
// Listing out serviceInstance because `DeleteCollection` method don't work on serviceInstance
|
||||
serviceInstances, err := c.GetServiceInstanceList(selector)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to list service instance")
|
||||
}
|
||||
|
||||
// Iterating over serviceInstance List and deleting one by one
|
||||
for _, serviceInstance := range serviceInstances {
|
||||
// we need to delete the ServiceBinding before deleting the ServiceInstance
|
||||
err = c.serviceCatalogClient.ServiceBindings(c.Namespace).Delete(serviceInstance.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete serviceBinding")
|
||||
}
|
||||
// now we perform the actual deletion
|
||||
err = c.serviceCatalogClient.ServiceInstances(c.Namespace).Delete(serviceInstance.Name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete serviceInstance")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServiceInstanceLabelValues get label values of given label from objects in project that match the selector
|
||||
func (c *Client) GetServiceInstanceLabelValues(label string, selector string) ([]string, error) {
|
||||
|
||||
// List ServiceInstance according to given selectors
|
||||
svcList, err := c.serviceCatalogClient.ServiceInstances(c.Namespace).List(metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list ServiceInstances")
|
||||
}
|
||||
|
||||
// Grab all the matched strings
|
||||
var values []string
|
||||
for _, elem := range svcList.Items {
|
||||
val, ok := elem.Labels[label]
|
||||
if ok {
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort alphabetically
|
||||
sort.Strings(values)
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// GetServiceInstanceList returns list service instances
|
||||
func (c *Client) GetServiceInstanceList(selector string) ([]scv1beta1.ServiceInstance, error) {
|
||||
// List ServiceInstance according to given selectors
|
||||
svcList, err := c.serviceCatalogClient.ServiceInstances(c.Namespace).List(metav1.ListOptions{LabelSelector: selector})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list ServiceInstances")
|
||||
}
|
||||
|
||||
return svcList.Items, nil
|
||||
}
|
||||
|
||||
// GetClusterServiceClasses queries the service service catalog to get available clusterServiceClasses
|
||||
func (c *Client) GetClusterServiceClasses() ([]scv1beta1.ClusterServiceClass, error) {
|
||||
classList, err := c.serviceCatalogClient.ClusterServiceClasses().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to list cluster service classes")
|
||||
}
|
||||
return classList.Items, nil
|
||||
}
|
||||
|
||||
// GetClusterServiceClass returns the required service class from the service name
|
||||
// serviceName is the name of the service
|
||||
// returns the required service class and the error
|
||||
func (c *Client) GetClusterServiceClass(serviceName string) (*scv1beta1.ClusterServiceClass, error) {
|
||||
opts := metav1.ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("spec.externalName", serviceName).String(),
|
||||
}
|
||||
searchResults, err := c.serviceCatalogClient.ClusterServiceClasses().List(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to search classes by name (%s)", err)
|
||||
}
|
||||
if len(searchResults.Items) == 0 {
|
||||
return nil, fmt.Errorf("class '%s' not found", serviceName)
|
||||
}
|
||||
if len(searchResults.Items) > 1 {
|
||||
return nil, fmt.Errorf("more than one matching class found for '%s'", serviceName)
|
||||
}
|
||||
return &searchResults.Items[0], nil
|
||||
}
|
||||
|
||||
// GetClusterPlansFromServiceName returns the plans associated with a service class
|
||||
// serviceName is the name (the actual id, NOT the external name) of the service class whose plans are required
|
||||
// returns array of ClusterServicePlans or error
|
||||
func (c *Client) GetClusterPlansFromServiceName(serviceName string) ([]scv1beta1.ClusterServicePlan, error) {
|
||||
opts := metav1.ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("spec.clusterServiceClassRef.name", serviceName).String(),
|
||||
}
|
||||
searchResults, err := c.serviceCatalogClient.ClusterServicePlans().List(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to search plans for service name '%s', (%s)", serviceName, err)
|
||||
}
|
||||
return searchResults.Items, nil
|
||||
}
|
||||
|
||||
// CreateServiceInstance creates service instance from service catalog
|
||||
func (c *Client) CreateServiceInstance(serviceName string, serviceType string, servicePlan string, parameters map[string]string, labels map[string]string) error {
|
||||
serviceInstanceParameters, err := serviceInstanceParameters(parameters)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create the service instance parameters")
|
||||
}
|
||||
|
||||
_, err = c.serviceCatalogClient.ServiceInstances(c.Namespace).Create(
|
||||
&scv1beta1.ServiceInstance{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ServiceInstance",
|
||||
APIVersion: "servicecatalog.k8s.io/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: serviceName,
|
||||
Namespace: c.Namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: scv1beta1.ServiceInstanceSpec{
|
||||
PlanReference: scv1beta1.PlanReference{
|
||||
ClusterServiceClassExternalName: serviceType,
|
||||
ClusterServicePlanExternalName: servicePlan,
|
||||
},
|
||||
Parameters: serviceInstanceParameters,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to create the service instance %s for the service type %s and plan %s", serviceName, serviceType, servicePlan)
|
||||
}
|
||||
|
||||
// Create the secret containing the parameters of the plan selected.
|
||||
err = c.CreateServiceBinding(serviceName, c.Namespace, labels)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to create the secret %s for the service instance", serviceName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateServiceBinding creates a ServiceBinding (essentially a secret) within the namespace of the
|
||||
// service instance created using the service's parameters.
|
||||
func (c *Client) CreateServiceBinding(bindingName string, namespace string, labels map[string]string) error {
|
||||
_, err := c.serviceCatalogClient.ServiceBindings(namespace).Create(
|
||||
&scv1beta1.ServiceBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bindingName,
|
||||
Namespace: namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: scv1beta1.ServiceBindingSpec{
|
||||
InstanceRef: scv1beta1.LocalObjectReference{
|
||||
Name: bindingName,
|
||||
},
|
||||
SecretName: bindingName,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Creation of the secret failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServiceBinding returns the ServiceBinding named serviceName in the namespace namespace
|
||||
func (c *Client) GetServiceBinding(serviceName string, namespace string) (*scv1beta1.ServiceBinding, error) {
|
||||
return c.serviceCatalogClient.ServiceBindings(namespace).Get(serviceName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// serviceInstanceParameters converts a map of variable assignments to a byte encoded json document,
|
||||
// which is what the ServiceCatalog API consumes.
|
||||
func serviceInstanceParameters(params map[string]string) (*runtime.RawExtension, error) {
|
||||
paramsJSON, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &runtime.RawExtension{Raw: paramsJSON}, nil
|
||||
}
|
||||
|
||||
// LinkSecret links a secret to the DeploymentConfig of a component
|
||||
func (c *Client) LinkSecret(secretName, componentName, applicationName string) error {
|
||||
|
||||
@@ -1377,52 +1164,6 @@ func (c *Client) UnlinkSecret(secretName, componentName, applicationName string)
|
||||
return c.patchDC(dcName, dcPatchProvider)
|
||||
}
|
||||
|
||||
// GetServiceClassesByCategory retrieves a map associating category name to ClusterServiceClasses matching the category
|
||||
func (c *Client) GetServiceClassesByCategory() (categories map[string][]scv1beta1.ClusterServiceClass, err error) {
|
||||
categories = make(map[string][]scv1beta1.ClusterServiceClass)
|
||||
classes, err := c.GetClusterServiceClasses()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Should we replicate the classification performed in
|
||||
// https://github.com/openshift/console/blob/master/frontend/public/components/catalog/catalog-items.jsx?
|
||||
for _, class := range classes {
|
||||
tags := class.Spec.Tags
|
||||
category := "other"
|
||||
if len(tags) > 0 && len(tags[0]) > 0 {
|
||||
category = tags[0]
|
||||
}
|
||||
categories[category] = append(categories[category], class)
|
||||
}
|
||||
|
||||
return categories, err
|
||||
}
|
||||
|
||||
// GetMatchingPlans retrieves a map associating service plan name to service plan instance associated with the specified service
|
||||
// class
|
||||
func (c *Client) GetMatchingPlans(class scv1beta1.ClusterServiceClass) (plans map[string]scv1beta1.ClusterServicePlan, err error) {
|
||||
planList, err := c.serviceCatalogClient.ClusterServicePlans().List(metav1.ListOptions{
|
||||
FieldSelector: "spec.clusterServiceClassRef.name==" + class.Spec.ExternalID,
|
||||
})
|
||||
|
||||
plans = make(map[string]scv1beta1.ClusterServicePlan)
|
||||
for _, v := range planList.Items {
|
||||
plans[v.Spec.ExternalName] = v
|
||||
}
|
||||
return plans, err
|
||||
}
|
||||
|
||||
// GetAllClusterServicePlans returns list of available plans
|
||||
func (c *Client) GetAllClusterServicePlans() ([]scv1beta1.ClusterServicePlan, error) {
|
||||
planList, err := c.serviceCatalogClient.ClusterServicePlans().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get cluster service plan")
|
||||
}
|
||||
|
||||
return planList.Items, nil
|
||||
}
|
||||
|
||||
// ServerInfo contains the fields that contain the server's information like
|
||||
// address, OpenShift and Kubernetes versions
|
||||
type ServerInfo struct {
|
||||
@@ -1651,16 +1392,6 @@ func isSubDir(baseDir, otherDir string) bool {
|
||||
return matches
|
||||
}
|
||||
|
||||
// IsSBRSupported checks if resource of type service binding request present on the cluster
|
||||
func (c *Client) IsSBRSupported() (bool, error) {
|
||||
return c.isResourceSupported("apps.openshift.io", "v1alpha1", "servicebindingrequests")
|
||||
}
|
||||
|
||||
// IsCSVSupported checks if resource of type service binding request present on the cluster
|
||||
func (c *Client) IsCSVSupported() (bool, error) {
|
||||
return c.isResourceSupported("operators.coreos.com", "v1alpha1", "clusterserviceversions")
|
||||
}
|
||||
|
||||
// GenerateOwnerReference generates an ownerReference which can then be set as
|
||||
// owner for various OpenShift objects and ensure that when the owner object is
|
||||
// deleted from the cluster, all other objects are automatically removed by
|
||||
@@ -1676,32 +1407,3 @@ func GenerateOwnerReference(dc *appsv1.DeploymentConfig) metav1.OwnerReference {
|
||||
|
||||
return ownerReference
|
||||
}
|
||||
|
||||
func (c *Client) isResourceSupported(apiGroup, apiVersion, resourceName string) (bool, error) {
|
||||
if c.supportedResources == nil {
|
||||
c.supportedResources = make(map[string]bool, 7)
|
||||
}
|
||||
groupVersion := metav1.GroupVersion{Group: apiGroup, Version: apiVersion}.String()
|
||||
|
||||
supported, found := c.supportedResources[groupVersion]
|
||||
if !found {
|
||||
list, err := c.discoveryClient.ServerResourcesForGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
supported = false
|
||||
} else {
|
||||
// don't record, just attempt again next time in case it's a transient error
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
for _, resources := range list.APIResources {
|
||||
if resources.Name == resourceName {
|
||||
supported = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
c.supportedResources[groupVersion] = supported
|
||||
}
|
||||
return supported, nil
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -208,7 +208,7 @@ func (c *Client) CreateNewProject(projectName string, wait bool) error {
|
||||
|
||||
// IsProjectSupported checks if Project resource type is present on the cluster
|
||||
func (c *Client) IsProjectSupported() (bool, error) {
|
||||
return c.isResourceSupported("project.openshift.io", "v1", "projects")
|
||||
return c.GetKubeClient().IsResourceSupported("project.openshift.io", "v1", "projects")
|
||||
}
|
||||
|
||||
// GetCurrentProjectName returns the current project name
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
// IsRouteSupported checks if route resource type is present on the cluster
|
||||
func (c *Client) IsRouteSupported() (bool, error) {
|
||||
|
||||
return c.isResourceSupported("route.openshift.io", "v1", "routes")
|
||||
return c.GetKubeClient().IsResourceSupported("route.openshift.io", "v1", "routes")
|
||||
}
|
||||
|
||||
// GetRoute gets the route with the given name
|
||||
|
||||
@@ -84,7 +84,7 @@ func (o *commonLinkOptions) complete(name string, cmd *cobra.Command, args []str
|
||||
}
|
||||
|
||||
if o.csvSupport && o.Context.EnvSpecificInfo != nil {
|
||||
sboSupport, err := o.Client.IsSBRSupported()
|
||||
sboSupport, err := o.Client.GetKubeClient().IsSBRSupported()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func (o *commonLinkOptions) validate(wait bool) (err error) {
|
||||
if o.isTargetAService {
|
||||
// if there is a ServiceBinding, then that means there is already a secret (or there will be soon)
|
||||
// which we can link to
|
||||
_, err = o.Client.GetServiceBinding(o.secretName, o.Project)
|
||||
_, err = o.Client.GetKubeClient().GetServiceBinding(o.secretName, o.Project)
|
||||
if err != nil {
|
||||
return fmt.Errorf("The service was not created via odo. Please delete the service and recreate it using 'odo service create %s'", o.secretName)
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func (o *LinkOptions) Complete(name string, cmd *cobra.Command, args []string) (
|
||||
return err
|
||||
}
|
||||
|
||||
o.csvSupport, err = o.Client.IsCSVSupported()
|
||||
o.csvSupport, err = o.Client.GetKubeClient().IsCSVSupported()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (o *UnlinkOptions) Complete(name string, cmd *cobra.Command, args []string)
|
||||
return err
|
||||
}
|
||||
|
||||
o.csvSupport, err = o.Client.IsCSVSupported()
|
||||
o.csvSupport, err = o.Client.GetKubeClient().IsCSVSupported()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func (o *ServiceCreateOptions) Complete(name string, cmd *cobra.Command, args []
|
||||
}
|
||||
|
||||
if o.interactive {
|
||||
classesByCategory, err := client.GetServiceClassesByCategory()
|
||||
classesByCategory, err := client.GetKubeClient().ListServiceClassesByCategory()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to retrieve service classes: %v", err)
|
||||
}
|
||||
@@ -177,7 +177,7 @@ func (o *ServiceCreateOptions) Complete(name string, cmd *cobra.Command, args []
|
||||
|
||||
class, o.ServiceType = ui.SelectClassInteractively(classesByCategory)
|
||||
|
||||
plans, err := client.GetMatchingPlans(class)
|
||||
plans, err := client.GetKubeClient().ListMatchingPlans(class)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't retrieve plans for class %s: %v", class.GetExternalName(), err)
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func (o *ServiceCreateOptions) Validate() (err error) {
|
||||
}
|
||||
}
|
||||
// make sure the service type exists
|
||||
classPtr, err := o.Client.GetClusterServiceClass(o.ServiceType)
|
||||
classPtr, err := o.Client.GetKubeClient().GetClusterServiceClass(o.ServiceType)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create service because Service Catalog is not enabled in your cluster")
|
||||
}
|
||||
@@ -407,7 +407,7 @@ func (o *ServiceCreateOptions) Validate() (err error) {
|
||||
}
|
||||
|
||||
// check plan
|
||||
plans, err := o.Client.GetMatchingPlans(*classPtr)
|
||||
plans, err := o.Client.GetKubeClient().ListMatchingPlans(*classPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ var ServiceCompletionHandler = func(cmd *cobra.Command, args parsedArgs, context
|
||||
// ServiceClassCompletionHandler provides catalog service class name completion
|
||||
var ServiceClassCompletionHandler = func(cmd *cobra.Command, args parsedArgs, context *genericclioptions.Context) (completions []string) {
|
||||
completions = make([]string, 0)
|
||||
services, err := context.Client.GetClusterServiceClasses()
|
||||
services, err := context.Client.GetKubeClient().ListClusterServiceClasses()
|
||||
if err != nil {
|
||||
complete.Log("error retrieving services")
|
||||
return completions
|
||||
@@ -70,13 +70,13 @@ var ServicePlanCompletionHandler = func(cmd *cobra.Command, args parsedArgs, con
|
||||
|
||||
complete.Log(fmt.Sprintf("Using input: serviceName = %s", inputServiceName))
|
||||
|
||||
clusterServiceClass, err := context.Client.GetClusterServiceClass(inputServiceName)
|
||||
clusterServiceClass, err := context.Client.GetKubeClient().GetClusterServiceClass(inputServiceName)
|
||||
if err != nil {
|
||||
complete.Log("Error retrieving details of service")
|
||||
return completions
|
||||
}
|
||||
|
||||
servicePlans, err := context.Client.GetClusterPlansFromServiceName(clusterServiceClass.Name)
|
||||
servicePlans, err := context.Client.GetKubeClient().ListClusterServicePlansByServiceName(clusterServiceClass.Name)
|
||||
if err != nil {
|
||||
complete.Log("Error retrieving details of plans of service")
|
||||
return completions
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestCreate(t *testing.T) {
|
||||
|
||||
// The function we are testing
|
||||
context := genericclioptions.NewFakeContext(tt.projectName, "app", "cmp", client, kubeClient)
|
||||
context.Client.SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
context.Client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
|
||||
err := Create(context, tt.projectName, true)
|
||||
|
||||
@@ -294,7 +294,7 @@ func TestCreate(t *testing.T) {
|
||||
|
||||
// The function we are testing
|
||||
context := genericclioptions.NewFakeContext(tt.projectName, "app", "cmp", client, kclient)
|
||||
context.Client.SetDiscoveryInterface(fakeDiscoveryWithNamespace)
|
||||
context.Client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithNamespace)
|
||||
|
||||
err := Create(context, tt.projectName, true)
|
||||
|
||||
@@ -362,7 +362,7 @@ func TestDelete(t *testing.T) {
|
||||
kclient, _ := fakeDeleteKClient(tt.projectName, tt.deleteLast)
|
||||
|
||||
context := genericclioptions.NewFakeContext(tt.projectName, "app", "cmp", client, kclient)
|
||||
context.Client.SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
context.Client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
|
||||
// The function we are testing
|
||||
err := Delete(context, tt.projectName, tt.wait)
|
||||
@@ -388,7 +388,7 @@ func TestDelete(t *testing.T) {
|
||||
kubeClient, fakeKClientSet := fakeDeleteKClient(tt.projectName, tt.deleteLast)
|
||||
|
||||
context := genericclioptions.NewFakeContext(tt.projectName, "app", "cmp", client, kubeClient)
|
||||
context.Client.SetDiscoveryInterface(fakeDiscoveryWithNamespace)
|
||||
context.Client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithNamespace)
|
||||
|
||||
// The function we are testing
|
||||
err := Delete(context, tt.projectName, tt.wait)
|
||||
@@ -478,7 +478,7 @@ func TestList(t *testing.T) {
|
||||
|
||||
kubeClient, _ := kclient.FakeNew()
|
||||
|
||||
client.SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
client.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
|
||||
context := genericclioptions.NewFakeContext("test", "app", "cmp", client, kubeClient)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ func CreateService(client *occlient.Client, serviceName string, serviceType stri
|
||||
labels := componentlabels.GetLabels(serviceName, applicationName, true)
|
||||
// save service type as label
|
||||
labels[componentlabels.ComponentTypeLabel] = serviceType
|
||||
err := client.CreateServiceInstance(serviceName, serviceType, servicePlan, parameters, labels)
|
||||
err := client.GetKubeClient().CreateServiceInstance(serviceName, serviceType, servicePlan, parameters, labels)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create service instance")
|
||||
|
||||
@@ -70,7 +70,7 @@ func CreateService(client *occlient.Client, serviceName string, serviceType stri
|
||||
// able to find them, an error otherwise.
|
||||
func GetCSV(client *kclient.Client, crd map[string]interface{}) (string, olm.ClusterServiceVersion, error) {
|
||||
cr := crd["kind"].(string)
|
||||
csvs, err := client.GetClusterServiceVersionList()
|
||||
csvs, err := client.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return cr, olm.ClusterServiceVersion{}, err
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func CreateOperatorService(client *kclient.Client, group, version, resource stri
|
||||
func DeleteServiceAndUnlinkComponents(client *occlient.Client, serviceName string, applicationName string) error {
|
||||
// first we attempt to delete the service instance itself
|
||||
labels := componentlabels.GetLabels(serviceName, applicationName, false)
|
||||
err := client.DeleteServiceInstance(labels)
|
||||
err := client.GetKubeClient().DeleteServiceInstance(labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -195,7 +195,7 @@ func List(client *occlient.Client, applicationName string) (ServiceList, error)
|
||||
applicationSelector := util.ConvertLabelsToSelector(labels)
|
||||
|
||||
// get service instance list based on given selector
|
||||
serviceInstanceList, err := client.GetServiceInstanceList(applicationSelector)
|
||||
serviceInstanceList, err := client.GetKubeClient().ListServiceInstances(applicationSelector)
|
||||
if err != nil {
|
||||
return ServiceList{}, errors.Wrapf(err, "unable to list services")
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func ListOperatorServices(client *kclient.Client) ([]unstructured.Unstructured,
|
||||
klog.V(4).Info("Getting list of services")
|
||||
|
||||
// First let's get the list of all the operators in the namespace
|
||||
csvs, err := client.GetClusterServiceVersionList()
|
||||
csvs, err := client.ListClusterServiceVersions()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to list operator backed services")
|
||||
}
|
||||
@@ -577,7 +577,7 @@ func SplitServiceKindName(serviceName string) (string, string, error) {
|
||||
// the first parameter returned is the ServiceClass object
|
||||
// the second parameter returned is the array of ServicePlan associated with the service class
|
||||
func GetServiceClassAndPlans(client *occlient.Client, serviceName string) (ServiceClass, []ServicePlan, error) {
|
||||
result, err := client.GetClusterServiceClass(serviceName)
|
||||
result, err := client.GetKubeClient().GetClusterServiceClass(serviceName)
|
||||
if err != nil {
|
||||
return ServiceClass{}, nil, errors.Wrap(err, "unable to get the given service")
|
||||
}
|
||||
@@ -608,7 +608,7 @@ func GetServiceClassAndPlans(client *occlient.Client, serviceName string) (Servi
|
||||
}
|
||||
|
||||
// get the plans according to the service name
|
||||
planResults, err := client.GetClusterPlansFromServiceName(result.Name)
|
||||
planResults, err := client.GetKubeClient().ListClusterServicePlansByServiceName(result.Name)
|
||||
if err != nil {
|
||||
return ServiceClass{}, nil, errors.Wrap(err, "unable to get plans for the given service")
|
||||
}
|
||||
@@ -683,10 +683,10 @@ func isRequired(required []string, name string) bool {
|
||||
|
||||
// IsCSVSupported checks if the cluster supports resources of type ClusterServiceVersion
|
||||
func IsCSVSupported() (bool, error) {
|
||||
oclient, err := occlient.New()
|
||||
occlient, err := occlient.New()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return oclient.IsCSVSupported()
|
||||
return occlient.GetKubeClient().IsCSVSupported()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/onsi/gomega/matchers"
|
||||
"github.com/openshift/odo/pkg/testingutil"
|
||||
|
||||
@@ -163,7 +163,8 @@ func TestGetURLsForKubernetes(t *testing.T) {
|
||||
// Initializing the fake occlient
|
||||
fkoclient, fakeoclientSet := occlient.FakeNew()
|
||||
fkoclient.Namespace = "default"
|
||||
fkoclient.SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
fkoclient.SetKubeClient(fkclient)
|
||||
fkoclient.GetKubeClient().SetDiscoveryInterface(fakeDiscoveryWithProject)
|
||||
fkoclient.SetKubeClient(fkclient)
|
||||
|
||||
// Return the test's route list when requested
|
||||
|
||||
Reference in New Issue
Block a user