diff --git a/apiserver/facades/agent/upgradesteps/register.go b/apiserver/facades/agent/upgradesteps/register.go index a9e13b78c02..58139088c3c 100644 --- a/apiserver/facades/agent/upgradesteps/register.go +++ b/apiserver/facades/agent/upgradesteps/register.go @@ -7,6 +7,8 @@ import ( "context" "reflect" + "github.com/juju/errors" + "github.com/juju/juju/apiserver/facade" ) @@ -15,6 +17,18 @@ func Register(registry facade.FacadeRegistry) { registry.MustRegister("UpgradeSteps", 3, func(stdCtx context.Context, ctx facade.ModelContext) (facade.Facade, error) { return newFacadeV3(ctx) }, reflect.TypeOf((*UpgradeStepsAPI)(nil))) + registry.MustRegister("UpgradeSteps", 2, func(stdCtx context.Context, ctx facade.ModelContext) (facade.Facade, error) { + return newFacadeV2(ctx) + }, reflect.TypeOf((*UpgradeStepsAPIV2)(nil))) +} + +// newFacadeV2 is used for API registration. +func newFacadeV2(ctx facade.ModelContext) (*UpgradeStepsAPIV2, error) { + api, err := newFacadeV3(ctx) + if err != nil { + return nil, errors.Trace(err) + } + return &UpgradeStepsAPIV2{UpgradeStepsAPI: api}, nil } // newFacadeV3 is used for API registration. diff --git a/apiserver/facades/agent/upgradesteps/upgradesteps.go b/apiserver/facades/agent/upgradesteps/upgradesteps.go index 49fd76658ec..3f18532e3cb 100644 --- a/apiserver/facades/agent/upgradesteps/upgradesteps.go +++ b/apiserver/facades/agent/upgradesteps/upgradesteps.go @@ -16,19 +16,13 @@ import ( "github.com/juju/juju/state" ) -// UpgradeStepsV3 defines the methods on the version 2 facade for the -// upgrade steps API endpoint. -type UpgradeSteps interface { - WriteAgentState(context.Context, params.SetUnitStateArgs) (params.ErrorResults, error) -} - // Logger represents the logging methods used by the upgrade steps. type Logger interface { Criticalf(string, ...any) Warningf(string, ...any) } -// UpgradeStepsAPI implements version 2 of the Upgrade Steps API, +// UpgradeStepsAPI implements version 3 of the Upgrade Steps API, // which adds WriteUniterState. type UpgradeStepsAPI struct { st UpgradeStepsState @@ -40,8 +34,15 @@ type UpgradeStepsAPI struct { logger Logger } -// UpgradeStepsAPIV1 implements version 1 of the Upgrade Steps API. -type UpgradeStepsAPIV1 struct { +// UpgradeStepsAPIV2 implements version 2 of the Uppgrade Steps API. +// We need this gavade for migrations from 3.x. This api includes the method +// ResetKVMMachineModificationStatusIdle dropped in v3. KVM is not supported +// in Juju 4.x, so this method is a simple no-op for non-KVM, and errors out +// for KVM +// +// TODO(jack-w-shaw): As soon as we no longer need to support migrations +// from 3.x, drop this facade +type UpgradeStepsAPIV2 struct { *UpgradeStepsAPI } @@ -69,6 +70,30 @@ func NewUpgradeStepsAPI( }, nil } +// ResetKVMMachineModificationStatusIdle is a legacy method required to support +// UpgradeSteps facade v2. Either no-op for non-KVM machines, or error out +func (api *UpgradeStepsAPIV2) ResetKVMMachineModificationStatusIdle(ctx context.Context, arg params.Entity) (params.ErrorResult, error) { + var result params.ErrorResult + + mTag, err := names.ParseMachineTag(arg.Tag) + if err != nil { + return result, errors.Trace(err) + } + entity, err := api.st.FindEntity(mTag) + if err != nil { + return result, errors.Trace(err) + } + machine, ok := entity.(Machine) + if !ok { + return result, errors.NotValidf("machine entity") + } + if machine.ContainerType() != "kvm" { + // no-op + return result, nil + } + return result, errors.NotSupportedf("kvm container type") +} + // WriteAgentState writes the agent state for the set of units provided. This // call presently deals with the state for the unit agent. func (api *UpgradeStepsAPI) WriteAgentState(ctx context.Context, args params.SetUnitStateArgs) (params.ErrorResults, error) { diff --git a/apiserver/facades/agent/upgradesteps/upgradesteps_test.go b/apiserver/facades/agent/upgradesteps/upgradesteps_test.go index 649491db3af..0779c22a8e5 100644 --- a/apiserver/facades/agent/upgradesteps/upgradesteps_test.go +++ b/apiserver/facades/agent/upgradesteps/upgradesteps_test.go @@ -15,6 +15,7 @@ import ( "github.com/juju/juju/apiserver/facades/agent/upgradesteps" "github.com/juju/juju/controller" + "github.com/juju/juju/core/instance" "github.com/juju/juju/rpc/params" "github.com/juju/juju/state" jujutesting "github.com/juju/juju/testing" @@ -194,3 +195,67 @@ type dummyOp struct { func (d dummyOp) Build(attempt int) ([]txn.Op, error) { return nil, nil } func (d dummyOp) Done(_ error) error { return nil } + +type kvmMachineUpgradeStepsSuite struct { + upgradeStepsSuite + + tag1 names.Tag + machine *MockMachine +} + +var _ = gc.Suite(&kvmMachineUpgradeStepsSuite{}) + +func (s *kvmMachineUpgradeStepsSuite) SetUpTest(c *gc.C) { + s.upgradeStepsSuite.SetUpTest(c) + s.tag1 = names.NewMachineTag("0") +} + +func (s *kvmMachineUpgradeStepsSuite) setup(c *gc.C) *gomock.Controller { + ctlr := s.upgradeStepsSuite.setup(c) + + s.expectAuthCalls() + s.machine = NewMockMachine(ctlr) + return ctlr +} + +func (s *kvmMachineUpgradeStepsSuite) TestResetKVMMachineModificationStatusIdleNoop(c *gc.C) { + defer s.setup(c).Finish() + + s.expectAuthCalls() + s.setupFacadeAPI(c) + api := &upgradesteps.UpgradeStepsAPIV2{s.api} + + s.expectFindEntityMachine(instance.LXD) + + result, err := api.ResetKVMMachineModificationStatusIdle(context.Background(), params.Entity{Tag: s.tag1.String()}) + c.Assert(err, jc.ErrorIsNil) + c.Assert(result.Error, gc.IsNil) +} + +func (s *kvmMachineUpgradeStepsSuite) TestResetKVMMachineModificationStatusIdleKVMUnsupported(c *gc.C) { + defer s.setup(c).Finish() + + s.expectAuthCalls() + s.setupFacadeAPI(c) + api := &upgradesteps.UpgradeStepsAPIV2{s.api} + + s.expectFindEntityMachine("kvm") + + _, err := api.ResetKVMMachineModificationStatusIdle(context.Background(), params.Entity{Tag: s.tag1.String()}) + c.Assert(err, jc.ErrorIs, errors.NotSupported) +} + +func (s *kvmMachineUpgradeStepsSuite) expectFindEntityMachine(t instance.ContainerType) { + s.machine.EXPECT().ContainerType().Return(t) + m := machineEntityShim{ + Machine: s.machine, + Entity: s.entity, + } + + s.state.EXPECT().FindEntity(s.tag1.(names.MachineTag)).Return(m, nil) +} + +type machineEntityShim struct { + upgradesteps.Machine + state.Entity +} diff --git a/apiserver/facades/schema.json b/apiserver/facades/schema.json index e6e7285a456..8bdb8a09931 100644 --- a/apiserver/facades/schema.json +++ b/apiserver/facades/schema.json @@ -45553,7 +45553,7 @@ }, { "Name": "UpgradeSteps", - "Description": "UpgradeStepsAPI implements version 2 of the Upgrade Steps API,\nwhich adds WriteUniterState.", + "Description": "UpgradeStepsAPI implements version 3 of the Upgrade Steps API,\nwhich adds WriteUniterState.", "Version": 3, "AvailableTo": [ "controller-machine-agent",