-
Notifications
You must be signed in to change notification settings - Fork 244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for creating component from service catalog #413
Conversation
please add link to the issue |
9c919a6
to
9c58fa1
Compare
Fixes #266 |
Prerequisite to run/test this PR:
|
pkg/catalog/catalog.go
Outdated
@@ -9,55 +9,68 @@ import ( | |||
) | |||
|
|||
// List lists all the available component types | |||
func List(client *occlient.Client) ([]string, error) { | |||
func List(client *occlient.Client) (finalList map[string][]string, err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please don't use named return values. It makes it hard to read :-(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
pkg/catalog/catalog.go
Outdated
} | ||
|
||
return result, nil | ||
} | ||
|
||
// Exists returns true if the given component type is valid, false if not | ||
func Exists(client *occlient.Client, componentType string) (bool, error) { | ||
func Exists(client *occlient.Client, componentType string) (bool, error, string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment explaining what return values are. Especially new returned string
pkg/occlient/occlient.go
Outdated
func (c *Client) CreateServiceInstance(componentName string, componentType string, labels map[string]string, applicationName string, projectName string) error { | ||
// Patching Template with ODO specific labels | ||
labelPatch := fmt.Sprintf(`{"labels": {"app.kubernetes.io/component-name": "%s", "app.kubernetes.io/component-type": "%s", "app.kubernetes.io/name": "%s"}}`, componentName, componentType, applicationName) | ||
_, err := c.templateClient.Templates("openshift").Patch(componentType, types.StrategicMergePatchType, []byte(labelPatch)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
won't this permanently modify templates saved in openshift
namespace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if service is from some other broker than openshift template broker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't get second question
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is called CreateServiceInstance, but is using OpenShift templates.
It is really confusing :-(
There can be multiple different Service brokers in Service Catalog.
pkg/occlient/occlient.go
Outdated
@@ -892,6 +899,21 @@ func (c *Client) GetClusterServiceClasses() ([]scv1beta1.ClusterServiceClass, er | |||
return classList.Items, nil | |||
} | |||
|
|||
func (c *Client) CreateServiceInstance(componentName string, componentType string, labels map[string]string, applicationName string, projectName string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are in occlient
package it should have componentName
or componentType
variables
pkg/occlient/occlient.go
Outdated
|
||
"github.com/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
types "k8s.io/apimachinery/pkg/types" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imports should be logically grouped together
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was auto goimports in goland :(
cmd/create.go
Outdated
@@ -127,6 +127,10 @@ A full list of component types that can be deployed is available using: 'odo com | |||
checkError(err, fmt.Sprintf("failed to push component: %v", componentName)) | |||
|
|||
fmt.Printf("Component '%s' was created.\n", componentName) | |||
} else if len(catalogType) != 0 && catalogType == "template" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if len(catalogType) != 0
and catalogType
is different from "template"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other catalog type is imagestream
so other conditions will handle that
It breaks for everything if cluster doesn't have service catalog.
|
why is 3.7.1 required?
why is centos required? |
@kadel , service catalog & ansible service broker addons works well with this version |
pkg/occlient/occlient.go
Outdated
return errors.Wrap(err, "unable to patch template") | ||
} | ||
// Creating Service Instance | ||
_, err = c.serviceCatalogClient.ServiceInstances(projectName).Create(&scv1beta1.ServiceInstance{metav1.TypeMeta{Kind: "ServiceInstance", APIVersion: "servicecatalog.k8s.io/v1beta1"}, metav1.ObjectMeta{Finalizers: []string{"kubernetes-incubator/service-catalog"}, Name: componentName, Namespace: "myproject", Labels: labels}, scv1beta1.ServiceInstanceSpec{UserInfo: &scv1beta1.UserInfo{Username: "developer"}, PlanReference: scv1beta1.PlanReference{ClusterServiceClassExternalName: componentType}}, scv1beta1.ServiceInstanceStatus{}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add break ServiceInstance
struct to multiple lines,it is hard to see what is going on there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are passing labels there. If you can pass labels, why is the patching needed in the previous step?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh I am gonna remove this label, I was just playing around it. this label will only apply to serviceinstance
. But we want label on every resource that will be created for example, deploymentconfig, services, routes
pkg/occlient/occlient.go
Outdated
@@ -892,6 +899,21 @@ func (c *Client) GetClusterServiceClasses() ([]scv1beta1.ClusterServiceClass, er | |||
return classList.Items, nil | |||
} | |||
|
|||
func (c *Client) CreateServiceInstance(componentName string, componentType string, labels map[string]string, applicationName string, projectName string) error { | |||
// Patching Template with ODO specific labels | |||
labelPatch := fmt.Sprintf(`{"labels": {"app.kubernetes.io/component-name": "%s", "app.kubernetes.io/component-type": "%s", "app.kubernetes.io/name": "%s"}}`, componentName, componentType, applicationName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please break this to multiple lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not able to create from catalog
▶ odo create jenkins-persistent
User "developer" cannot patch templates.template.openshift.io in the namespace "openshift": User "developer" cannot "patch" "templates.template.openshift.io" with name "jenkins-persistent" in project "openshift" (patch templates.template.openshift.io jenkins-persistent)
ab1de12
to
1153b25
Compare
cmd/service.go
Outdated
}, | ||
} | ||
|
||
//var serviceCatalogCmd = &cobra.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why Commented out?
I tried this based on #413 (comment) but doesn't seem to be working
Commands to test:
|
I would add to the list of tests the ones for a component, as the possible components that can be used are from the catalog.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pleas also add e2e tests
I tried to setup minishift with service catalog enabled but I see consistent failures with it :
- sometimes at the time of pulling minishift-centos iso
- sometimes at the time of pulling origin container image
- sometimes at time of starting openshift cluster
So, couldn't verify the PR
Run: func(cmd *cobra.Command, args []string) { | ||
client := getOcClient() | ||
catalogList, err := svc.ListCatalog(client) | ||
checkError(err, "unable to list services because Service Catalog is not enabled in your cluster") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it better to only say "unable to list services" and leave the other part of the error to come from openshift?
If there's a network error for example, I feel it might be misleading to suggest "Service Catalog is not enabled in your cluster"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our user will not understand openshift error (so we have to simplify it)
if there is network error, process will not reach till this stage :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm so the occlient creation would fail is what you are saying right? So can there be any other error like permissions/authorisation for using service catalog issue ?
If not please ignore this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this error message is okay for this situation
pkg/occlient/occlient.go
Outdated
// Service Instance | ||
glog.V(4).Infof("Deleting Service Instance") | ||
// Listing out serviceInstance because `DeleteCollection` method don't work on serviceInstance | ||
svcCatList, err := c.serviceCatalogClient.ServiceInstances(c.namespace).List(metav1.ListOptions{LabelSelector: selector}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different from https://github.com/redhat-developer/odo/pull/413/files#diff-6025e9b620e9321c03c11bf29e5c4dbdR1204 can it be reused here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done 👍
pkg/occlient/occlient.go
Outdated
return values, nil | ||
} | ||
|
||
// GetServiceInstanceList returns list service instances | ||
func (c *Client) GetServiceInstanceList(project string, selector string) ([]scv1beta1.ServiceInstance, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we call project as namespace ?
Just trying to avoid multiple terminologies for same thing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fine, I guess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
pkg/occlient/occlient_test.go
Outdated
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 !reflect.DeepEqual(createdServiceInstance.Name, tt.args.componentName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have just == comparisons for basic types ?
@@ -0,0 +1,133 @@ | |||
package service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
Doesn't look like a lot of validations in this file
But, may be for code-coverage :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
But may be you need to add unit test for pkg/service/service.go + also e2e tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
odo service create mysql-persistent
I suppose that you assume here that mysql-persistent
corresponds to the class of the service to be used to create a ServiceInstance ? How will the user be able to define the serviceInstance name to be used ? How will it be possible to define the parameters of the service (e.g. DB_*** parameters) ? @surajnarwade
pkg/occlient/occlient.go
Outdated
func (c *Client) GetClusterServiceClasses() ([]scv1beta1.ClusterServiceClass, error) { | ||
classList, err := c.serviceCatalogClient.ClusterServiceClasses().List(metav1.ListOptions{}) | ||
// TODO: Remove `FieldSelector` from ListOptions when we are confident with Ansible Service Broker | ||
classList, err := c.serviceCatalogClient.ClusterServiceClasses().List(metav1.ListOptions{FieldSelector: "spec.clusterServiceBrokerName=template-service-broker"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OSB is working pretty well for me
minishift v1.23.0+91235ee
minishift config set memory 6G
minishift config set openshift-version v3.10.0
minsishift addons enable admin-user
MINISHIFT_ENABLE_EXPERIMENTAL=y minishift start --extra-clusterup-flags="--enable=*,service-catalog,automation-service-broker"
if err != nil { | ||
return nil, errors.Wrap(err, "unable to list cluster service classes") | ||
} | ||
return classList.Items, nil | ||
} | ||
|
||
// CreateServiceInstance creates service instance from service catalog | ||
func (c *Client) CreateServiceInstance(componentName string, componentType string, labels map[string]string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that your createServiceInstance function doesn't include the spec.parameters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically every service will require some configuration, so user will need to In reality this will get horribly complex because:
This task it's turning more complex than initially envisioned for the way how servicecatalog API works. I would defer the work or think that we should revisit this in the near future with many changes. |
@jorgemoralespou , @cmoulliard : This PR just demonstrate that we can create the basic service from service catalog. Also, this PR does not conflict with odo's core functionality. Upon merging this PR: Next possible steps are:
WDYT ? |
I agree with you. The flow requires that we do :
|
@surajnarwade sounds good to me.
odo catalog list service
odo catalog describe service
odo service create -p param1=value1 -p param2=value2
odo link |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create a bug to track e2e test and docs only so that we don't lose track of it and link back here
this command will work for service containing string's fields but when json or yaml content is required (as this is the case for the keycloak's service), then such info should be defined within a config's application file (MANIFEST, odo-application.yaml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@jorgemoralespou @cmoulliard @cdrage , if you all agree, then @anmolbabu can merge this PR |
@surajnarwade I can't vote as I can't read the implementation. To me looks good and as part of the discussion we can create follow up issues. |
Merging based on previous acks but @surajnarwade please log issue to add documentation and e2e tests |
As per our discussion, I have also raised #678 please take it up on priority @surajnarwade |
@@ -21,15 +22,26 @@ var catalogCmd = &cobra.Command{ | |||
|
|||
var catalogListCmd = &cobra.Command{ | |||
Use: "list", | |||
Short: "List all available component & service types.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should change the sentence so both commands are similar:
Currently it is:
Available Commands:
components List all available component types.
services Lists all the services from service catalog
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe: Lists all components available
and Lists all services available
?
Example: ` # List all services | ||
odo catalog list services | ||
|
||
# Search for a supported services |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Search for a supported service
|
||
If service name is not provided, service type value will be used. | ||
|
||
A full list of service types that can be deployed is available using: 'odo service catalog'`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are available
exists, err = svc.SvcExists(client, serviceName, applicationName, projectName) | ||
checkError(err, "") | ||
if exists { | ||
fmt.Printf("Service with the name %s already exists in the current application.\n", serviceName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove with
Use: "delete <service_name>", | ||
Short: "Delete an existing service", | ||
Long: "Delete an existing service", | ||
Example: ` # Delete service named 'mysql-persistent' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete the service
serviceCmd.SetUsageTemplate(cmdUsageTemplate) | ||
serviceCmd.AddCommand(serviceCreateCmd) | ||
serviceCmd.AddCommand(serviceDeleteCmd) | ||
//serviceCmd.AddCommand(serviceCatalogCmd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove commented out code
glog.V(4).Infof("Selectors used for deletion: %s", selector) | ||
// Service Instance | ||
glog.V(4).Infof("Deleting Service Instance") | ||
// Listing out serviceInstance because `DeleteCollection` method don't work on serviceInstance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add some newline / spacing :( makes everything a bit cluttered up here.
// convert labels to selector | ||
selector := util.ConvertLabelsToSelector(labels) | ||
glog.V(4).Infof("Selectors used for deletion: %s", selector) | ||
// Service Instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really need this comment
if err != nil { | ||
return nil, errors.Wrap(err, "unable to list cluster service classes") | ||
} | ||
return classList.Items, nil | ||
} | ||
|
||
// CreateServiceInstance creates service instance from service catalog | ||
func (c *Client) CreateServiceInstance(componentName string, componentType string, labels map[string]string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//since, service is associated with application, it consist of application label as well | ||
// which we can give as a selector | ||
applicationSelector := util.ConvertLabelsToSelector(labels) | ||
// get service instance list based on given selector |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add newline / spacing
Fixes #266
Signed-off-by: Suraj Narwade surajnarwade353@gmail.com
This PR adds the support for creating services from service catalog. for this support, we have used
client from kubernetes-incubator/service-catalog.
Currently, we are supporting template service broker only. In future, we will add support for
other brokers as well.
We have added entire new command set for this purpose.