-
Notifications
You must be signed in to change notification settings - Fork 510
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
External controller updater worker #7924
External controller updater worker #7924
Conversation
return nil, errors.Trace(err) | ||
} | ||
info := results.Results[0].Info | ||
return &crossmodel.ControllerInfo{ |
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 now have a controller alias - let's populate that so we can use it when logging errors etc
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
state/watcher.go
Outdated
w.watcher.WatchCollection(externalControllersC, in) | ||
defer w.watcher.UnwatchCollection(externalControllersC, in) | ||
|
||
// Get the initial documents in the collection. |
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 chuck to get the initial docs should probably be in an initial() func like is done for other watchers (for consistency)
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
} | ||
} | ||
|
||
func (c *Client) ControllerInfo(controllerUUID string) (*crossmodel.ControllerInfo, 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.
Given there's several of these now duplicated, is it time to introduce an api/common struct and embed in several api 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.
No, because
the one I added to apiserver/crossmodelrelations shouldn't be there, I added it and forgot to drop it
this one and the one in crosscontroller aren't duplicates, they have different signatures
1b8678d
to
4709bf1
Compare
@@ -186,6 +188,16 @@ func Manifolds(config ManifoldsConfig) dependency.Manifolds { | |||
externalUpdateProxyFunc = lxd.ConfigureLXDProxies | |||
} | |||
|
|||
newExternalControllerWatcherClient := func(apiInfo *api.Info) ( |
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.
It would be nice to be consistent with how the remoterelations worker is set up. That worker's manifold has a func to get the controller connection and then there's a shim.go in the worker package that constructs the client - so we pass in the connection rather than the facade client. I guess the use cases might be subtly different enough that maybe it doesn't make sense to consolidate on a single approach.
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 idea was to avoid a dependency on the specific API facade, and have that passed in by the code configuring/constructing the manifold. My approach means that this package can just require an interface, and not be concerned at all with how it's fulfilled.
|
||
var logger = loggo.GetLogger("juju.worker.externalcontrollerupdater") | ||
|
||
type ExternalControllerUpdaterClient interface { |
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 be better not to group these 3 methods on a single interface? For a given external controller, we need to watch for changes and then ask for changes when the watcher fires. And then we need to take those changes and update the local controller. So Watch/GetInfo belong on one interface, and SetInfo() on another interface.
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 does that buy? In practice they're all implemented by the same API, and conceptually they belong together as they're all dealing with the same source of information. i.e. we're watching, fetching and updating the local controller's knowledge of external controllers.
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 same API but different targets. Just as Go uses small interfaces specific to a particular purpose, and then composes as needed into broader interfaces, I think we should do that here too (expect there's no need for the broader interface, just the individual ones). The facade connected to the local controller will just implement SetExternalControllerInfo(), and the one connected to the remote controller will implement the other two.
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.
No, that's not how it works.
All of the methods in this interface are dealing with the local controller.
- WatchExternalControllers watches for addition and removal of external controller records in the local controller
- ExternalControllerInfo asks the local controller for its current information about an external controller (so we can make an API connection)
- ExternalControllerInfo sets new external controller information in the local controller
The ExternalControllerWatcherClient
interface a couple of types below is the one that communicates with the external controller. It has two methods:
- WatchControllerInfo watches the external controller's API info for changes
- ControllerInfo gets the external controller's current API info
externalControllerInfo: externalControllers.ExternalControllerInfo, | ||
setExternalControllerInfo: externalControllers.SetExternalControllerInfo, | ||
newExternalControllerWatcherClient: newExternalControllerWatcherClient, | ||
runner: worker.NewRunner(worker.RunnerParams{ |
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 we also need to add the runner to the catacomb of the main worker so it and all the subworkers are stopped when the main worker dies?
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.
It is, see the Init in catacomb.Plan below.
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.
Ah yes, so it is.
6ee9a6a
to
25d3be8
Compare
25d3be8
to
f98cb6b
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.
Thank you
} | ||
logger.Infof("starting watcher for external controller %q", tag.Id()) | ||
watchers.Add(tag) | ||
w.runner.StartWorker(tag.Id(), func() (worker.Worker, 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.
The error from StartWorker should not be ignored.
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.
fixed
@@ -0,0 +1,209 @@ | |||
// Copyright 2016 Canonical Ltd. |
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.
2017
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.
fixed
return errors.Annotate(err, "caching external controller info") | ||
} | ||
logger.Infof("new controller info for controller %q: %v", w.tag.Id(), info) | ||
if err := worker.Stop(nw); err != nil { |
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 also remove nw from the catacomb? Otherwise we are just adding reference to the catacomb each time we create the client again and get a new watcher?
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 catacomb will remove the worker from its management when the worker stops
We introduce a new worker that watches for addition and removal of external controller entries, and then watches for changes to each one's API addresses. When the addresses change, we update the external controller details in the local controller's database. To support this worker, two new facades are introduced: ExternalControllerUpdater, and CrossController. The former is an internal controller facade, used by the worker to watch, fetch and store the local knowledge of external controllers. The latter is an anonymous controller facade that is used by other controllers to watch and fetch the controller's API connection info. There's a drive-by fix to stop importing apiserver/authentication in workers. Workers should never be using backend code directly, so we move the AnonymousUsername constant to the api package.
f98cb6b
to
5a26cd3
Compare
|
Status: merge request accepted. Url: http://ci.jujucharms.com/job/github-merge-juju |
Description of change
We introduce a new worker that watches for
addition and removal of external controller
entries, and then watches for changes to
each one's API addresses. When the addresses
change, we update the external controller
details in the local controller's database.
To support this worker, two new facades are
introduced: ExternalControllerUpdater, and
CrossController. The former is an internal
controller facade, used by the worker to
watch, fetch and store the local knowledge
of external controllers. The latter is an
anonymous controller facade that is used by
other controllers to watch and fetch the
controller's API connection info.
There's a drive-by fix to stop importing
apiserver/authentication in workers. Workers
should never be using backend code directly,
so we move the AnonymousUsername constant
to the api package.
QA steps
watch l1's debug log for changes to external controller info
Documentation changes
None.
Bug reference
None.