Skip to content

Commit

Permalink
Restore upgrade steps v2 facade
Browse files Browse the repository at this point in the history
This facade is required for migrations from 3.x controllers

The only change between v2 -> v3 was a KVM method was dropped because
kvm container type is not supported in 4.0

Restore this method, which is a no-op for non-KVM, and returns an error
for kvm container types
  • Loading branch information
jack-w-shaw committed Apr 5, 2024
1 parent e86a0e8 commit e0bcf75
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 10 deletions.
14 changes: 14 additions & 0 deletions apiserver/facades/agent/upgradesteps/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"context"
"reflect"

"github.com/juju/errors"

"github.com/juju/juju/apiserver/facade"
)

Expand All @@ -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.
Expand Down
43 changes: 34 additions & 9 deletions apiserver/facades/agent/upgradesteps/upgradesteps.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand Down Expand Up @@ -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) {
Expand Down
65 changes: 65 additions & 0 deletions apiserver/facades/agent/upgradesteps/upgradesteps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion apiserver/facades/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit e0bcf75

Please sign in to comment.