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

Breakup all the Broker Clients into a clients pkg #222

Merged
merged 4 commits into from Jun 26, 2017

Conversation

rthallisey
Copy link
Contributor

@rthallisey rthallisey commented Jun 22, 2017

Refactor the broker clients into their own package.

Right now, we have clients scattered around in different packages. This is causing the clients to be initialized on each action (bind, unbind, etc...) as well as other places because the clients aren't available for use.

Let's initialize the clients one time and distribute those clients to the places that need it. This patch set creates a global struct 'Clients' that gets initialized by app.go before the broker object is created. Any function that runs after the broker object creation, will have access to all the clients.

Fixes: #213

@rthallisey
Copy link
Contributor Author

Testing: Run the normal broker tests.

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.

I'm going to try to apply my review comments to the PR that originally introduced the change since there are what look like 3 different ones. Will try to keep higher level discussion to this one.

  • I like the clients pkg a lot, decouples things in a way that makes changes a lot less brittle (client init code isn't just thrown about where it's used; it's got a home). Also going to make it real easy and natural to add an Origin() client.

[this is where you use clients] - [this is where you get clients (and how we create them)]

  • I think we should push any remaining client code unrelated to actually running an apb into the clients package, then we should reconsider renaming apb/client.go to something that more accurately describes what it's doing. Semantically, it's the part of the apb package that's responsible for actually executing apb methods. Could almost be apb/apb.go? Curious what you guys think. EDIT: Realizing this is directly related to my next bullet. NewClient simply initializes the various clients and sticks them onto a struct. All of that is effectively being replaced by the clients package and the clients.<instance>() variants.

  • We should get rid of this struct if its purpose is to just aggregate references to clients. We've basically turned it into a package, so caller code should import the clients package, and then actually get references by clients.Origin(). Really nice interface that lets us change code behind the instance accessors without breaking callers.

  • Speaking of clients.() methods, do we want any of these to be singletons? I.E., first time that method is called, check internal _instance field, if it's nil, construct and return and cache instance, then on subsequent calls, return cached instance.

  • I think I would have preferred for the PRs to have come in as one unit. Made it difficult to review the set since it looks like C builds on B builds on A, and they all introduce new features on top of the others.

"github.com/coreos/etcd/client"
)

type EtcdConfig struct {
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 should remain dao.Config, which is composed of EtcdConfig. Although it's only etcd currently, leaves dao configuration flexible for change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Speaking of clients.() methods, do we want any of these to be singletons?

singleton object I think that we just create them during initialization of application with the configuration of the clients. Allows us to error early if something is going to go wrong imo.

I think I would have preferred for the PRs to have come in as one unit. Made it difficult to review the set since it looks like C builds on B builds on A, and they all introduce new features on top of the others.

wish that at least on comments that told us the order, which could be added.

We should get rid of this struct

👍

I like the clients pkg a lot, decouples things in a way that makes changes a lot less brittle (client init code isn't just thrown about where it's used; it's got a home). Also going to make it real easy and natural to add an Origin() client.

👍

Semantically, it's the part of the apb package that's responsible for actually executing apb methods. Could almost be apb/apb.go? Curious what you guys think.

To me, it looks like a lot of the ABP code is in their own files. and client.go should all be in the new package. I am wondering what methods you were thinking should be left in apb?

Copy link
Contributor

Choose a reason for hiding this comment

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

@eriknelson +1 to EtcdConfig remaining Config. I just added that as a comment to my review.

Copy link
Contributor

Choose a reason for hiding this comment

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

To me, it looks like a lot of the ABP code is in their own files. and client.go should all be in the new package. I am wondering what methods you were thinking should be left in apb?

I don't think code that's responsible for the execution of an apb belongs in the clients pkg, it's a natural fit for the apb pkg. In my mind, the clients package encapsulates the various gateways to other systems and APIs, along with their setup and validation.

RE: the logic that belongs in the apb pkg, it's effectively ExecuteApb(method, parameters), and we should hide the guts of how that actually gets done behind that function (in this case, it's running the pod). ExecuteApb IMO is a better name for RunImage, it's a higher level of abstraction. RunImage bleeds implementation details into the name. It suggests "run this apb method with these parameters, I don't care how you do that" vs "run this image because that's how we happen to run apbs".

Copy link
Contributor

Choose a reason for hiding this comment

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

Speaking of clients.() methods, do we want any of these to be singletons?

This sounds ok, we need to make sure we test multiple users of the SAME client at the SAME time. Will that work ok? IS it really a 'single' connection? The old way we created a new connection so if there were multiple provisions going on each worker would have their own connection.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should get rid of this struct

I also concur with this 👍

}
return config, nil
}

func NewClient(log *logging.Logger) (*Client, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we push this into the clients package? I think it makes more sense there. Related to my overall comment on apb/client.go

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eriknelson I agree, but this is a much larger change since Client is a class. So things like RunImage need to be distributed out of client.go. For now, I'm going to keep this in place, but adding a TODO in the final patch for this series and we can return to it later.

Copy link
Contributor

Choose a reason for hiding this comment

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

@rthallisey since I'm requesting the change, mind if I take a crack at it and submit for your review? Think I could probably just explain myself better with code anyways. I think it's totally fine to accept this PR without it and add the TODO for a follow up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eriknelson That would be fantastic 👍

@eriknelson
Copy link
Contributor

Is this PR a strict superset of the docker and k8s ones? Should all the changes just get make and addressed here and we can close the others, pulling it all in from this?

@rthallisey
Copy link
Contributor Author

@eriknelson They are each a super set of the previous patch. Personally, I'd like for us to discuss in each patch the code that each one touches. I think it's much easier to review because this entire patch set is large and I have one more on the way ;). Also, I was careful not to have overlap, so anything in the docker patch only touches docker client code. The large patch that's coming last will touch a bit of everything.

If we want to talk about overall structure, then the final patch at the end will make sense since it will have the final picture.

@jmrodri
Copy link
Contributor

jmrodri commented Jun 23, 2017

@rthallisey the individual patches actually make it harder to see on github. Since the diff of the last one is ALL of them. It's hard to see what was just for the last patch vs the first one. And while looking at the first one, it's hard to see where you are going with it in the final implementation. 😄

@shawn-hurley
Copy link
Contributor

I am wondering if we are even using the docker client. Pull Image appears to be the only thing that uses the dockerClient and that is not being called anywhere. I think we should consider removing this.

I also would like to note that we should add doc comments on the new exported structs/functions/constants et all.

Lastly, and this is just an idea/thing I want to throw out there. using individual clients should be in their own package. example client/kubernetes/client.go the client object could import this and do the above workflow but just a better speration of the clients.

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.

This one boils down to 1 major change which is keep dao.Config with embedded EtcdConfig

)

type Config struct {
Registry apb.RegistryConfig
Dao dao.Config
Dao clients.EtcdConfig
Copy link
Contributor

Choose a reason for hiding this comment

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

This will mean that if we ever want to add some configuration to the dao that is not etcd related we'd have to redo this. dao.Config was easier so we could configure all of the dao. I see how you arrived here since the only configuration items on the dao were etcd related, but it paints in a corner of only being etcd.

"github.com/coreos/etcd/client"
)

type EtcdConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

@eriknelson +1 to EtcdConfig remaining Config. I just added that as a comment to my review.

"github.com/coreos/etcd/client"
)

type EtcdConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Speaking of clients.() methods, do we want any of these to be singletons?

This sounds ok, we need to make sure we test multiple users of the SAME client at the SAME time. Will that work ok? IS it really a 'single' connection? The old way we created a new connection so if there were multiple provisions going on each worker would have their own connection.

"github.com/coreos/etcd/client"
)

type EtcdConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should get rid of this struct

I also concur with this 👍

endpoints []string
client client.Client
kapi client.KeysAPI // Used to interact with kvp API over HTTP
config clients.EtcdConfig
Copy link
Contributor

Choose a reason for hiding this comment

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

should be dao.Config

@rthallisey
Copy link
Contributor Author

@jmrodri wfm. One more on the way

@eriknelson
Copy link
Contributor

eriknelson commented Jun 23, 2017

@shawn-hurley

singleton object I think that we just create them during initialization of application with the configuration of the clients. Allows us to error early if something is going to go wrong imo.

Good argument over lazy singleton, fail fast and early.

I am wondering if we are even using the docker client. Pull Image appears to be the only thing that uses the dockerClient and that is not being called anywhere. I think we should consider removing this.

I think you're right. It's a vestige from when we pulled images before running then with oc run. I don't remember why we needed the pull in the first place, it's possible we never did. It's a use case entirely covered by the Pod pullPolicy. Huge bonus points if it means we can shed a dependency on docker entirely. We should definitely look into this, probably appropriate for an issue and follow up PR. Edit: #227

I also would like to note that we should add doc comments on the new exported structs/functions/constants et all.
👍 , this a style thing for the linter? Obviously a good habit.

Lastly, and this is just an idea/thing I want to throw out there. using individual clients should be in their own package. example client/kubernetes/client.go the client object could import this and do the above workflow but just a better speration of the clients.

What's the benefit of having a package for every client? I understand it would separate things more, just don't see a case for something I can't do with them all in the same package. It also feels like we're blowing up our package count, I'm not familiar enough with go conventions to know if this is frowned upon or it's normal matter of course, but it feels excessive.

@shawn-hurley
Copy link
Contributor

I think the major benefit is the code breaking up into their own little place. because of the way go does packages just be in their own file doesn't break it up for the caller. So, for instance, Origin client has a struct that we want to call ServiceRoleBinding but so does Kubernetes and they are different. Rather than having to name them OriginServiceRoleBinding and KuberneetesServiceRoleBinding you name it ServiceRoleBinding and use the package to tell which one to use. I think it makes for cleaner code. If this is not a use case we are worried about then yes I agree it is not worth the extra packages.

@eriknelson
Copy link
Contributor

@shawn-hurley I'd propose we start with one package and if we start to see naming collisions, we can break things out.

@rthallisey rthallisey changed the title Breakup dao client Breakup all the Broker Clients into a clients pkg Jun 23, 2017
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.

Going to try to summarize acceptance criteria so @rthallisey can knock stuff out. Please add/dispute anything if I miss something.

Requested Changes:

  • Doc comments for anything exported so we don't introduce additional linter debt.
  • dao.Config should remain dao.Config, and it should be composed of EtcdConfig to allow for future expansion/changes.

Issues outside the scope of this PR (should get followed up):

@rthallisey rthallisey closed this Jun 23, 2017
@rthallisey rthallisey deleted the breakup-dao-client branch June 23, 2017 21:22
@rthallisey rthallisey restored the breakup-dao-client branch June 23, 2017 21:22
@rthallisey rthallisey reopened this Jun 23, 2017
@rthallisey
Copy link
Contributor Author

git didn't like the branch rename :). We'll leave it as is

Ryan Hallisey added 3 commits June 23, 2017 17:34
Make a seperate directory for clients so they are
not apart of the APB code.  This will make the clients
easy to initialize and create new ones.
The Etcd Client is a little tricker because it requires
a config file. Later when we unify all the clients we will
use individual functions just like etcd.
Pull together all the client split work by using a global variable
to pass around the clients.
@rthallisey
Copy link
Contributor Author

Sorry for the confusion on the PRs :). That experiment didn't work

@rthallisey
Copy link
Contributor Author

I think the major benefit is the code breaking up into their own little place. because of the way go does packages just be in their own file doesn't break it up for the caller. So, for instance, Origin client has a struct that we want to call ServiceRoleBinding but so does Kubernetes and they are different. Rather than having to name them OriginServiceRoleBinding and KuberneetesServiceRoleBinding you name it ServiceRoleBinding and use the package to tell which one to use. I think it makes for cleaner code. If this is not a use case we are > worried about then yes I agree it is not worth the extra packages.

I think that the clients should stay in the clients package because they're just objects. They aren't classes. We aren't building a kubernetes or docker client, we're creating a variable to call the clients efficiently.

@eriknelson
Copy link
Contributor

Going to test this now in an integrated environment to make sure things are still running smoothly, but the current thinking after speak with the guys offline is we're ready to merge this into master. Doc strings can come in with a follow up PR (there's one out there to become golint compliant), and I will be following this up with a change that already has the DaoConfig/EtcdConfig requested change.

@eriknelson
Copy link
Contributor

ACK, tested and was able to provision things fine with this on top of master. Merging.

@eriknelson eriknelson merged commit b2809dc into openshift:master Jun 26, 2017
@rthallisey rthallisey deleted the breakup-dao-client branch July 27, 2017 13:14
jianzhangbjz pushed a commit to jianzhangbjz/ansible-service-broker that referenced this pull request May 17, 2018
* Break apart the Kubernetes Client

Make a seperate directory for clients so they are
not apart of the APB code.  This will make the clients
easy to initialize and create new ones.

* Break apart the Docker Client

* Break apart the Etcd client

The Etcd Client is a little tricker because it requires
a config file. Later when we unify all the clients we will
use individual functions just like etcd.

* Create a global client variable

Pull together all the client split work by using a global variable
to pass around the clients.
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