Skip to content

Commit

Permalink
Merge branch '3.0' into 3.0-develop-merge-20230119
Browse files Browse the repository at this point in the history
  • Loading branch information
hpidcock committed Jan 19, 2023
2 parents 86fbe64 + 8155654 commit 0eebc95
Show file tree
Hide file tree
Showing 18 changed files with 249 additions and 105 deletions.
2 changes: 1 addition & 1 deletion cmd/juju/application/integrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func (c *addRelationCommand) Run(ctx *cmd.Context) error {
splitError := strings.Join(strings.Split(err.Error(), ": "), "\n")
infoErr := errors.Errorf(`
Use 'juju status --integrations' to view the current integrations.`)
Use 'juju status --relations' to view the current relations.`)
return errors.Annotatef(infoErr, splitError)
}
if err != nil {
Expand Down
15 changes: 14 additions & 1 deletion cmd/juju/controller/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,24 @@ func (c *configCommand) setConfig(client controllerAPI, attrs config.Attrs) erro
}

// Check if any of the `attrs` are not allowed to be set
fields, _, err := controller.ConfigSchema.ValidationSchema()
if err != nil {
return errors.Trace(err)
}

extraValues := set.NewStrings()
values := make(map[string]interface{})
for k := range attrs {
if controller.AllowedUpdateConfigAttributes.Contains(k) {
values[k] = attrs[k]
if field, ok := fields[k]; ok {
v, err := field.Coerce(attrs[k], []string{k})
if err != nil {
return err
}
values[k] = v
} else {
values[k] = attrs[k]
}
} else {
extraValues.Add(k)
}
Expand Down
15 changes: 14 additions & 1 deletion cmd/juju/controller/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ func (s *ConfigSuite) TestSettingKey(c *gc.C) {
c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"juju-ha-space": "value"})
}

func (s *ConfigSuite) TestSettingDuration(c *gc.C) {
var api fakeControllerAPI
context, err := s.runWithAPI(c, &api, "api-port-open-delay=100ms")
c.Assert(err, jc.ErrorIsNil)

output := strings.TrimSpace(cmdtesting.Stdout(context))
c.Assert(output, gc.Equals, "")

c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"api-port-open-delay": "100ms"})
}

func (s *ConfigSuite) TestSettingComplexKey(c *gc.C) {
var api fakeControllerAPI
context, err := s.runWithAPI(c, &api, "features=[value1,value2]")
Expand Down Expand Up @@ -227,7 +238,9 @@ func (s *ConfigSuite) TestOverrideFileFromArgs(c *gc.C) {
c.Assert(output, gc.Equals, "")

c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
"juju-ha-space": "value", "audit-log-max-backups": "4"})
"juju-ha-space": "value",
"audit-log-max-backups": 4,
})
}

func (s *ConfigSuite) TestErrorOnSetting(c *gc.C) {
Expand Down
9 changes: 1 addition & 8 deletions cmd/juju/controller/listmodels.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,10 @@ func (c *modelsCommand) SetFlags(f *gnuflag.FlagSet) {
func (c *modelsCommand) Run(ctx *cmd.Context) error {
controllerName, err := c.ControllerName()
if err != nil {
ctx.Infof(err.Error())
return errors.Trace(err)
}
accountDetails, err := c.CurrentAccountDetails()
if err != nil {
ctx.Infof(err.Error())
return err
}
c.loggedInUser = accountDetails.User
Expand All @@ -105,9 +103,7 @@ func (c *modelsCommand) Run(ctx *cmd.Context) error {
c.user = accountDetails.User
}
if !names.IsValidUser(c.user) {
err := errors.NotValidf("user %q", c.user)
ctx.Infof(err.Error())
return err
return errors.NotValidf("user %q", c.user)
}

c.runVars = modelsRunValues{
Expand All @@ -119,14 +115,12 @@ func (c *modelsCommand) Run(ctx *cmd.Context) error {

modelmanagerAPI, err := c.getModelManagerAPI()
if err != nil {
ctx.Infof(err.Error())
return errors.Trace(err)
}
defer modelmanagerAPI.Close()

haveModels, err := c.getModelSummaries(ctx, modelmanagerAPI, now)
if err != nil {
ctx.Infof(err.Error())
return err
}
if !haveModels && c.out.Name() == "tabular" {
Expand Down Expand Up @@ -289,7 +283,6 @@ func (c *modelsCommand) modelSummaryFromParams(apiSummary base.UserModelSummary,

if apiSummary.ProviderType != "" {
summary.ProviderType = apiSummary.ProviderType

}
if apiSummary.CloudCredential != "" {
if !names.IsValidCloudCredential(apiSummary.CloudCredential) {
Expand Down
13 changes: 3 additions & 10 deletions cmd/juju/controller/listmodels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,14 @@ func (f *fakeModelMgrAPIClient) ListModelSummaries(user string, all bool) ([]bas
cloud, err := names.ParseCloudTag(info.Result.CloudTag)
if err != nil {
cloud = names.NewCloudTag("aws")

}
cred, err := names.ParseCloudCredentialTag(info.Result.CloudCredentialTag)
if err != nil {
cred = names.NewCloudCredentialTag("foo/bob/one")

}
owner, err := names.ParseUserTag(info.Result.OwnerTag)
if err != nil {
owner = names.NewUserTag("admin")

}
results[i] = base.UserModelSummary{
Name: info.Result.Name,
Expand Down Expand Up @@ -231,7 +228,7 @@ func (s *ModelsSuite) SetUpTest(c *gc.C) {
LastConnection: &last1,
Access: params.ModelReadAccess,
}}
//2nd model
// 2nd model
secondModel := s.api.infos[1].Result
last2 := time.Date(2015, 3, 1, 0, 0, 0, 0, time.UTC)
secondModel.Users = []params.ModelUserInfo{{
Expand Down Expand Up @@ -361,19 +358,15 @@ func (s *ModelsSuite) TestUnrecognizedArg(c *gc.C) {
}

func (s *ModelsSuite) TestInvalidUser(c *gc.C) {
context, err := cmdtesting.RunCommand(c, s.newCommand(), "--user", "+bob")
_, err := cmdtesting.RunCommand(c, s.newCommand(), "--user", "+bob")
c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`user "+bob" not valid`))
c.Assert(cmdtesting.Stdout(context), gc.Equals, "")
c.Assert(cmdtesting.Stderr(context), gc.Equals, "user \"+bob\" not valid\n")
s.api.CheckNoCalls(c)
}

func (s *ModelsSuite) TestModelsError(c *gc.C) {
s.api.err = apiservererrors.ErrPerm
context, err := cmdtesting.RunCommand(c, s.newCommand())
_, err := cmdtesting.RunCommand(c, s.newCommand())
c.Assert(err, gc.ErrorMatches, "permission denied")
c.Assert(cmdtesting.Stdout(context), gc.Equals, "")
c.Assert(cmdtesting.Stderr(context), gc.Equals, "permission denied\n")
s.checkAPICalls(c, "ListModelSummaries", "Close")
}

Expand Down
47 changes: 10 additions & 37 deletions controller/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ const (
DefaultAPIPort int = 17070

// DefaultAPIPortOpenDelay is the default value for api-port-open-delay.
// It is a string representation of a time.Duration.
DefaultAPIPortOpenDelay = "2s"
DefaultAPIPortOpenDelay = 2 * time.Second

// DefaultMongoMemoryProfile is the default profile used by mongo.
DefaultMongoMemoryProfile = MongoProfDefault
Expand Down Expand Up @@ -358,7 +357,7 @@ const (
// processing 1000 txs seems to take about 100ms, so a sleep time of 10ms
// represents a 10% slowdown, but allows other systems to
// operate concurrently.
DefaultPruneTxnSleepTime = "10ms"
DefaultPruneTxnSleepTime = 10 * time.Millisecond

// DefaultMaxCharmStateSize is the maximum size (in bytes) of charm
// state data that each unit can store to the controller.
Expand All @@ -377,7 +376,7 @@ const (
DefaultBatchRaftFSM = false

// DefaultMigrationMinionWaitMax is the default value for
DefaultMigrationMinionWaitMax = "15m"
DefaultMigrationMinionWaitMax = 15 * time.Minute
)

var (
Expand Down Expand Up @@ -630,11 +629,7 @@ func (c Config) APIPort() int {
// the APIPort once the controller has started up. Only used when
// the ControllerAPIPort is non-zero.
func (c Config) APIPortOpenDelay() time.Duration {
v := c.asString(APIPortOpenDelay)
// We know that v must be a parseable time.Duration for the config
// to be valid.
d, _ := time.ParseDuration(v)
return d
return c.durationOrDefault(APIPortOpenDelay, DefaultAPIPortOpenDelay)
}

// ControllerAPIPort returns the optional API port to be used for
Expand Down Expand Up @@ -873,11 +868,7 @@ func (c Config) ModelLogsSizeMB() int {
// MaxDebugLogDuration is the maximum time a debug-log session is allowed
// to run before it is terminated by the server.
func (c Config) MaxDebugLogDuration() time.Duration {
duration, ok := c[MaxDebugLogDuration].(time.Duration)
if !ok {
duration = DefaultMaxDebugLogDuration
}
return duration
return c.durationOrDefault(MaxDebugLogDuration, DefaultMaxDebugLogDuration)
}

// MaxTxnLogSizeMB is the maximum size in MiB of the txn log collection.
Expand All @@ -902,16 +893,7 @@ func (c Config) PruneTxnQueryCount() int {

// PruneTxnSleepTime is the amount of time to sleep between batches.
func (c Config) PruneTxnSleepTime() time.Duration {
asInterface, ok := c[PruneTxnSleepTime]
if !ok {
asInterface = DefaultPruneTxnSleepTime
}
asStr, ok := asInterface.(string)
if !ok {
asStr = DefaultPruneTxnSleepTime
}
val, _ := time.ParseDuration(asStr)
return val
return c.durationOrDefault(PruneTxnSleepTime, DefaultPruneTxnSleepTime)
}

// PublicDNSAddress returns the DNS name of the controller.
Expand Down Expand Up @@ -1023,16 +1005,7 @@ func (c Config) BatchRaftFSM() bool {
// migration-master worker should wait for migration-minion reports during
// phases of a model migration.
func (c Config) MigrationMinionWaitMax() time.Duration {
asInterface, ok := c[MigrationMinionWaitMax]
if !ok {
asInterface = DefaultMigrationMinionWaitMax
}
asStr, ok := asInterface.(string)
if !ok {
asStr = DefaultMigrationMinionWaitMax
}
val, _ := time.ParseDuration(asStr)
return val
return c.durationOrDefault(MigrationMinionWaitMax, DefaultMigrationMinionWaitMax)
}

// Validate ensures that config is a valid configuration.
Expand Down Expand Up @@ -1332,7 +1305,7 @@ var configChecker = schema.FieldMap(schema.Fields{
AuditLogMaxBackups: schema.ForceInt(),
AuditLogExcludeMethods: schema.List(schema.String()),
APIPort: schema.ForceInt(),
APIPortOpenDelay: schema.String(),
APIPortOpenDelay: schema.TimeDuration(),
ControllerAPIPort: schema.ForceInt(),
ControllerName: schema.String(),
StatePort: schema.ForceInt(),
Expand All @@ -1354,7 +1327,7 @@ var configChecker = schema.FieldMap(schema.Fields{
ModelLogfileMaxSize: schema.String(),
ModelLogsSize: schema.String(),
PruneTxnQueryCount: schema.ForceInt(),
PruneTxnSleepTime: schema.String(),
PruneTxnSleepTime: schema.TimeDuration(),
PublicDNSAddress: schema.String(),
JujuHASpace: schema.String(),
JujuManagementSpace: schema.String(),
Expand All @@ -1366,7 +1339,7 @@ var configChecker = schema.FieldMap(schema.Fields{
MaxAgentStateSize: schema.ForceInt(),
NonSyncedWritesToRaftLog: schema.Bool(),
BatchRaftFSM: schema.Bool(),
MigrationMinionWaitMax: schema.String(),
MigrationMinionWaitMax: schema.TimeDuration(),
ApplicationResourceDownloadLimit: schema.ForceInt(),
ControllerResourceDownloadLimit: schema.ForceInt(),
}, schema.Defaults{
Expand Down
10 changes: 4 additions & 6 deletions controller/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,13 @@ var newConfigTests = []struct {
config: controller.Config{
controller.APIPortOpenDelay: "15",
},
expectError: `api-port-open-delay value "15" must be a valid duration`,
expectError: `api-port-open-delay: conversion to duration: time: missing unit in duration "15"`,
}, {
about: "txn-prune-sleep-time not a duration",
config: controller.Config{
controller.PruneTxnSleepTime: "15",
},
expectError: `prune-txn-sleep-time must be a valid duration \(eg "10ms"\): time: missing unit in duration "?15"?`,
expectError: `prune-txn-sleep-time: conversion to duration: time: missing unit in duration "15"`,
}, {
about: "mongo-memory-profile not valid",
config: controller.Config{
Expand Down Expand Up @@ -386,7 +386,7 @@ var newConfigTests = []struct {
config: controller.Config{
controller.MigrationMinionWaitMax: "15",
},
expectError: `migration-agent-wait-time value "15" must be a valid duration`,
expectError: `migration-agent-wait-time: conversion to duration: time: missing unit in duration "15"`,
}, {
about: "application-resource-download-limit cannot be negative",
config: controller.Config{
Expand Down Expand Up @@ -925,9 +925,7 @@ func (s *ConfigSuite) TestMigrationMinionWaitMax(c *gc.C) {
testing.CACert, nil)
c.Assert(err, jc.ErrorIsNil)

defaultDuration, err := time.ParseDuration(controller.DefaultMigrationMinionWaitMax)
c.Assert(err, jc.ErrorIsNil)
c.Assert(cfg.MigrationMinionWaitMax(), gc.Equals, defaultDuration)
c.Assert(cfg.MigrationMinionWaitMax(), gc.Equals, controller.DefaultMigrationMinionWaitMax)

cfg[controller.MigrationMinionWaitMax] = "500ms"
c.Assert(cfg.MigrationMinionWaitMax(), gc.Equals, 500*time.Millisecond)
Expand Down
2 changes: 1 addition & 1 deletion featuretests/cmd_juju_relation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (s *CmdRelationSuite) TestAddRelationSuccessOnAlreadyExists(c *gc.C) {
c.Check(cmdtesting.Stderr(context), jc.Contains, `ERROR cannot add relation "wordpress:db mysql:server"
relation wordpress:db mysql:server (already exists):
Use 'juju status --integrations' to view the current integrations.
Use 'juju status --relations' to view the current relations.
`)
}

Expand Down
38 changes: 14 additions & 24 deletions network/containerizer/bridgepolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,24 +245,29 @@ func linkLayerDevicesForSpaces(host Machine, spaces corenetwork.SpaceInfos) (map
if err != nil {
return nil, errors.Trace(err)
}
processedDeviceNames := set.NewStrings()
spaceToDevices := make(namedNICsBySpace, 0)

// First pass, iterate the addresses, lookup the associated spaces, and
// gather the devices.
addresses, err := host.AllDeviceAddresses()
if err != nil {
return nil, errors.Trace(err)
}

// Iterate all addresses and key them by the address device name.
addressByDeviceName := make(map[string]Address)
for _, addr := range addresses {
device, ok := deviceByName[addr.DeviceName()]
addressByDeviceName[addr.DeviceName()] = addr
}

// Iterate the devices by name, lookup the associated spaces, and
// gather the devices.
spaceToDevices := make(namedNICsBySpace, 0)
for _, device := range deviceByName {
addr, ok := addressByDeviceName[device.Name()]
if !ok {
return nil, errors.Errorf("address %v for machine %q refers to a missing device %q",
addr, host.Id(), addr.DeviceName())
logger.Infof("device %q has no addresses, ignoring", device.Name())
continue
}
processedDeviceNames.Add(device.Name())

// We do not care about loopback devices.
// Loopback devices are not considered part of the empty space.
if device.Type() == corenetwork.LoopbackDevice {
continue
}
Expand All @@ -281,21 +286,6 @@ func linkLayerDevicesForSpaces(host Machine, spaces corenetwork.SpaceInfos) (map
spaceToDevices = includeDevice(spaceToDevices, spaceID, device)
}

// Second pass, grab any devices we may have missed. For now, any device without an
// address must be in the default space.
for devName, device := range deviceByName {
if processedDeviceNames.Contains(devName) {
continue
}
// Loopback devices are not considered part of the empty space.
// Also, devices that are attached to another device also aren't
// considered to be in the unknown space.
if device.Type() == corenetwork.LoopbackDevice || device.ParentName() != "" {
continue
}
spaceToDevices = includeDevice(spaceToDevices, corenetwork.AlphaSpaceId, device)
}

result := make(map[string][]LinkLayerDevice, len(spaceToDevices))
for spaceID, deviceMap := range spaceToDevices {
if !spaces.ContainsID(spaceID) {
Expand Down
4 changes: 3 additions & 1 deletion network/containerizer/bridgepolicy_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,9 @@ func (s *bridgePolicyStateSuite) TestFindMissingBridgesForContainerContainerNetw
// machine. Triggers the fallback code to have us bridge all devices.
missing, reconfigureDelay, err := bridgePolicy.FindMissingBridgesForContainer(s.machine, s.containerMachine)
c.Assert(err, jc.ErrorIsNil)
c.Check(missing, jc.DeepEquals, []network.DeviceToBridge{})
c.Check(missing, jc.DeepEquals, []network.DeviceToBridge{
{DeviceName: "ens3", BridgeName: "br-ens3", MACAddress: ""},
})
c.Check(reconfigureDelay, gc.Equals, 0)
}

Expand Down
Loading

0 comments on commit 0eebc95

Please sign in to comment.