Skip to content

Commit

Permalink
Merge pull request juju#18932 from hpidcock/merge-3.6-main-20250218
Browse files Browse the repository at this point in the history
juju#18932

Forward ports:
- juju#18365
- juju#18701
- juju#18821
- juju#18849
- juju#18858
- juju#18861
- juju#18866
- juju#18868
- juju#18869
- juju#18902
- juju#18903
- juju#18909
- juju#18910
- juju#18911
- juju#18918
- juju#18931

Conflicts:
- CONTRIBUTING.md
- agent/agentbootstrap/bootstrap_test.go
- apiserver/facades/client/cloud/backend.go
- apiserver/facades/client/cloud/cloud.go
- apiserver/facades/client/cloud/cloud_test.go
- apiserver/facades/client/cloud/instance_information.go
- apiserver/facades/client/cloud/instance_information_test.go
- apiserver/facades/client/cloud/mocks/cloud_mock.go
- apiserver/facades/client/cloud/package_test.go
- cmd/juju/commands/bootstrap.go
- cmd/jujud-controller/agent/bootstrap.go
- controller/config.go
- controller/config_test.go
- controller/configschema.go
- docs/user/reference/configuration/list-of-controller-configuration-keys.md
- environs/bootstrap/bootstrap_test.go
- environs/bootstrap/config.go
- environs/jujutest/livetests.go
- internal/testing/cert.go
- internal/worker/deployer/nested_test.go
- juju/testing/conn.go
- provider/dummy/environs.go
- provider/dummy/environs_test.go
- state/controller_test.go
- state/initialize.go
- state/initialize_test.go
- state/internal_test.go
- state/model_test.go
- state/state_test.go
  • Loading branch information
jujubot authored Feb 18, 2025
2 parents b9d227d + 9d573d8 commit 4adfecd
Show file tree
Hide file tree
Showing 41 changed files with 1,014 additions and 163 deletions.
3 changes: 2 additions & 1 deletion agent/agentbootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ func (b *AgentBootstrap) Initialize(ctx context.Context) (_ *state.Controller, r
b.logger.Debugf(context.TODO(), "initializing address %v", info.Addrs)

ctrl, err := state.Initialize(state.InitializeParams{
Clock: clock.WallClock,
SSHServerHostKey: stateParams.SSHServerHostKey,
Clock: clock.WallClock,
ControllerModelArgs: state.ModelArgs{
Type: modelType,
Owner: b.adminUser,
Expand Down
2 changes: 2 additions & 0 deletions agent/agentbootstrap/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ func (s *bootstrapSuite) TestInitializeState(c *gc.C) {
"foo": "bar",
},
},
SSHServerHostKey: testing.SSHServerHostKey,
}
adminUser := names.NewLocalUserTag("agent-admin")
bootstrap, err := agentbootstrap.NewAgentBootstrap(
Expand Down Expand Up @@ -346,6 +347,7 @@ func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
},
ControllerConfig: testing.FakeControllerConfig(),
ControllerModelConfig: modelCfg,
SSHServerHostKey: testing.SSHServerHostKey,
}

adminUser := names.NewLocalUserTag("agent-admin")
Expand Down
1 change: 1 addition & 0 deletions apiserver/facades/client/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ func (api *CloudAPI) UpdateCredentialsCheckModels(ctx context.Context, args para
}
return params.UpdateCredentialResults{Results: results}, nil
}

func modelResultsToParams(modelResults []service.UpdateCredentialModelResult) []params.UpdateCredentialModelResult {
result := make([]params.UpdateCredentialModelResult, len(modelResults))
for i, modelResult := range modelResults {
Expand Down
36 changes: 36 additions & 0 deletions apiserver/facades/client/cloud/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,42 @@ func (s *cloudSuite) TestAddCloud(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
}

func (s *cloudSuite) TestAddCloudAsExternalUser(c *gc.C) {
// In this test we attempt to add a cloud as an authorized external user.

// User `superuser-alice@external` is an external user. We need the `superuser` prefix
// because of the fake authorized used in this test - means alice is has the
// `superuser` access level on the controller.
aliceTag := names.NewUserTag("superuser-alice@external")
defer s.setup(c, aliceTag).Finish()

cloudservice := s.cloudService.EXPECT()
cloud := jujucloud.Cloud{
Name: "newcloudname",
Type: "maas",
}
cloudservice.Cloud(gomock.Any(), "dummy").Return(&cloud, nil)
newCloud := jujucloud.Cloud{
Name: "newcloudname",
Type: "maas",
Endpoint: "fake-endpoint",
AuthTypes: []jujucloud.AuthType{jujucloud.EmptyAuthType, jujucloud.UserPassAuthType},
Regions: []jujucloud.Region{{Name: "nether", Endpoint: "nether-endpoint"}},
}
cloudservice.CreateCloud(gomock.Any(), user.NameFromTag(aliceTag), newCloud).Return(nil)
paramsCloud := params.AddCloudArgs{
Name: "newcloudname",
Cloud: params.Cloud{
Type: "maas",
AuthTypes: []string{"empty", "userpass"},
Endpoint: "fake-endpoint",
Regions: []params.CloudRegion{{Name: "nether", Endpoint: "nether-endpoint"}},
}}

err := s.api.AddCloud(context.Background(), paramsCloud)
c.Assert(err, jc.ErrorIsNil)
}

func createAddCloudParam(cloudType string) params.AddCloudArgs {
if cloudType == "" {
cloudType = "fake"
Expand Down
3 changes: 3 additions & 0 deletions apiserver/facades/client/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,15 +655,18 @@ func (s *controllerSuite) TestConfigSet(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
// Sanity check.
c.Assert(config.AuditingEnabled(), gc.Equals, false)
c.Assert(config.SSHServerPort(), gc.Equals, 17022)

err = s.controller.ConfigSet(context.Background(), params.ControllerConfigSet{Config: map[string]interface{}{
"auditing-enabled": true,
"ssh-server-port": 17023,
}})
c.Assert(err, jc.ErrorIsNil)

config, err = controllerConfigService.ControllerConfig(context.Background())
c.Assert(err, jc.ErrorIsNil)
c.Assert(config.AuditingEnabled(), gc.Equals, true)
c.Assert(config.SSHServerPort(), gc.Equals, 17023)
}

func (s *controllerSuite) TestConfigSetRequiresSuperUser(c *gc.C) {
Expand Down
3 changes: 2 additions & 1 deletion cmd/juju/commands/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ bootstrap by changing the following settings in your configuration
# How often to refresh controller addresses from the API server.
bootstrap-addresses-delay: 10 # default: 10 seconds
It is possible to override the base e.g. ubuntu@22.04, Juju attempts
It is possible to override the base e.g. ubuntu@22.04, Juju attempts
to bootstrap on to, by supplying a base argument to '--bootstrap-base'.
An error is emitted if the determined base is not supported. Using the
Expand Down Expand Up @@ -876,6 +876,7 @@ to create a new model to deploy %sworkloads.
RegionInheritedConfig: cloud.RegionConfig,
AdminSecret: bootstrapCfg.bootstrap.AdminSecret,
CAPrivateKey: bootstrapCfg.bootstrap.CAPrivateKey,
SSHServerHostKey: bootstrapCfg.bootstrap.SSHServerHostKey,
ControllerServiceType: bootstrapCfg.bootstrap.ControllerServiceType,
ControllerExternalName: bootstrapCfg.bootstrap.ControllerExternalName,
ControllerExternalIPs: append([]string(nil), bootstrapCfg.bootstrap.ControllerExternalIPs...),
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/storage/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type FilesystemInfo struct {
Storage string `yaml:"storage,omitempty" json:"storage,omitempty"`

// Attachments is the set of entities attached to the filesystem.
Attachments *FilesystemAttachments
Attachments *FilesystemAttachments `yaml:"attachments,omitempty" json:"attachments,omitempty"`

// Pool is the name of the storage pool that the filesystem came from.
Pool string `yaml:"pool,omitempty" json:"pool,omitempty"`
Expand Down
24 changes: 22 additions & 2 deletions cmd/jujud-controller/agent/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/juju/juju/internal/database"
internallogger "github.com/juju/juju/internal/logger"
"github.com/juju/juju/internal/mongo"
pkissh "github.com/juju/juju/internal/pki/ssh"
"github.com/juju/juju/internal/storage/provider"
"github.com/juju/juju/internal/tools"
"github.com/juju/juju/internal/worker/peergrouper"
Expand Down Expand Up @@ -269,7 +270,10 @@ func (c *BootstrapCommand) Run(ctx *cmd.Context) error {
if !ok {
return fmt.Errorf("bootstrap machine config has no state serving info")
}
if err := ensureKeys(isCAAS, args, &info); err != nil {
if err := ensureKeys(isCAAS, &args, &info); err != nil {
return errors.Trace(err)
}
if err := ensureSSHServerHostKey(&args); err != nil {
return errors.Trace(err)
}
addrs, err := getAddressesForMongo(isCAAS, env, ctx, args)
Expand Down Expand Up @@ -406,9 +410,24 @@ func getAddressesForMongo(
return addrs, nil
}

// ensureSSHServerHostKey ensures that either a) a user has provided a host key
// or b) one has been generated for the controller.
func ensureSSHServerHostKey(args *instancecfg.StateInitializationParams) error {
if args.SSHServerHostKey != "" {
return nil
}
// Generate the embedded SSH server host key and store it within StateInitializationParams.
hostKey, err := pkissh.GenerateED25519KeyString()
if err != nil {
return errors.Annotatef(err, "failed to ensure ssh server host key")
}
args.SSHServerHostKey = hostKey
return nil
}

func ensureKeys(
isCAAS bool,
args instancecfg.StateInitializationParams,
args *instancecfg.StateInitializationParams,
info *controller.StateServingInfo,
) error {
if isCAAS {
Expand All @@ -431,6 +450,7 @@ func ensureKeys(
return errors.Trace(err)
}
info.SharedSecret = sharedSecret

return nil
}

Expand Down
50 changes: 50 additions & 0 deletions controller/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,24 @@ const (
// Can be set to "legacy", "snapstore", "local" or "local-dangerous".
// Cannot be changed.
JujudControllerSnapSource = "jujud-controller-snap-source"

// SSHServerPort is the port used for the embedded SSH server.
SSHServerPort = "ssh-server-port"

// SSHMaxConcurrentConnections is the maximum number of concurrent SSH
// connections to the controller.
SSHMaxConcurrentConnections = "ssh-max-concurrent-connections"
)

// Attribute Defaults
const (
// DefaultSSHMaxConcurrentConnections is the default maximum number of
// concurrent SSH connections to the controller.
DefaultSSHMaxConcurrentConnections = 100

// DefaultSSHServerPort is the default port used for the embedded SSH server.
DefaultSSHServerPort = 17022

// DefaultApplicationResourceDownloadLimit allows unlimited
// resource download requests initiated by a unit agent per application.
DefaultApplicationResourceDownloadLimit = 0
Expand Down Expand Up @@ -531,6 +545,8 @@ var (
ObjectStoreS3StaticSession,
SystemSSHKeys,
JujudControllerSnapSource,
SSHMaxConcurrentConnections,
SSHServerPort,
}

// For backwards compatibility, we must include "anything", "juju-apiserver"
Expand Down Expand Up @@ -590,6 +606,8 @@ var (
ObjectStoreS3StaticKey,
ObjectStoreS3StaticSecret,
ObjectStoreS3StaticSession,
SSHMaxConcurrentConnections,
SSHServerPort,
)

methodNameRE = regexp.MustCompile(`[[:alpha:]][[:alnum:]]*\.[[:alpha:]][[:alnum:]]*`)
Expand Down Expand Up @@ -1137,6 +1155,17 @@ func (c Config) ObjectStoreS3StaticSession() string {
return c.asString(ObjectStoreS3StaticSession)
}

// SSHServerPort returns the port the SSH server listens on.
func (c Config) SSHServerPort() int {
return c.intOrDefault(SSHServerPort, DefaultSSHServerPort)
}

// SSHMaxConcurrentConnections returns the maximum number of concurrent
// SSH connections that the controller will allow.
func (c Config) SSHMaxConcurrentConnections() int {
return c.intOrDefault(SSHMaxConcurrentConnections, DefaultSSHMaxConcurrentConnections)
}

// Validate ensures that config is a valid configuration.
func Validate(c Config) error {
if v, ok := c[IdentityPublicKey].(string); ok {
Expand Down Expand Up @@ -1415,6 +1444,27 @@ func Validate(c Config) error {
}
}

if v, ok := c[SSHServerPort].(int); ok {
if v <= 0 {
return errors.NotValidf("non-positive integer for ssh-server-port")
}
if v == c.APIPort() {
return errors.NotValidf("ssh-server-port matching api-port")
}
if v == c.StatePort() {
return errors.NotValidf("ssh-server-port matching state-port")
}
if v == c.ControllerAPIPort() {
return errors.NotValidf("ssh-server-port matching controller-api-port")
}
}

if v, ok := c[SSHMaxConcurrentConnections].(int); ok {
if v <= 0 {
return errors.NotValidf("non-positive integer for ssh-max-concurrent-connections")
}
}

return nil
}

Expand Down
53 changes: 53 additions & 0 deletions controller/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,33 @@ var newConfigTests = []struct {
controller.ControllerName: "is_invalid",
},
expectError: `controller-name value must be a valid controller name.*`,
}, {
about: "invalid ssh port",
config: controller.Config{
controller.SSHServerPort: 0,
},
expectError: `non-positive integer for ssh-server-port not valid`,
}, {
about: "SSH port equals api server port",
config: controller.Config{
controller.APIPort: 17070,
controller.SSHServerPort: 17070,
},
expectError: `ssh-server-port matching api-port not valid`,
}, {
about: "SSH port equals state port",
config: controller.Config{
controller.StatePort: 17075,
controller.SSHServerPort: 17075,
},
expectError: `ssh-server-port matching state-port not valid`,
}, {
about: "SSH port equals controller api port",
config: controller.Config{
controller.ControllerAPIPort: 17078,
controller.SSHServerPort: 17078,
},
expectError: `ssh-server-port matching controller-api-port not valid`,
}}

func (s *ConfigSuite) TestNewConfig(c *gc.C) {
Expand Down Expand Up @@ -787,6 +814,8 @@ func (s *ConfigSuite) TestDefaults(c *gc.C) {
c.Assert(cfg.ControllerResourceDownloadLimit(), gc.Equals, controller.DefaultControllerResourceDownloadLimit)
c.Assert(cfg.QueryTracingEnabled(), gc.Equals, controller.DefaultQueryTracingEnabled)
c.Assert(cfg.QueryTracingThreshold(), gc.Equals, controller.DefaultQueryTracingThreshold)
c.Assert(cfg.SSHServerPort(), gc.Equals, controller.DefaultSSHServerPort)
c.Assert(cfg.SSHMaxConcurrentConnections(), gc.Equals, controller.DefaultSSHMaxConcurrentConnections)
}

func (s *ConfigSuite) TestAgentLogfile(c *gc.C) {
Expand Down Expand Up @@ -1006,6 +1035,30 @@ func (s *ConfigSuite) TestOpenTelemetryTailSamplingThreshold(c *gc.C) {
c.Assert(cfg.OpenTelemetryTailSamplingThreshold(), gc.Equals, time.Second)
}

func (s *ConfigSuite) TestSSHServerPort(c *gc.C) {
cfg, err := controller.NewConfig(
testing.ControllerTag.Id(),
testing.CACert,
map[string]interface{}{
controller.SSHServerPort: 10,
},
)
c.Assert(err, jc.ErrorIsNil)
c.Assert(cfg.SSHServerPort(), gc.Equals, 10)
}

func (s *ConfigSuite) TestSSHServerConcurrentConnections(c *gc.C) {
cfg, err := controller.NewConfig(
testing.ControllerTag.Id(),
testing.CACert,
map[string]interface{}{
controller.SSHMaxConcurrentConnections: 10,
},
)
c.Assert(err, jc.ErrorIsNil)
c.Assert(cfg.SSHMaxConcurrentConnections(), gc.Equals, 10)
}

func (s *ConfigSuite) TestObjectStoreType(c *gc.C) {
backendType := "file"
cfg, err := controller.NewConfig(
Expand Down
Loading

0 comments on commit 4adfecd

Please sign in to comment.