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

State support for Bundles #60

Merged
merged 1 commit into from
May 10, 2018

Conversation

maleck13
Copy link
Contributor

Apologies on delay with this. Here is a pass at the state support in the bundle lib. Please be brutal 😀 I have changes to the broker also but will wait until this is nailed down.

@shawn-hurley You mentioned making the PR against 0.1-release. Is that needed for this work as it is targeting the next release?

}

// NewExecutor - Creates a new Executor for running an APB.
func NewExecutor() Executor {
func NewExecutor(k8sClient k8.Interface, stateNS string) Executor {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure if this is the right approach. Feedback welcome

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 prefer to use the clients package to get the k8s client that way. That is how most things are behaving and I have examples of how to test that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is stateNS different than bundle.serviceInstance.Context.Namespace https://github.com/automationbroker/bundle-lib/blob/master/bundle/types.go#L140 ?

@maleck13
Copy link
Contributor Author

Not sure how to handle version checks here as state support wont be present until the following is present ansibleplaybookbundle/ansible-asb-modules#15 Does it mean a bump of the bundle / apb spec version and adding checks to the code for this version?

@jmrodri
Copy link
Contributor

jmrodri commented Apr 24, 2018

Can someone point me to the genesis of this PR? IRC logs, email, or issue? Trying to get an idea what it is we're trying to solve. I think I missed or probably just forgot :) Thanks.

@maleck13
Copy link
Contributor Author

maleck13 commented Apr 24, 2018

@jmrodri it is the bundle-lib part of https://github.com/openshift/ansible-service-broker/blob/master/docs/proposals/apb-state-support.md the apb state support proposal

Notes This is the first real thing I have done in the lib so struggled a little with understanding where the boundaries lay (ie what should be in the broker and what should be in the lib) If I am off on where the implementation of this should be, I'd be keen to know and understand more.

runtime/state.go Outdated
func (s *State) PrepareMount(name string) (*v1.VolumeMount, *v1.Volume, error) {
mount := &v1.VolumeMount{
Name: name,
MountPath: "/etc/apb/state",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

set this value in PodEnv also so that it can be read by the module

@jmrodri jmrodri self-requested a review April 24, 2018 14:00
@rthallisey rthallisey self-requested a review April 24, 2018 14:01
Copy link
Contributor

@shawn-hurley shawn-hurley left a comment

Choose a reason for hiding this comment

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

this is really LGTM!

I like the use of volume mounts.

@@ -38,7 +38,7 @@ func (e *executor) Bind(
go func() {
e.actionStarted()
executionContext, err := e.executeApb(
"bind", instance.Spec, instance.Context, parameters)
"bind", instance, parameters)
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm okay with it, I prefer only to pass in what is absolutely necessary but that is just a nitpick. I also understand this makes it easier to keep the signature stable as you require more things on the instance.

}

// NewExecutor - Creates a new Executor for running an APB.
func NewExecutor() Executor {
func NewExecutor(k8sClient k8.Interface, stateNS string) Executor {
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 prefer to use the clients package to get the k8s client that way. That is how most things are behaving and I have examples of how to test that.

runtime/state.go Outdated

// State handles the state for service bundles
type State struct {
Client k8.Interface
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 prefer this to use the clients package.

@@ -141,8 +155,10 @@ func (e *executor) updateDescription(newDescription string) {

// executeApb - Runs an APB Action with a provided set of inputs
func (e *executor) executeApb(
action string, spec *Spec, context *Context, p *Parameters,
action string, instance *ServiceInstance, p *Parameters,
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

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.

Overall decent job. Minor change requests. Thanks for the PR.

PrepareMount(name string) (*v1.VolumeMount, *v1.Volume, error)
StateIsPresent(name string) (bool, error)
Name(instanceID string) string
MasterNS() string
Copy link
Contributor

Choose a reason for hiding this comment

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

If NS is Namespace, I'd call the method MasterNamespace, using ns as a variable is okay, but for the method feels better to spell it out.

@@ -38,7 +38,7 @@ func (e *executor) Bind(
go func() {
e.actionStarted()
executionContext, err := e.executeApb(
"bind", instance.Spec, instance.Context, parameters)
"bind", instance, parameters)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm okay with it, I prefer only to pass in what is absolutely necessary but that is just a nitpick. I also understand this makes it easier to keep the signature stable as you require more things on the instance.

bundle/bind.go Outdated
@@ -62,6 +62,12 @@ func (e *executor) Bind(
}
}

// pod execution is complete so transfer state back
if err := e.stateManager.CopyState(executionContext.PodName, e.stateManager.Name(instance.ID.String()), executionContext.Namespace, e.stateManager.MasterNS()); 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.

This is one really really long line :) can we just break it on one of the parameters?

	if err := e.stateManager.CopyState(executionContext.PodName, e.stateManager.Name(instance.ID.String()),
		executionContext.Namespace, e.stateManager.MasterNS()); err != nil {

		e.actionFinishedWithError(err)
		return
	}

OR

	if err := e.stateManager.CopyState(executionContext.PodName,
		e.stateManager.Name(instance.ID.String()),
		executionContext.Namespace,
		e.stateManager.MasterNS()); err != nil {

		e.actionFinishedWithError(err)
		return
	}

executionContext, err := e.executeApb("deprovision", instance, instance.Parameters)
defer func() {
if err := e.stateManager.DeleteState(e.stateManager.Name(instance.ID.String())); err != nil {
log.Error("failed to delete state for instance "+instance.ID.String(), 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'd use the formatted version:

log.Errorf("failed to delete state for instance %s - %v", instance.ID.String(), err)

@@ -31,6 +31,7 @@ import (
"github.com/pborman/uuid"
log "github.com/sirupsen/logrus"
"k8s.io/api/core/v1"
k8 "k8s.io/client-go/kubernetes"
Copy link
Contributor

Choose a reason for hiding this comment

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

k8 feels weird, haven't we been doing k8s? or k8scli

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

runtime/state.go Outdated

// Name provides a consistent name for the state object
func (s *State) Name(id string) string {
return id + "-state"
Copy link
Contributor

Choose a reason for hiding this comment

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

this works, usually we do the return fmt.Sprintf("%s-state", id)

runtime/state.go Outdated
log.Info("state: checking is present")
if _, err := s.Client.CoreV1().ConfigMaps(s.targetNs).Get(stateName, metav1.GetOptions{}); err != nil {
if kerror.IsNotFound(err) {
log.Info("state: is not found ** ")
Copy link
Contributor

Choose a reason for hiding this comment

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

How often will this occur? Feels like this should be a debug statement not info.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep left in by accident there

runtime/state.go Outdated
return true, nil
}

// PrepareMount will prepare the voume definitions and mounts
Copy link
Contributor

Choose a reason for hiding this comment

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

typo in comment: voume -> volume

runtime/state.go Outdated

// DeleteState will remove the state object from the broker namespace
func (s *State) DeleteState(name string) error {
log.Info("state: deleting master state " + name + " in ns " + s.targetNs)
Copy link
Contributor

Choose a reason for hiding this comment

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

use the formatted version of info:

log.Infof("state: deleting master state %s in ns %s", name, s.targetNs)

runtime/state.go Outdated
type State struct {
Client k8.Interface
// this is the namespace where the master configs will be stored
targetNs string
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 prefer targetns or targetNS or even better nsTarget

@maleck13
Copy link
Contributor Author

@jmrodri @shawn-hurley ok thanks for feedback looks like we are happy with the approach. I will make the required changes and flesh out unit tests for the state module (didn't do this first as wanted to ensure I was heading in the right direction)

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.

Nice job.

}

// NewExecutor - Creates a new Executor for running an APB.
func NewExecutor() Executor {
func NewExecutor(k8sClient k8.Interface, stateNS string) Executor {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is stateNS different than bundle.serviceInstance.Context.Namespace https://github.com/automationbroker/bundle-lib/blob/master/bundle/types.go#L140 ?

@maleck13
Copy link
Contributor Author

@rthallisey stateNS is the where the master copy of the state will be stored. In our case the broker namespace. So it is a different namespace

@maleck13 maleck13 force-pushed the bundle-state-support branch 2 times, most recently from c6f0bc9 to a31958b Compare May 2, 2018 15:12
@maleck13
Copy link
Contributor Author

maleck13 commented May 2, 2018

addressed all requested changes. I will add a set of tests for the state manager. Note I also added a new env var to set the BUNDLE_STATE_LOCATION for use by the module

@shawn-hurley
Copy link
Contributor

@maleck13 So I was re-looking through this after the changes and I actually see 1 thing that should be changed.

We are trying to move all of the stuff that uses k8scli to the runtime, and therefore I think that State Manager should be moved to the runtime package, its interface embedded into the Runtime interface and the provider struct should embed a default runtime. I also think that allowing an override in the configuration should be added. Please ping me if you have any questions.

Sorry I didn't catch this the first time around.

@maleck13
Copy link
Contributor Author

maleck13 commented May 3, 2018

Is the idea here that a different StateManager could be provided externally when using the lib outside of the broker but we will provide a default implementation? I am ok making the change just trying to understand the reasoning. The actual concrete implementation of the interface is already in the runtime package limiting the k8scli to the runtime package.

This makes me wonder should the state type in the runtime package be exported, seems it should be internal right?

@shawn-hurley
Copy link
Contributor

shawn-hurley commented May 3, 2018

@maleck13

The idea is that the only way to interact with the runtime package is through the Provider. This Provider is just an implementation of the Runtime interface. We should not be adding a new way to interact with runtime than through the provider.

The idea is that if we have a bunch of sane defaults, but then if someone wants to change something they can. This will allow users of bundle lib who want to implement a new runtime can. I don't envision anyone doing this right at the moment but I do see future use cases that are not too far into the future.

@maleck13 maleck13 force-pushed the bundle-state-support branch 3 times, most recently from c1f2d72 to aa349d2 Compare May 8, 2018 13:48
@maleck13
Copy link
Contributor Author

maleck13 commented May 8, 2018

@shawn-hurley I believe I have made the changes you requested. Let me know if this what your were expecting.

@jmrodri I believe I have addressed your feedback

Copy link
Contributor

@shawn-hurley shawn-hurley left a comment

Choose a reason for hiding this comment

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

This a nit, but I would like to keep the same structure/layout that we have been using

}

// StateManager defines an interface for managing state created by service bundles
type StateManager interface {
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 move this interface into the state file. this would follow the pattern that we have used for ExtractedCredential

@shawn-hurley shawn-hurley changed the title wip state support for Bundles State support for Bundles May 8, 2018
runtime/state.go Outdated
import (
"fmt"

"github.com/apex/log"
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 this is a mistaken import. I believe it should be log "github.com/sirupsen/logrus"

Remove the apex log, and add the logrus UNDER the clients, like it looks below. This makes goimports happy and uses the correct logger.

import (
    "fmt"

    "github.com/automationbroker/bundle-lib/clients"
    log "github.com/sirupsen/logrus"
    "k8s.io/api/core/v1"
    kerror "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

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.

@maleck13 Wrong logger used in state.go, see the other comment above with the suggested fix. Then I will merge it tomorrow (Thursday). I validated it today. Great job.

fix import for log
@maleck13
Copy link
Contributor Author

@jmrodri Thanks. Good spot on the import. Once merged will we tag / release I will then make the needed updates to the broker

Copy link
Contributor

@dymurray dymurray left a comment

Choose a reason for hiding this comment

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

Looks great. This approach is going to make it much easier for APB developers to pass data between calls even outside of the cluster approach since it's just mounted files. Great job!

@jmrodri jmrodri merged commit 697a231 into automationbroker:master May 10, 2018
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

5 participants