Skip to content
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

Adding ability to pass credentials to bind and unbind actions. #302

Merged
merged 8 commits into from Aug 4, 2017

Conversation

shawn-hurley
Copy link
Contributor

Implementation for #293. Just getting thoughts down. This allows you test with the the test apps and APB
https://github.com/shawn-hurley/rhscl-postgresql-apb
https://github.com/shawn-hurley/bottle-todo-demo

@shawn-hurley shawn-hurley force-pushed the bind-wkflw branch 2 times, most recently from 0a1443c to 4e61fc8 Compare July 28, 2017 12:59
@shawn-hurley
Copy link
Contributor Author

shawn-hurley commented Jul 28, 2017

TESTING New Workflow

Needs to be run on a machine that spins up containers quickly

Use:
APB - https://github.com/shawn-hurley/rhscl-postgresql-apb
Application - https://github.com/shawn-hurley/bottle-todo-demo use S2I to build to pod.

The test APB will give you the ability to select which workflow you would like the APB to do.

The options are multiple or single. multiple will tell the APB to generate a new user for each bind. The credentials created at provision time should be for the postgres user. The single option will tell the APB to generate a new user, and then use that user for subsequent bind requests.

Test 1

Launch catasb point to broker built with the changes. Leave launch_apb_on_bind to false.

  • Use the media-wiki and RHSCL postgres images to test that the original workflow still works.
  • deploy postgresql apb and media-wiki apb
  • should be able to bind mediawiki-apb and postgres-apb
  • unbind should delete the secret and remove the pod preset

Test 2

Launch catasb point to broker built with the changes. set launch_apb_on_bind to true.

  • Use test postgres-apb and test application
  • deploy S2I python application and test APB Postgresql. Select the multiple user option
  • application should display no database connection.
  • Create a binding between application and PostgreSQL.
  • APB should launch.
  • New generated user and password should be created in etcd /extracted_credentials directory with key of binding id.
  • the secret should be created with new user and password.
  • pod preset should be created with new user and password.
  • redeploy application and reload application page. Then navigate to /todo
  • Should see data, can update tasks. You can create new todo's by navigating to /new and creating one
  • Choose to delete the binding
  • Should see APB launch and should see the user removed from the database.
  • Extracted Credentials should be deleted

Test 3

Launch catasb point to broker built with the changes. set launch_apb_on_bind to true.

  • Use test postgres-apb and test application
  • deploy S2I python application and test APB Postgresql. Select the single user option
  • application should display no database connection.
  • Create a binding between application and postgresql.
  • APB should launch.
  • same user and password should be created in etcd /extracted_credentials directory with key of binding id.
  • secret should be created with new user and password.
  • pod preset should be created with new user and password.
  • redeploy application and reload application page. Then navigate to /todo
  • Should see data, can update tasks. You can create new todo's by navigating to /new and creating one
  • Choose to delete the binding
  • Should see APB launch and should see the user removed from the database.
  • Extracted Credentials should be deleted

PLEASE NOTE: that if it takes too long for the APB to run the service catalog will fail to get the data and will not create the secret. This is due to lack of async binding support.

@shawn-hurley shawn-hurley changed the title [WIP] Adding ability to pass credentials to bind and unbind actions. Adding ability to pass credentials to bind and unbind actions. Jul 28, 2017
@shawn-hurley
Copy link
Contributor Author

1 similar comment
@shawn-hurley
Copy link
Contributor Author

Copy link
Contributor

@rthallisey rthallisey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a simple nit

@@ -678,6 +677,9 @@ func (a AnsibleBroker) Bind(instanceUUID uuid.UUID, bindingUUID uuid.UUID, req *
params[planParameterKey] = req.PlanID

// Create a BindingInstance with a reference to the serviceinstance.
//
// Create a BindingInstance with a reference to the serviceinstance.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like an extra comment

@rthallisey
Copy link
Contributor

LGTM. I haven't tested yet.

Copy link
Contributor

@jmrodri jmrodri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically some formatting changes.

@@ -100,6 +100,8 @@ The broker config section will tell the broker what functionality should be enab
and disabled. It will also tell the broker where to find files on disk that will
enable the full functionality.

*Note: with the absence of async bind, setting launch_apb_on_bind to true can cause the bind action to timeout and will span a retry. The broker will handle with with 409 Conflicts because it is the same bind request with different parameters.*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good note.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

log.Notice("============================================================")
log.Notice(" UNBINDING ")
log.Notice("============================================================")

// podName, err
_, err := ExecuteApb(
"unbind", clusterConfig, instance.Spec,
instance.Context, instance.Parameters, log,
instance.Context, parameters, log,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@@ -10,15 +10,15 @@ import (
// github.com/op/go-logging, which is used all over the broker
// Maybe apb defines its own interface and accepts that optionally
// Little looser, but still not great
func Unbind(instance *ServiceInstance, clusterConfig ClusterConfig, log *logging.Logger) error {
func Unbind(instance *ServiceInstance, clusterConfig ClusterConfig, log *logging.Logger, parameters *Parameters) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to use the same order as Bind:

func Bind(
    instance *ServiceInstance,
    parameters *Parameters,
    clusterConfig ClusterConfig,
    log *logging.Logger,
) (string, *ExtractedCredentials, error) {

@@ -751,31 +734,28 @@ func (a AnsibleBroker) Bind(instanceUUID uuid.UUID, bindingUUID uuid.UUID, req *
return nil, err
}
} else {
a.log.Warning("Broker configured to *NOT* launch and run APB bind")
a.log.Warningf("Broker configured to *NOT* launch and run APB bind")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like using the f version, but do we need to change it if we're not passing in variables. I think it's ok, but I wouldn't change them unless we're passing in a variable.

a.log.Error("No extracted credentials found from provision or bind")
a.log.Error("Instance ID: %s", instanceUUID.String())
a.log.Errorf("No extracted credentials found from provision or bind instance ID: %s",
instanceUUID.String())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a prime example of requiring the change as we are passing the variable in.

return nil, err
if bindExtCreds != nil {
err = a.dao.DeleteExtractedCredentials(bindingUUID.String())
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible we could leak bindings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 4 cases on 777 we will attempt to get the credentials.

  1. etcd/dao error that is something other than creds could not be found
  • we return the error and error out to service catalog which will re-try.
  1. etcd/dao error that is creds not found
  • we don't need to attempt to delete anything that is not there
  1. etcd/dao finds creds and delete succeeds
  • happy path
  1. etcd/dao finds creds and delete creds fails.
  • we will error out which will bubble up to service catalog which will re-try.

Can you think of another path?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're covered by service cat retries.

resp, err := h.broker.Unbind(instanceUUID, bindingUUID, planID)

if errors.IsNotFound(err) {
writeResponse(w, http.StatusGone, resp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason we deleted the blank lines? they were single lines which isn't egregious and I think it makes it more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No good reason, I will add it back

@@ -113,7 +113,7 @@ echo -e "Wrote \n${BROKER_SVC_ACCT_TOKEN}\n to: ${SVC_ACCT_TOKEN_FILE}\n"
###
# Fetch the tls.crt for the asb deployment
###
TLS_CRT_DATA=`oc get secret asb-tls -o jsonpath='{ .data.tls\.crt }'`
TLS_CRT_DATA=`oc get secret asb-tls -o jsonpath='{ .data.tls\.crt}'`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this intentional? we should be consistent and we currently aren't. I would not make this change as part of this PR. Here are other ones in the same file:

[jesusr@speed3 ansible-service-broker{authimpl}]$ grep jsonpath scripts/prep_local_devel_env.sh 
BROKER_SVC_ACCT_SECRET_NAME=`oc get serviceaccount asb -n ansible-service-broker -o jsonpath='{.secrets[0].name}'`
SVC_ACCT_CA_CRT_DATA=`oc get secret ${BROKER_SVC_ACCT_SECRET_NAME} -n ${ASB_PROJECT} -o jsonpath='{ .data.service-ca\.crt }'`
BROKER_SVC_ACCT_TOKEN=`oc get secret ${BROKER_SVC_ACCT_SECRET_NAME} -n ${ASB_PROJECT} -o jsonpath='{ .data.token }'`
TLS_CRT_DATA=`oc get secret asb-tls -o jsonpath='{ .data.tls\.crt }'`
TLS_KEY_DATA=`oc get secret asb-tls -o jsonpath='{ .data.tls\.key }'`
etcd_route=`oc get route asb-etcd -n ${ASB_PROJECT} -o=jsonpath=\'\{.spec.host\}\'`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to fix this and they you submitted the patch, I must have chosen the wrong one on the merge. I will add the space back my fault.

}

err = a.dao.DeleteBindInstance(bindingUUID.String())
if err != nil {
return nil, err
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have left this blank line as well.

params[provisionCredentialsKey] = provExtCreds.Credentials
if bindExtCreds != nil {
params[bindCredentialsKey] = bindExtCreds.Credentials
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall this looks good.

Copy link
Contributor

@eriknelson eriknelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Questions around APBs that return only provision credentials, or only bind credentials. Unbind is written expecting both to be present
  • Return err if serviceInstance is not found on unbind
  • Waning on no launch APB in unbind
  • Spoke with @shawn-hurley in IRC, thought it was a little weird to key into /extracted_credentials sourcing from two different places (instance_ids and binding_ids). Would be useful to know where they came from, he came up with an additional namespace: /extracted_credentials/prov & /extracted_credentials/bind

Overall I like this a lot. Solves a problem we've been wondering about in the past: how should the broker deal with two different sets of binding credentials? Answer: it shouldn't. Delegate that decision to the APBs and remain dumb.

@@ -100,6 +100,8 @@ The broker config section will tell the broker what functionality should be enab
and disabled. It will also tell the broker where to find files on disk that will
enable the full functionality.

*Note: with the absence of async bind, setting launch_apb_on_bind to true can cause the bind action to timeout and will span a retry. The broker will handle with with 409 Conflicts because it is the same bind request with different parameters.*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

a.log.Errorf("Could not persist extracted credentials - %v", err)
return nil, err
}
return &BindResponse{Credentials: bindExtCreds.Credentials}, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better than our original thinking. Keeps the broker dumb and delegates the responsibility for what needs to be in the bind response entirely to the APBs, while still allowing them to include provision credentials since they're passed in as a param during the bind action. Nice job 👍

@@ -789,14 +769,41 @@ func (a AnsibleBroker) Unbind(
return nil, errors.New(errMsg)
}

params := make(apb.Parameters)
provExtCreds, err := a.dao.GetExtractedCredentials(instanceUUID.String())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads like any APB that has been bound is required to have credentials stashed for both provision and bind. What if I have a bindable APB that only returns credentials during a bind operation? This will error out unless the provision object is some kind of empty object, which I also don't think we should be doing.

params[provisionCredentialsKey] = provExtCreds.Credentials
if bindExtCreds != nil {
params[bindCredentialsKey] = bindExtCreds.Credentials
}
serviceInstance, err := a.getServiceInstance(instanceUUID)
if err != nil {
a.log.Debugf("Service instance with id %s does not exist", instanceUUID.String())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticing this; if this branch is taken it's a hard error and we need to return w/ error code. We'll potentially hit an NPE continuing with a nil serviceInstance.

This would also be quite bad; if someone is trying to unbind from a service that we don't know exists, we're in a real corrupt state.

if err != nil {
return nil, err
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a warning to indicate the APB was not run in the logs, making sure we are clear that nothing was launched in case somebody expects otherwise.

return nil, err
if bindExtCreds != nil {
err = a.dao.DeleteExtractedCredentials(bindingUUID.String())
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're covered by service cat retries.

but should still handle bind and unbind.
@eriknelson eriknelson merged commit f569628 into openshift:master Aug 4, 2017
jianzhangbjz pushed a commit to jianzhangbjz/ansible-service-broker that referenced this pull request May 17, 2018
…hift#302)

* adding ability to pass credentials to bind and unbind actions.

* fixing unbind. and updating name of params to spec compliant

* update style, making note of issues with lack of async support

* config fix up

* removing duplicate comment.

* addressing comments

* addressing issues where prov credentials not sent.

but should still handle bind and unbind.

* adding warning for not finding any credentials at unbind
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants