diff --git a/overlord/configstate/configcore/corecfg_test.go b/overlord/configstate/configcore/corecfg_test.go index 633e7a2a56f..232b638c832 100644 --- a/overlord/configstate/configcore/corecfg_test.go +++ b/overlord/configstate/configcore/corecfg_test.go @@ -133,7 +133,7 @@ type configcoreSuite struct { state *state.State - systemctlOutput func(args ...string) []byte + systemctlOutput func(args ...string) ([]byte, error) systemctlArgs [][]string systemdSysctlArgs [][]string } @@ -148,7 +148,7 @@ func (s *configcoreSuite) SetUpTest(c *C) { s.AddCleanup(osutil.MockMountInfo("")) - s.systemctlOutput = func(args ...string) []byte { + s.systemctlOutput = func(args ...string) ([]byte, error) { if args[0] == "show" { return []byte(fmt.Sprintf(`Type=notify Id=%[1]s @@ -156,14 +156,14 @@ Names=%[1]s ActiveState=inactive UnitFileState=enabled NeedDaemonReload=no -`, args[len(args)-1])) +`, args[len(args)-1])), nil } - return []byte("ActiveState=inactive") + return []byte("ActiveState=inactive"), nil } s.AddCleanup(systemd.MockSystemctl(func(args ...string) ([]byte, error) { s.systemctlArgs = append(s.systemctlArgs, args[:]) - return s.systemctlOutput(args...), nil + return s.systemctlOutput(args...) })) s.systemctlArgs = nil s.AddCleanup(systemd.MockSystemdSysctl(func(args ...string) error { diff --git a/overlord/configstate/configcore/ctrlaltdel_test.go b/overlord/configstate/configcore/ctrlaltdel_test.go index d502345a89c..e7ac383b1e4 100644 --- a/overlord/configstate/configcore/ctrlaltdel_test.go +++ b/overlord/configstate/configcore/ctrlaltdel_test.go @@ -59,7 +59,7 @@ var _ = Suite(&ctrlaltdelSuite{}) func (s *ctrlaltdelSuite) SetUpTest(c *C) { s.configcoreSuite.SetUpTest(c) - s.systemctlOutput = func(args ...string) []byte { + s.systemctlOutput = func(args ...string) ([]byte, error) { var output []byte // 'args' represents the arguments passed in for the systemctl Status call. // The test context is specific to the ctrlaltdel handler, which only uses @@ -91,7 +91,7 @@ func (s *ctrlaltdelSuite) SetUpTest(c *C) { // No output returned by systemctl } } - return output + return output, nil } s.unit = unitStateNone c.Assert(os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "etc"), 0755), IsNil) diff --git a/overlord/configstate/configcore/services.go b/overlord/configstate/configcore/services.go index 475b8f1cbc2..b55a33d3a87 100644 --- a/overlord/configstate/configcore/services.go +++ b/overlord/configstate/configcore/services.go @@ -372,8 +372,19 @@ func handleServiceConfigSSHListen(dev sysconfig.Device, tr ConfGetter, opts *fsO if opts == nil { sysd := systemd.New(systemd.SystemMode, &sysdLogger{}) - if err := sysd.ReloadOrRestart([]string{"ssh.service"}); err != nil { - return err + // From 22.10 sshd now uses socket based activation. This changes how to reload ssh configuration + // Discussion here: https://discourse.ubuntu.com/t/sshd-now-uses-socket-based-activation-ubuntu-22-10-and-later/30189/9 + if enabled, err := sysd.IsEnabled("ssh.socket"); err == nil && enabled { + if err := sysd.DaemonReload(); err != nil { + return err + } + if err := sysd.Restart([]string{"ssh.socket"}); err != nil { + return err + } + } else { + if err := sysd.ReloadOrRestart([]string{"ssh.service"}); err != nil { + return err + } } } diff --git a/overlord/configstate/configcore/services_test.go b/overlord/configstate/configcore/services_test.go index 6049a3a8ca1..a4054f8914e 100644 --- a/overlord/configstate/configcore/services_test.go +++ b/overlord/configstate/configcore/services_test.go @@ -35,14 +35,16 @@ import ( type servicesSuite struct { configcoreSuite serviceInstalled bool + socketEnabled bool } var _ = Suite(&servicesSuite{}) func (s *servicesSuite) SetUpTest(c *C) { s.configcoreSuite.SetUpTest(c) - s.systemctlOutput = func(args ...string) []byte { + s.systemctlOutput = func(args ...string) ([]byte, error) { var output []byte + var err error if args[0] == "show" { if args[1] == "--property=ActiveState" { output = []byte("ActiveState=inactive") @@ -53,8 +55,14 @@ func (s *servicesSuite) SetUpTest(c *C) { output = []byte(fmt.Sprintf("Id=%s\nType=\nActiveState=inactive\nUnitFileState=\nNames=%[1]s\nNeedDaemonReload=no\n", args[2])) } } + } else if args[0] == "is-enabled" { + if s.socketEnabled { + output = []byte("enabled\n") + } else { + err = fmt.Errorf("disabled\n") + } } - return output + return output, err } c.Assert(os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "etc"), 0755), IsNil) @@ -437,6 +445,28 @@ func (s *servicesSuite) TestConfigureNetworkValid(c *C) { } } +func (s *servicesSuite) TestConfigureNetworkValidWithSocketPresent(c *C) { + s.socketEnabled = true + defer func() { s.socketEnabled = false }() + + sshListenCfg := filepath.Join(dirs.GlobalRootDir, "/etc/ssh/sshd_config.d/listen.conf") + err := configcore.FilesystemOnlyRun(core20Dev, &mockConf{ + state: s.state, + changes: map[string]interface{}{ + "service.ssh.listen-address": "10.0.2.2", + }, + }) + c.Assert(err, IsNil) + c.Check(sshListenCfg, testutil.FileEquals, "ListenAddress 10.0.2.2\n") + c.Check(s.systemctlArgs, DeepEquals, [][]string{ + {"is-enabled", "ssh.socket"}, + {"daemon-reload"}, + {"stop", "ssh.socket"}, + {"show", "--property=ActiveState", "ssh.socket"}, + {"start", "ssh.socket"}, + }) +} + func (s *servicesSuite) TestSamePortNoChange(c *C) { err := configcore.FilesystemOnlyRun(core20Dev, &mockConf{ state: s.state, @@ -463,6 +493,7 @@ func (s *servicesSuite) TestConfigureNetworkIntegrationSSHListenAddress(c *C) { sshListenCfg := filepath.Join(dirs.GlobalRootDir, "/etc/ssh/sshd_config.d/listen.conf") c.Check(sshListenCfg, testutil.FileEquals, "ListenAddress 0.0.0.0:8022\nListenAddress [::]:8022\n") c.Check(s.systemctlArgs, DeepEquals, [][]string{ + {"is-enabled", "ssh.socket"}, {"reload-or-restart", "ssh.service"}, }) @@ -492,6 +523,7 @@ func (s *servicesSuite) TestConfigureNetworkIntegrationSSHListenAddressMulti(c * sshListenCfg := filepath.Join(dirs.GlobalRootDir, "/etc/ssh/sshd_config.d/listen.conf") c.Check(sshListenCfg, testutil.FileEquals, "ListenAddress 0.0.0.0:8022\nListenAddress [::]:8022\nListenAddress 192.168.99.4:9922\n") c.Check(s.systemctlArgs, DeepEquals, [][]string{ + {"is-enabled", "ssh.socket"}, {"reload-or-restart", "ssh.service"}, }) }