Skip to content

Commit

Permalink
Merge branch '2.9' into merge-2.9-20211022
Browse files Browse the repository at this point in the history
  • Loading branch information
wallyworld committed Oct 22, 2021
2 parents c42ba91 + c52dcbc commit 992dc0b
Show file tree
Hide file tree
Showing 117 changed files with 3,324 additions and 603 deletions.
2 changes: 1 addition & 1 deletion agent/agentbootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ func initRaft(agentConfig agent.Config) error {
StorageDir: raftDir,
Logger: logger,
LocalID: coreraft.ServerID(agentConfig.Tag().Id()),
Queue: queue.NewBlockingOpQueue(clock.WallClock),
Queue: queue.NewOpQueue(clock.WallClock),
})
}

Expand Down
5 changes: 5 additions & 0 deletions api/application/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ type DeployArgs struct {
// value being the unique ID of a pre-uploaded resources in
// storage.
Resources map[string]string

// Force can be set to true to bypass any checks for charm-specific
// requirements ("assumes" sections in charm metadata)
Force bool
}

// Deploy obtains the charm, either locally or from the charm store, and deploys
Expand Down Expand Up @@ -155,6 +159,7 @@ func (c *Client) Deploy(args DeployArgs) error {
AttachStorage: attachStorage,
EndpointBindings: args.EndpointBindings,
Resources: args.Resources,
Force: args.Force,
}},
}
var results params.ErrorResults
Expand Down
4 changes: 4 additions & 0 deletions api/caasapplicationprovisioner/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ type ProvisioningInfo struct {
ImageRepo docker.ImageRepoDetails
CharmModifiedVersion int
CharmURL *charm.URL
Trust bool
Scale int
}

// ProvisioningInfo returns the info needed to provision an operator for an application.
Expand Down Expand Up @@ -168,6 +170,8 @@ func (c *Client) ProvisioningInfo(applicationName string) (ProvisioningInfo, err
Series: r.Series,
ImageRepo: imageRepo,
CharmModifiedVersion: r.CharmModifiedVersion,
Trust: r.Trust,
Scale: r.Scale,
}

for _, fs := range r.Filesystems {
Expand Down
4 changes: 4 additions & 0 deletions api/caasapplicationprovisioner/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) {
ImageRepo: params.DockerImageInfo{Repository: "jujuqa"},
CharmModifiedVersion: 1,
CharmURL: "cs:~test/charm-1",
Trust: true,
Scale: 3,
}}}
return nil
})
Expand All @@ -169,6 +171,8 @@ func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) {
ImageRepo: docker.ImageRepoDetails{Repository: "jujuqa"},
CharmModifiedVersion: 1,
CharmURL: &charm.URL{Schema: "cs", User: "test", Name: "charm", Revision: 1},
Trust: true,
Scale: 3,
})
}

Expand Down
16 changes: 16 additions & 0 deletions api/modelmanager/modelinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ func (s *modelInfoSuite) TestModelInfoWithAgentVersion(c *gc.C) {
s.assertExpectedModelInfo(c, results)
}

func (s *modelInfoSuite) TestModelInfoWithSupportedFeatures(c *gc.C) {
results := params.ModelInfoResults{
Results: []params.ModelInfoResult{{
Result: &params.ModelInfo{
Name: "name",
UUID: "etc.",
Type: "foo",
SupportedFeatures: []params.SupportedFeature{
{Name: "foo", Description: "bar", Version: "2.9.17"},
},
},
}},
}
s.assertExpectedModelInfo(c, results)
}

func (s *modelInfoSuite) TestInvalidResultCount(c *gc.C) {
apiCaller := basetesting.APICallerFunc(
func(objType string, version int, id, request string, a, result interface{}) error {
Expand Down
11 changes: 9 additions & 2 deletions api/raftlease/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ func (c *Client) Request(ctx context.Context, command *raftlease.Command) error
return errors.Trace(err)
},
IsFatalError: func(err error) bool {
return lease.IsDropped(err)
// We only want to retry if the leader has changed, all other errors
// can be handled via the lease manager.
return !apiservererrors.IsNotLeaderError(err)
},
Attempts: 3,
Delay: time.Millisecond * 100,
Expand Down Expand Up @@ -219,13 +221,18 @@ func (c *Client) handleRetryRequestError(command *raftlease.Command, remote Remo
// The raft instance isn't clustered, we don't have a way
// forward, so send back a dropped error.
c.config.Logger.Errorf("No leader found and no cluster available, dropping command: %v", command)
return remote, lease.ErrDropped
}

// If it is a not leader error and we haven't got a remote, just
// return dropped.
return remote, lease.ErrDropped

} else if apiservererrors.IsDeadlineExceededError(err) {
// Enqueuing into the queue just timed out, we should just
// log this error and try again if possible. The lease manager
// will know if a retry at that level is possible.
c.config.Logger.Errorf("Deadline exceeded enqueuing command.")
return remote, lease.ErrDropped
}

// If we can't find a remote, we should just return that the error was
Expand Down
18 changes: 13 additions & 5 deletions api/raftlease/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ func (s *RaftLeaseClientSuite) TestRequestWithDeadlineExceededError(c *gc.C) {
"0": s.remote,
"1": s.remote,
}
s.remote.EXPECT().Request(gomock.Any(), cmd).Return(apiservererrors.NewDeadlineExceededError("deadline exceeded"))
s.remote.EXPECT().Request(gomock.Any(), cmd).Return(nil)
s.remote.EXPECT().Request(gomock.Any(), cmd).Return(apiservererrors.NewDeadlineExceededError("deadline exceeded"))

defer func() {
_ = client.Close()
Expand All @@ -206,6 +206,13 @@ func (s *RaftLeaseClientSuite) TestRequestWithDeadlineExceededError(c *gc.C) {
err = client.Request(context.TODO(), cmd)
c.Assert(err, jc.ErrorIsNil)
c.Assert(client.lastKnownRemote, gc.NotNil)

err = client.Request(context.TODO(), cmd)
c.Assert(err, gc.ErrorMatches, `lease operation dropped`)

// Ensure that a lease operation that has the deadline exceeded does not
// drop the lastKnownRemote.
c.Assert(client.lastKnownRemote, gc.NotNil)
}

func (s *RaftLeaseClientSuite) TestRequestWithCancelledContext(c *gc.C) {
Expand Down Expand Up @@ -533,10 +540,11 @@ func (s *RaftLeaseClientSuite) setupMocks(c *gc.C) *gomock.Controller {
NewRemote: func(config RemoteConfig) Remote {
return s.remote
},
Logger: fakeLogger{},
ClientMetrics: fakeClientMetrics{},
Clock: clock.WallClock,
Random: rand.New(rand.NewSource(time.Now().UnixNano())),
Logger: fakeLogger{},
ClientMetrics: fakeClientMetrics{},
Clock: clock.WallClock,
Random: rand.New(rand.NewSource(time.Now().UnixNano())),
ForwardTimeout: time.Second,
}

return ctrl
Expand Down
2 changes: 1 addition & 1 deletion apiserver/apiserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (s *apiserverConfigFixture) SetUpTest(c *gc.C) {
}
return 0
},
RaftOpQueue: queue.NewBlockingOpQueue(testclock.NewClock(time.Now())),
RaftOpQueue: queue.NewOpQueue(testclock.NewClock(time.Now())),
}
}

Expand Down
105 changes: 55 additions & 50 deletions apiserver/common/crossmodel/crossmodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,39 +39,14 @@ func PublishRelationChange(backend Backend, relationTag names.Tag, change params
return errors.Trace(err)
}

// Update the relation suspended status.
currentStatus := rel.Suspended()
if !dyingOrDead && change.Suspended != nil && currentStatus != *change.Suspended {
var (
newStatus status.Status
message string
)
if *change.Suspended {
newStatus = status.Suspending
message = change.SuspendedReason
if message == "" {
message = "suspending after update from remote model"
}
}
if err := rel.SetSuspended(*change.Suspended, message); err != nil {
return errors.Trace(err)
}
if !*change.Suspended {
newStatus = status.Joining
message = ""
}
if err := rel.SetStatus(status.StatusInfo{
Status: newStatus,
Message: message,
}); err != nil && !errors.IsNotValid(err) {
return errors.Trace(err)
}
if err := handleSuspendedRelation(change, rel, dyingOrDead); err != nil {
return errors.Trace(err)
}

// Look up the application on the remote side of this relation
// ie from the model which published this change.
applicationTag, err := backend.GetRemoteEntity(change.ApplicationToken)
if err != nil {
if err != nil && !errors.IsNotFound(err) {
return errors.Trace(err)
}
logger.Debugf("application tag for token %+v is %v in model %v", change.ApplicationToken, applicationTag, backend.ModelUUID())
Expand All @@ -80,7 +55,7 @@ func PublishRelationChange(backend Backend, relationTag names.Tag, change params
forceCleanUp := change.ForceCleanup != nil && *change.ForceCleanup
if dyingOrDead {
logger.Debugf("remote consuming side of %v died", relationTag)
if forceCleanUp {
if forceCleanUp && applicationTag != nil {
logger.Debugf("forcing cleanup of units for %v", applicationTag.Id())
remoteUnits, err := rel.AllRemoteUnits(applicationTag.Id())
if err != nil {
Expand All @@ -94,30 +69,17 @@ func PublishRelationChange(backend Backend, relationTag names.Tag, change params
}
}

if err := rel.Destroy(); err != nil {
if forceCleanUp {
oppErrs, err := rel.DestroyWithForce(true, 0)
if len(oppErrs) > 0 {
logger.Warningf("errors forcing cleanup of %v: %v", rel.Tag().Id(), oppErrs)
}
// If we are forcing cleanup, we can exit early here.
return errors.Trace(err)
}
// See if we need to remove the remote application proxy - we do this
// on the offering side as there is 1:1 between proxy and consuming app.
remoteApp, err := backend.RemoteApplication(applicationTag.Id())
if err != nil && !errors.IsNotFound(err) {
if err := rel.Destroy(); err != nil {
return errors.Trace(err)
}
if err == nil && remoteApp.IsConsumerProxy() {
logger.Debugf("destroy consuming app proxy for %v", applicationTag.Id())
opErrs, err := remoteApp.DestroyWithForce(true, 0)
if err != nil {
return errors.Trace(err)
}
if len(opErrs) > 0 {
logger.Warningf("errors removing consuming app proxy for %v: %v", applicationTag.Id(), opErrs)
}
}

// If we are forcing cleanup, we can exit early here.
if forceCleanUp {
return nil
}
}

// TODO(wallyworld) - deal with remote application being removed
Expand All @@ -138,9 +100,49 @@ func PublishRelationChange(backend Backend, relationTag names.Tag, change params
}
}

if err := handleDepartedUnits(change, applicationTag, rel); err != nil {
return errors.Trace(err)
}

return errors.Trace(handleChangedUnits(change, applicationTag, rel))
}

func handleSuspendedRelation(change params.RemoteRelationChangeEvent, rel Relation, dyingOrDead bool) error {
// Update the relation suspended status.
currentStatus := rel.Suspended()
if !dyingOrDead && change.Suspended != nil && currentStatus != *change.Suspended {
var (
newStatus status.Status
message string
)
if *change.Suspended {
newStatus = status.Suspending
message = change.SuspendedReason
if message == "" {
message = "suspending after update from remote model"
}
}
if err := rel.SetSuspended(*change.Suspended, message); err != nil {
return errors.Trace(err)
}
if !*change.Suspended {
newStatus = status.Joining
message = ""
}
if err := rel.SetStatus(status.StatusInfo{
Status: newStatus,
Message: message,
}); err != nil && !errors.IsNotValid(err) {
return errors.Trace(err)
}
}
return nil
}

func handleDepartedUnits(change params.RemoteRelationChangeEvent, applicationTag names.Tag, rel Relation) error {
for _, id := range change.DepartedUnits {
unitTag := names.NewUnitTag(fmt.Sprintf("%s/%v", applicationTag.Id(), id))
logger.Debugf("unit %v has departed relation %v", unitTag.Id(), relationTag.Id())
logger.Debugf("unit %v has departed relation %v", unitTag.Id(), rel.Tag().Id())
ru, err := rel.RemoteUnit(unitTag.Id())
if err != nil {
return errors.Trace(err)
Expand All @@ -150,7 +152,10 @@ func PublishRelationChange(backend Backend, relationTag names.Tag, change params
return errors.Trace(err)
}
}
return nil
}

func handleChangedUnits(change params.RemoteRelationChangeEvent, applicationTag names.Tag, rel Relation) error {
for _, change := range change.ChangedUnits {
unitTag := names.NewUnitTag(fmt.Sprintf("%s/%v", applicationTag.Id(), change.UnitId))
logger.Debugf("changed unit tag for unit id %v is %v", change.UnitId, unitTag)
Expand Down
5 changes: 5 additions & 0 deletions apiserver/common/crossmodel/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ type Relation interface {
// no units are currently in scope, it will be removed immediately.
Destroy() error

// DestroyWithForce may force the destruction of the relation.
// In addition, this function also returns all non-fatal operational errors
// encountered.
DestroyWithForce(force bool, maxWait time.Duration) ([]error, error)

// Id returns the integer internal relation key.
Id() int

Expand Down
23 changes: 19 additions & 4 deletions apiserver/facades/client/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ type APIBase struct {
storagePoolManager poolmanager.PoolManager
registry storage.ProviderRegistry
caasBroker caasBrokerInterface
deployApplicationFunc func(ApplicationDeployer, DeployApplicationParams) (Application, error)
deployApplicationFunc func(ApplicationDeployer, Model, DeployApplicationParams) (Application, error)
}

func NewFacadeV13(ctx facade.Context) (*APIv13, error) {
Expand Down Expand Up @@ -199,7 +199,7 @@ func NewAPIBase(
model Model,
leadershipReader leadership.Reader,
stateCharm func(Charm) *state.Charm,
deployApplication func(ApplicationDeployer, DeployApplicationParams) (Application, error),
deployApplication func(ApplicationDeployer, Model, DeployApplicationParams) (Application, error),
storagePoolManager poolmanager.PoolManager,
registry storage.ProviderRegistry,
resources facade.Resources,
Expand Down Expand Up @@ -490,7 +490,7 @@ func deployApplication(
model Model,
stateCharm func(Charm) *state.Charm,
args params.ApplicationDeploy,
deployApplicationFunc func(ApplicationDeployer, DeployApplicationParams) (Application, error),
deployApplicationFunc func(ApplicationDeployer, Model, DeployApplicationParams) (Application, error),
storagePoolManager poolmanager.PoolManager,
registry storage.ProviderRegistry,
caasBroker caasBrokerInterface,
Expand Down Expand Up @@ -556,7 +556,7 @@ func deployApplication(
if err != nil {
return errors.Trace(err)
}
_, err = deployApplicationFunc(backend, DeployApplicationParams{
_, err = deployApplicationFunc(backend, model, DeployApplicationParams{
ApplicationName: args.ApplicationName,
Series: args.Series,
Charm: stateCharm(ch),
Expand All @@ -572,6 +572,7 @@ func deployApplication(
AttachStorage: attachStorage,
EndpointBindings: bindings.Map(),
Resources: args.Resources,
Force: args.Force,
})
return errors.Trace(err)
}
Expand Down Expand Up @@ -1045,6 +1046,20 @@ func (api *APIBase) applicationSetCharm(
}
}

// Enforce "assumes" requirements if the feature flag is enabled.
model, err := api.backend.Model()
if err != nil {
return errors.Annotate(err, "retrieving model")
}

if err := assertCharmAssumptions(newCharm.Meta().Assumes, model, api.backend.ControllerConfig); err != nil {
if !errors.IsNotSupported(err) || !params.Force.Force {
return errors.Trace(err)
}

logger.Warningf("proceeding with upgrade of application %q even though the charm feature requirements could not be met as --force was specified", params.AppName)
}

force := params.Force
cfg := state.SetCharmConfig{
Charm: api.stateCharm(newCharm),
Expand Down
Loading

0 comments on commit 992dc0b

Please sign in to comment.