-
Notifications
You must be signed in to change notification settings - Fork 494
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 update-series command by application. #7677
Conversation
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.
Some initial comments....
apiserver/allfacades.go
Outdated
@@ -123,6 +123,7 @@ func AllFacades() *facade.Registry { | |||
reg("Application", 2, application.NewFacade) | |||
reg("Application", 3, application.NewFacade) | |||
reg("Application", 4, application.NewFacade) | |||
reg("Application", 5, application.NewFacade) // UpdateSeries |
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 is not the preferred way to do it - the fact that it was done this way previously was a mistake. See StorageProvisionerAPIv3 and StorageProvisionerAPIv4 for the right way.
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.
Will do.
There is a side question on this. Version 5 is already used in develop. What is the correct version to use here?
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.
apiserver/application/application.go
Outdated
} | ||
|
||
if !app.IsPrincipal() { | ||
return errors.New(fmt.Sprintf("%s is a subordinate application, series update is not supported.", args.ApplicationName)) |
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.
Errorf
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.
apiserver/application/application.go
Outdated
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
// all units will have the same subordinates, therefore we only |
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.
All
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
apiserver/application/application.go
Outdated
// all units will have the same subordinates, therefore we only | ||
// need to check one. | ||
unit := units[0] | ||
if unit != 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.
When would unit ever be nil? I don't think we need this check. For safety, we should error though if len(units) == 0
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
apiserver/application/application.go
Outdated
} | ||
_, seriesSupportedErr := charm.SeriesForCharm(args.Series, subordinateCharm.Meta().Series) | ||
if seriesSupportedErr != nil && !args.Force { | ||
return errors.New(fmt.Sprintf("series %s is not supported by the subordinates of the application in use. Use --force to override.", args.Series)) |
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.
Errorf.
Also, the apiserver layer is not the place to put error messages. You need to define a new error type and have the caller react to that. The API is called by more than just the CLI. eg Juju Python library. There's no such thing as --force there.
See apiserver/params/apierror.go
@@ -1480,6 +1480,91 @@ func (s *applicationSuite) TestApplicationUpdateInvalidApplication(c *gc.C) { | |||
c.Assert(err, gc.ErrorMatches, `application "no-such-application" not found`) | |||
} | |||
|
|||
func (s *applicationSuite) TestApplicationUpdateSeries(c *gc.C) { |
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.
New tests should be added to application_unit_test.go
The tests in application_test.go use JujuConnSuite which we are trying to move away from
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.
removed changes to application_test.go and added unit tests to application_unit_tests.go
cmd/juju/application/updateseries.go
Outdated
} | ||
|
||
var updateSeriesDoc = ` | ||
It is recommended to update the series on existing units before running this |
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 don't think we need to necessarily recommend this? There's no real harm in having existing units on trusty and new ones on xenial. It's really outside of Juju's domain and more of a charm thing.
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 was thinking in terms of when updating the series of a machine is requested, not a the application data. e.g.: ..."running this command to update a machines' series.
cmd/juju/application/updateseries.go
Outdated
command. | ||
|
||
By updating the application series, future units of the application to use | ||
the new series. The series for subordinate applications is also updated. |
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.
Let's not mention subordinates here. There's no real point as people don't use or pay attention to the series there. They don't care - they are just interested in the principal.
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.
cmd/juju/application/updateseries.go
Outdated
the new series. The series for subordinate applications is also updated. | ||
|
||
The update is disallowed unless the --force flag is used if the series is not | ||
explicitly supported: |
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.
"... if the requested series is not explicitly supported by the application's charm and any subordinates, as well as any other charms which may be deployed to the same machine."
You can add a comment that the user may wish to upgrade the charm to a later revision that does support their preferred series.
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.
cmd/juju/application/updateseries.go
Outdated
|
||
Examples: | ||
juju update-series <application> <series> | ||
juju update-series <machine> <series> |
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.
Include a --force example
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
b3e8cb7
to
bc32899
Compare
bc32899
to
afa054d
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.
A good iteration on the first commit with some good progress towards how things need to be. There's a few issues with the apiserver layer to sort out. In the state layer, we need tests for the concurrency checks, and there's also logic and asserts missing.
api/application/client.go
Outdated
@@ -219,6 +219,11 @@ func (c *Client) Update(args params.ApplicationUpdate) error { | |||
return c.facade.FacadeCall("Update", args, nil) | |||
} | |||
|
|||
// UpdateApplicationSeries updates the application series. | |||
func (c *Client) UpdateApplicationSeries(args params.ApplicationUpdateSeries) error { | |||
return c.facade.FacadeCall("UpdateApplicationSeries", args, 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.
This should be a bulk call. The api layer typically takes a singular argument like here. But what is passed over the wire to the apiserver facade is a set of bulk args. There's lot of examples to cargo cult, but it would be something like:
type UpdateApplicationSeriesArg struct {
ApplicationName string
Force bool
etc
}
type UpateApplicationSeriesArgs struct {
Args []UpdateApplicationSeriesArg
}
and then
args := params.UpateApplicationSeriesArgs {
Args: []params.UpdateApplicationSeriesArg{arg}
}
var results params.ErrorResults
err := c.facade.FacadeCall("UpdateApplicationSeries", args, results)
if err != nil {
return err
}
return results.OneError()
As I said, lots of examples to copy off, but the above pseudo code should get you started.
On the server side, the pattern is to define a func to do one arg at a time, and loop over the supplied args in the args parameter, setting the results.Error for each one.
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.
apiserver/application/application.go
Outdated
if err := api.checkCanWrite(); err != nil { | ||
return err | ||
} | ||
if !args.Force { |
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.
Even if force is true, if changes are blocked, it should still error. Force is only to bypass incompatible series, not change blocks
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.
Rechecked the examples I was using. Removed the Force part.
apiserver/application/application.go
Outdated
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
if args.Series == "" { |
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 should be checked first as it is cheap to check. We should not waste cpu cycles, db access etc loading the application if a simple arg check would fail
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.
moved
apiserver/application/application.go
Outdated
} | ||
if err = verifySupportedSeries(app, args.Series, args.Force); err != nil { | ||
if params.IsCodeIncompatibleSeries(err) { | ||
err = errors.Annotatef(err, "series %s is not supported by the application in use. Use --force to override.", args.Series) |
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! No CLI related messages at the apiserver layer. These facades are called by external client libraries as well, eg juju python lib. You don't need the params.IsCodeIncompatibleSeries(err) check here at all.
As well, all errors returned from the apiserver facade methods need to be wrapped like so:
return common.ServerError(err)
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.
wrapped appropriate errors in common.ServerError. Removed checks highlighted in comment.
apiserver/application/application.go
Outdated
return err | ||
} | ||
|
||
if !app.IsPrincipal() { |
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 check should be further up - why go to all the trouble of checking for supported series if we won't update anything anyway because of the app being a subordinate.
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.
moved.
} | ||
|
||
var _ = gc.Suite(&ApplicationSuite{}) | ||
|
||
func (s *ApplicationSuite) TearDownTest(c *gc.C) { | ||
for _, a := range s.applications { |
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 implies that we are leaking applications between tests. s.application should start out empty or with newly cnstructed mocks.
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.
removed
state/application.go
Outdated
Assert: bson.D{{"charmurl", chURL}}, | ||
} | ||
|
||
var ops []txn.Op |
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 ops here should also include the ones to update any subordinates, instead of doing that in the apiserver layer.
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.
moved.
state/application.go
Outdated
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
var unitOps []txn.Op |
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.
These ops all need to be built up inside a buildTxn() function, with matching business logic to perform the same checks as what the asserts do.
(as an aside, there's no model is alive check and there needs to be).
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.
buildTxn() function added
@@ -922,6 +922,16 @@ func (s *ApplicationSuite) TestUpdateConfigSettings(c *gc.C) { | |||
} | |||
} | |||
|
|||
func (s *ApplicationSuite) TestUpdateApplicationSeries(c *gc.C) { |
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 need tests that check the behaviour when things change concurrently (eg adding subordinates). This is done using the various txn hook helpers See various uses of state.SetBeforeHooks, state.SetAfterHooks, state.SetRetryHooks
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.
starting to add these tests.
state/application.go
Outdated
unitOps = append(unitOps, txn.Op{ | ||
C: unitsC, | ||
Id: u.doc.DocID, | ||
Assert: bson.D{{"subordinates", subNames}}, |
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.
If this sufficient? Maybe it is! I thought maybe it would have been a bit more complicated, but I am probably wrong. A test to check all this is needed to be sure (using the txn hook helpers).
0718e0d
to
2a576fd
Compare
!!build!! |
2a576fd
to
5a93f6e
Compare
!!build!! |
1 similar comment
!!build!! |
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.
Good progress, not quite done yet, some more comments
api/application/client.go
Outdated
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
return errors.Trace(results.OneError()) |
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.
Typically we don't need trace here. Don't hurt but not really needed.
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.
removed.
apiserver/application/application.go
Outdated
@@ -78,6 +94,11 @@ func NewFacade(ctx facade.Context) (*API, error) { | |||
) | |||
} | |||
|
|||
// NewAPIv5 creates a new server-side API v5 facade. | |||
func NewAPIv5(v4 *API) *APIv5 { |
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 isn't really needed - just use "return &APIv5{v4}" directly in the NewFacadeV5() method
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.
apiserver/application/application.go
Outdated
} | ||
for i, arg := range args.Args { | ||
err := api.updateOneApplicationSeries(arg) | ||
results.Results[i].Error = err |
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.
Typically the pattern is not to assume the "doOne" method will return a params.Error and so use common.ServerError(err) here. If err is already a params.Error, it will just work.
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.
apiserver/application/application.go
Outdated
|
||
// Find our subordinate applications, to verify their series as well, | ||
for _, subUnitName := range unit.SubordinateNames() { | ||
subordinateApplicationName := strings.Split(subUnitName, "/")[0] |
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.
There could be a helper for this - might pay to check
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.
Found one.
charm: &ch, | ||
} | ||
|
||
s.applications["foo"] = &app |
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.
why do we need both s.applications and s.backend.applications (and charms)
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 tests were originally setup that way, however it appears that neither s.applications nor s.charms are not needed, removed. Looking at the other mock structs in the ApplicationSuite, endpoints and relation are not needed either, removed those as well.
state/application.go
Outdated
@@ -1005,6 +1005,108 @@ func (a *Application) SetCharm(cfg SetCharmConfig) (err error) { | |||
return nil | |||
} | |||
|
|||
// UpdateApplicationSeries updates the series for the Application. | |||
func (a *Application) UpdateApplicationSeries(series string, force bool) (err error) { | |||
acopy := &Application{a.st, a.doc} |
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.
not sure why we need a copy here
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.
removed
state/application.go
Outdated
|
||
var ops []txn.Op | ||
|
||
appOps, err := a.addApplicationUpdateSeriesOps(series, force) |
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.
just make this first one ops and subsequent things append to that
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/application.go
Outdated
ops = append(ops, txn.Op{ | ||
C: unitsC, | ||
Id: u.doc.DocID, | ||
Assert: txn.DocExists, |
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.
why is this is a separate txn.Op? just include with the assert above
state/application.go
Outdated
buildTxn := func(attempt int) ([]txn.Op, error) { | ||
a := acopy | ||
if attempt > 0 { | ||
// If we've tried once already and failed, re-evaluate the criteria. |
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.
On attempt > 0, we need to check that someone hasn't already updated the series to what we want; in that case we return ErrNoOperations. And there needs to be a test for that.
And we need to check for that in business logic outside the buildTxn func
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/application.go
Outdated
|
||
func (a *Application) addApplicationUpdateSeriesOps(series string, force bool) ([]txn.Op, error) { | ||
var ops []txn.Op | ||
err := a.VerifySupportedSeries(series, force) |
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 is done outside the ops funcs. And then the ops func build up asserts to match.
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/application_test.go
Outdated
app, subApp := s.setupMultiSeriesUnitWithSubordinate(c) | ||
err := app.UpdateApplicationSeries("trusty", false) | ||
c.Assert(err, jc.ErrorIsNil) | ||
app.Refresh() |
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.
need to check error, here and elsewhere
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/application_test.go
Outdated
defer state.SetTestHooks(c, s.State, | ||
jujutxn.TestHook{ | ||
Before: func() { | ||
ops := []txn.Op{{ |
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 typically just manipulate state directly via state.State api calls. Using the txn runner works but should be a last resort. eg could just use app.SetCharm(blah)
state/application_test.go
Outdated
c.Assert(subApp.Series(), gc.Equals, "xenial") | ||
} | ||
|
||
func (s *ApplicationSuite) TestUpdateApplicationSeriesURLChange(c *gc.C) { |
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 doesn't quite look right.
There should be 2 variations.
- the charm changes to one where the series is not supported and so an incompatible series error occurs
- the charm changes but the series is still supported so all good
I'm not sure why the after hooks are needed. They are typically used to verify that a particular txn run attempt has done to the db what is expected, ie read only checks. We don't need that here because we check via api calls that things are as expected.
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.
After hooks removed
state/application_test.go
Outdated
c.Assert(app.Series(), gc.Equals, "trusty") | ||
} | ||
|
||
func (s *ApplicationSuite) TestUpdateApplicationSeriesUnitCountChange(c *gc.C) { |
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.
Same comment applies here etc - as per other test
5d5898d
to
b9b89e9
Compare
apiserver/application/application.go
Outdated
@@ -339,6 +354,71 @@ func (api *API) Update(args params.ApplicationUpdate) error { | |||
return nil | |||
} | |||
|
|||
// UpdateApplicationSeries updates the application series. Series for |
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 don't use double spaces after a full stop. There's at least a couple of places.
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.
updated
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.
There's a few things to fix before landing but otherwise everything looks ok.
apiserver/application/application.go
Outdated
} | ||
app, err := api.backend.Application(arg.ApplicationName) | ||
if err != nil { | ||
return err |
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.
In most cases, we use errors.Trace(err) for standard err returns
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
apiserver/application/application.go
Outdated
} | ||
} | ||
if arg.Series == app.Series() { | ||
// HML do something and add test |
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.
You'd just return nil here? I think that will suffice.
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.
Series: "zesty", | ||
}}, | ||
} | ||
results, err := s.api.UpdateApplicationSeries(args) |
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 see that below we verify that UpdateApplicationSeries with the passed in series is called so that's ok. Ideally the test would use different application names rather than "foo" for both args though.
results, err := s.api.UpdateApplicationSeries(args) | ||
c.Assert(err, jc.ErrorIsNil) | ||
c.Assert(len(results.Results), gc.Equals, 1) | ||
c.Assert(results.Results[0], jc.DeepEquals, params.ErrorResult{}) |
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 meant the value in params.ErrorResult.
It's nil but we expect a fail?
} | ||
c.series = args[1] | ||
case 1: | ||
if names.IsValidMachine(args[0]) { |
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.
if names.IsValidMachine(args[0]) || names.IsValidApplication(args[0]) {
}
?
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 know that if IsValidMachine is true with only 1 arg, then the series is missing. Otherwise it's unknown if the series or application name is missing because IsValidApplication doesn't seem to know the difference between an application and a series.
state/application.go
Outdated
Assert: isAliveDoc, | ||
Update: bson.D{{"$set", bson.D{{"series", series}}}}, | ||
}} | ||
ops = append(ops, txn.Op{ |
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 need for all these appends, just to it as a slice with many elements
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.
combined into 1 txn and removed the function.
state/application.go
Outdated
ops = append(ops, txn.Op{ | ||
C: applicationsC, | ||
Id: a.doc.DocID, | ||
Assert: bson.D{{"unitcount", a.doc.UnitCount}}, |
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.
Same with this asset - add it to the first txn.Op.
So in fact we only need the one txn.Op in the return result. That op will have 3 assert values appended together
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.
same as above
state/application_test.go
Outdated
ch := state.AddTestingCharmMultiSeries(c, s.State, "multi-series") | ||
app := state.AddTestingServiceForSeries(c, s.State, "precise", "multi-series", ch) | ||
err := app.UpdateApplicationSeries("precise", false) | ||
c.Assert(err, gc.ErrorMatches, "no transaction operations are available") |
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 "no transaction operations are available" error should not get exposed - the txn runner sees it and returns nil.
If this is required here then there's something wrong elsewhere.
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 test was to see an error when the series on the app matches the requested change before even trying to build the txn. However now the underlying code has been changed per other comments. The test now doesn't expect and error.
state/application_test.go
Outdated
err := app.SetCharm(cfg) | ||
c.Assert(err, jc.ErrorIsNil) | ||
}, | ||
After: 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.
You can just drop the After: 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.
done.
assertApplicationSeriesUpdate(c, subApp, "trusty") | ||
} | ||
|
||
func (s *ApplicationSuite) TestUpdateApplicationSeriesSecondSubordinate(c *gc.C) { |
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 still need a test where an added subordinate is not compatible
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.
added.
0f28886
to
5c0b46c
Compare
5c0b46c
to
6df95bd
Compare
!!build!! |
1 similar comment
!!build!! |
!!build!! |
1 similar comment
!!build!! |
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju |
Description of change
The update-series command will allow a user to juju of a new series for an application or a machine. This initial commit covers the application case where updating the series of an application allows for new units of the application to use the new series.
The new series must be in the supported series list of the related charm. As well, charms subordinate
to the one specified must also support the new series. A --force flag allows this behavior to be over ridden.
QA steps
At any time, the series to be used by an application can be found in the output of "juju status --format yaml"
Documentation changes
Yes, the online list of commands needs to be updated.
Bug reference
This is a planned project, however a feature request bug was filed as well:
https://bugs.launchpad.net/juju/+bug/1704135