Skip to content

Commit

Permalink
Upgrade model to controller version as a fallback;
Browse files Browse the repository at this point in the history
  • Loading branch information
ycliuhw committed Aug 3, 2022
1 parent 409b017 commit 2311693
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 18 deletions.
10 changes: 10 additions & 0 deletions apiserver/facades/client/modelupgrader/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ func newFacadeV1(ctx facade.Context) (*ModelUpgraderAPI, error) {
if err != nil {
return nil, errors.Trace(err)
}
controllerModel, err := systemState.Model()
if err != nil {
return nil, errors.Trace(err)
}
controllerAgentVersion, err := controllerModel.AgentVersion()
if err != nil {
return nil, errors.Trace(err)
}

configGetter := stateenvirons.EnvironConfigGetter{Model: model}
newEnviron := common.EnvironFuncForModel(model, configGetter)
Expand All @@ -56,8 +64,10 @@ func newFacadeV1(ctx facade.Context) (*ModelUpgraderAPI, error) {
}
apiUser, _ := auth.GetAuthTag().(names.UserTag)
backend := common.NewUserAwareModelManagerBackend(model, pool, apiUser)

return NewModelUpgraderAPI(
systemState.ControllerTag(),
controllerAgentVersion,
statePoolShim{StatePool: pool},
toolsFinder,
newEnviron,
Expand Down
42 changes: 33 additions & 9 deletions apiserver/facades/client/modelupgrader/upgrader.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ var logger = loggo.GetLogger("juju.apiserver.modelupgrader")
// ModelUpgraderAPI implements the model upgrader interface and is
// the concrete implementation of the api end point.
type ModelUpgraderAPI struct {
statePool StatePool
check common.BlockCheckerInterface
authorizer facade.Authorizer
toolsFinder common.ToolsFinder
apiUser names.UserTag
isAdmin bool
callContext context.ProviderCallContext
newEnviron common.NewEnvironFunc
statePool StatePool
check common.BlockCheckerInterface
authorizer facade.Authorizer
toolsFinder common.ToolsFinder
apiUser names.UserTag
isAdmin bool
ctrlAgentVersion version.Number
callContext context.ProviderCallContext
newEnviron common.NewEnvironFunc

registryAPIFunc func(repoDetails docker.ImageRepoDetails) (registry.Registry, error)
environscloudspecGetter func(names.ModelTag) (environscloudspec.CloudSpec, error)
Expand All @@ -48,6 +49,7 @@ type ModelUpgraderAPI struct {
// models.
func NewModelUpgraderAPI(
controllerTag names.ControllerTag,
ctrlAgentVersion version.Number,
stPool StatePool,
toolsFinder common.ToolsFinder,
newEnviron common.NewEnvironFunc,
Expand Down Expand Up @@ -80,6 +82,7 @@ func NewModelUpgraderAPI(
newEnviron: newEnviron,
registryAPIFunc: registryAPIFunc,
environscloudspecGetter: environscloudspecGetter,
ctrlAgentVersion: ctrlAgentVersion,
}, nil
}

Expand Down Expand Up @@ -121,6 +124,16 @@ func (m *ModelUpgraderAPI) AbortModelUpgrade(arg params.ModelParam) error {
return st.AbortCurrentUpgrade()
}

func isKnownError(err error) bool {
if errors.Is(errors.Cause(err), errors.NotFound) {
return true
}
if errors.Is(errors.Cause(err), errors.AlreadyExists) {
return true
}
return false
}

// UpgradeModel upgrades a model.
func (m *ModelUpgraderAPI) UpgradeModel(arg params.UpgradeModelParams) (result params.UpgradeModelResult, err error) {
logger.Tracef("UpgradeModel arg %#v", arg)
Expand Down Expand Up @@ -164,7 +177,18 @@ func (m *ModelUpgraderAPI) UpgradeModel(arg params.UpgradeModelParams) (result p
targetVersion, err = m.decideVersion(
targetVersion, agentVersion, arg.AgentStream, st, model,
)
if errors.Is(errors.Cause(err), errors.NotFound) || errors.Is(errors.Cause(err), errors.AlreadyExists) {
if isKnownError(err) &&
arg.TargetVersion == version.Zero && // no target vesion provided.
!model.IsControllerModel() &&
m.ctrlAgentVersion.Compare(agentVersion) > 0 {
// check if we can upgrade to the controller agent version if no target version provided.
logger.Debugf("checking if we can upgrade model %q to controller version %q", agentVersion, m.ctrlAgentVersion)
targetVersion = m.ctrlAgentVersion
targetVersion, err = m.decideVersion(
targetVersion, agentVersion, arg.AgentStream, st, model,
)
}
if isKnownError(err) {
result.Error = apiservererrors.ServerError(err)
return result, nil
}
Expand Down
118 changes: 109 additions & 9 deletions apiserver/facades/client/modelupgrader/upgrader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ import (
type modelUpgradeSuite struct {
jujutesting.IsolationSuite

adminUser names.UserTag
authoriser apiservertesting.FakeAuthorizer
callContext context.ProviderCallContext
adminUser names.UserTag
authoriser apiservertesting.FakeAuthorizer
callContext context.ProviderCallContext
ctrlAgentVersion version.Number

statePool *mocks.MockStatePool
toolsFinder *mocks.MockToolsFinder
Expand Down Expand Up @@ -79,6 +80,7 @@ func (s *modelUpgradeSuite) getModelUpgraderAPI(c *gc.C) (*gomock.Controller, *m

api, err := modelupgrader.NewModelUpgraderAPI(
coretesting.ControllerTag,
s.ctrlAgentVersion,
s.statePool,
s.toolsFinder,
func() (environs.BootstrapEnviron, error) {
Expand Down Expand Up @@ -458,13 +460,13 @@ func (s *modelUpgradeSuite) TestUpgradeModelForControllerModelJuju3Failed(c *gc.
model1.EXPECT().Name().Return("model-1"),
)

_, err = api.UpgradeModel(
result, _ := api.UpgradeModel(
params.UpgradeModelParams{
ModelTag: ctrlModelTag.String(),
TargetVersion: version.MustParse("3.9.99"),
},
)
c.Assert(err.Error(), gc.Equals, `
c.Assert(result.Error.Error(), gc.Equals, `
cannot upgrade to "3.9.99" due to issues with these models:
"admin/controller":
- current model ("2.9.1") has to be upgraded to "2.9.2" at least
Expand Down Expand Up @@ -559,7 +561,6 @@ func (s *modelUpgradeSuite) assertUpgradeModelJuju3(c *gc.C, dryRun bool) {
}
if !dryRun {
assertions = append(assertions,
// s.statePool.EXPECT().Get(modelUUID).Return(st, nil),
st.EXPECT().SetModelAgentVersion(version.MustParse("3.9.99"), nil, false).Return(nil),
)
}
Expand Down Expand Up @@ -669,14 +670,13 @@ func (s *modelUpgradeSuite) TestUpgradeModelJuju3Failed(c *gc.C) {
model.EXPECT().Owner().Return(names.NewUserTag("admin")),
model.EXPECT().Name().Return("model-1"),
)
_, err := api.UpgradeModel(
result, _ := api.UpgradeModel(
params.UpgradeModelParams{
ModelTag: coretesting.ModelTag.String(),
TargetVersion: version.MustParse("3.9.99"),
},
)
c.Logf(err.Error())
c.Assert(err.Error(), gc.Equals, `
c.Assert(result.Error.Error(), gc.Equals, `
cannot upgrade to "3.9.99" due to issues with these models:
"admin/model-1":
- unexpected upgrade series lock found
Expand All @@ -685,6 +685,106 @@ cannot upgrade to "3.9.99" due to issues with these models:
- LXD version has to be "5.2.0" at least, but current version is "5.1.0"`[1:])
}

func (s *modelUpgradeSuite) TestUpgradeModelRetryUseControllerVersion(c *gc.C) {
s.ctrlAgentVersion = version.MustParse("3.9.99")

ctrl, api := s.getModelUpgraderAPI(c)
defer ctrl.Finish()

s.PatchValue(&upgradevalidation.MinMajorUpgradeVersion, map[int]version.Number{
3: version.MustParse("2.9.1"),
})

server := upgradevalidationmocks.NewMockServer(ctrl)
serverFactory := upgradevalidationmocks.NewMockServerFactory(ctrl)
s.PatchValue(&upgradevalidation.NewServerFactory,
func(httpClient *http.Client) lxd.ServerFactory {
return serverFactory
},
)

modelUUID := coretesting.ModelTag.Id()
model := mocks.NewMockModel(ctrl)
st := mocks.NewMockState(ctrl)
st.EXPECT().Release()

s.statePool.EXPECT().Get(modelUUID).AnyTimes().Return(st, nil)
st.EXPECT().Model().AnyTimes().Return(model, nil)

gomock.InOrder(
s.blockChecker.EXPECT().ChangeAllowed().Return(nil),

// find tool using agent version.
model.EXPECT().AgentVersion().Return(version.MustParse("2.9.1"), nil),
s.toolsFinder.EXPECT().FindTools(params.FindToolsParams{MajorVersion: 2, MinorVersion: -1}).Return(
params.FindToolsResult{
List: []*coretools.Tools{
{Version: version.MustParseBinary("2.9.1-ubuntu-amd64")},
},
}, nil,
),
model.EXPECT().Type().Return(state.ModelTypeIAAS),
// find tool using controller version again.
model.EXPECT().IsControllerModel().Return(false),
s.toolsFinder.EXPECT().FindTools(params.FindToolsParams{MajorVersion: 3, MinorVersion: -1}).Return(
params.FindToolsResult{
List: []*coretools.Tools{
{Version: version.MustParseBinary("3.9.99-ubuntu-amd64")},
},
}, nil,
),
model.EXPECT().Type().Return(state.ModelTypeIAAS),

model.EXPECT().Name().Return("model-1"),
model.EXPECT().IsControllerModel().Return(false),

// - check no upgrade series in process.
st.EXPECT().HasUpgradeSeriesLocks().Return(false, nil),

// - check if the model has win machines;
st.EXPECT().MachineCountForSeries(
"win10", "win2008r2", "win2012", "win2012hv", "win2012hvr2", "win2012r2",
"win2016", "win2016hv", "win2019", "win7", "win8", "win81",
).Return(nil, nil),
// - check if the model has deprecated ubuntu machines;
st.EXPECT().MachineCountForSeries(
"artful",
"bionic",
"cosmic",
"disco",
"eoan",
"groovy",
"hirsute",
"impish",
"precise",
"quantal",
"raring",
"saucy",
"trusty",
"utopic",
"vivid",
"wily",
"xenial",
"yakkety",
"zesty",
).Return(nil, nil),
// - check LXD version.
serverFactory.EXPECT().RemoteServer(s.cloudSpec).Return(server, nil),
server.EXPECT().ServerVersion().Return("5.2"),

st.EXPECT().SetModelAgentVersion(version.MustParse("3.9.99"), nil, false).Return(nil),
)
result, err := api.UpgradeModel(
params.UpgradeModelParams{
ModelTag: coretesting.ModelTag.String(),
},
)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result, gc.DeepEquals, params.UpgradeModelResult{
ChosenVersion: version.MustParse("3.9.99"),
})
}

func (s *modelUpgradeSuite) TestAbortCurrentUpgrade(c *gc.C) {
ctrl, api := s.getModelUpgraderAPI(c)
defer ctrl.Finish()
Expand Down
1 change: 1 addition & 0 deletions cmd/juju/commands/upgrademodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ func (c *upgradeJujuCommand) upgradeModel(
return err
}
// juju upgrade-controller without --build-agent or --agent-version
// or juju upgrade-model without --agent-version
targetVersion, err = c.notifyControllerUpgrade(
ctx, modelUpgrader,
version.Zero, // no target version provided, we figure it out on the server side.
Expand Down

0 comments on commit 2311693

Please sign in to comment.