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
Conversation
Testing: Run the normal broker tests. |
9b96a73
to
fe5a7c1
Compare
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 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 { |
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 should remain dao.Config
, which is composed of EtcdConfig
. Although it's only etcd currently, leaves dao configuration flexible for change.
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.
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?
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.
@eriknelson +1 to EtcdConfig
remaining Config
. I just added that as a comment to my review.
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.
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".
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.
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.
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 should get rid of this struct
I also concur with this 👍
} | ||
return config, nil | ||
} | ||
|
||
func NewClient(log *logging.Logger) (*Client, 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.
Can we push this into the clients package? I think it makes more sense there. Related to my overall comment on apb/client.go
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.
@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.
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.
@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.
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.
@eriknelson That would be fantastic 👍
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? |
@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. |
@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. 😄 |
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. |
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 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 |
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 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 { |
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.
@eriknelson +1 to EtcdConfig
remaining Config
. I just added that as a comment to my review.
"github.com/coreos/etcd/client" | ||
) | ||
|
||
type EtcdConfig struct { |
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.
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 { |
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 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 |
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 be dao.Config
@jmrodri wfm. One more on the way |
Good argument over lazy singleton, fail fast and early.
I think you're right. It's a vestige from when we pulled images before running then with
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. |
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. |
@shawn-hurley I'd propose we start with one package and if we start to see naming collisions, we can break things out. |
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.
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):
- Singleton clients and testing
Needs IssueConsider singleton clients #229 - Removal of DockerClient, PullImage, and docker dependency Investigate removing dockerClient and dependency #227
- I will follow up with a PR to remove the Client struct and constructor from client.go, refactor the file/RunImage to better reflect what we're doing
Needs IssueRemove apb/client.go Client struct and related refactoring. #231 - Keep the various clients in the
clients
package, if we start to see naming collisions, let's talk about separating into packages.
git didn't like the branch rename :). We'll leave it as is |
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.
173cd5b
to
c8ddfb5
Compare
Sorry for the confusion on the PRs :). That experiment didn't work |
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. |
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. |
ACK, tested and was able to provision things fine with this on top of master. Merging. |
* 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.
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