From 1ccb02c2bb7afd34db73d8fe4bc27fd637e3ae79 Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Wed, 4 Dec 2024 15:56:28 -0500 Subject: [PATCH 1/4] wip --- lib/autoupdate/agent/setup.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/autoupdate/agent/setup.go b/lib/autoupdate/agent/setup.go index b51e378208715..26f48a13789ab 100644 --- a/lib/autoupdate/agent/setup.go +++ b/lib/autoupdate/agent/setup.go @@ -69,6 +69,9 @@ RandomizedDelaySec=1m [Install] WantedBy={{.TeleportService}} ` + + // /etc/needrestart/conf.d/90-teleport.conf + needrestartDisableConf = `$nrconf{override_rc}{qr(^teleport\.service)} = 0;` + "\n" ) // Namespace represents a namespace within various system paths for a isolated installation of Teleport. From 5976abdbbf3185574c82c2814c1ade3a971e2f5e Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Thu, 5 Dec 2024 01:08:45 -0500 Subject: [PATCH 2/4] Add more config --- lib/autoupdate/agent/setup.go | 157 ++++++++++++------ lib/autoupdate/agent/setup_test.go | 144 ++++++++-------- .../no_namespace/dropin.golden | 4 + .../no_namespace/needrestart.golden | 1 + .../test_namespace/dropin.golden | 4 + .../test_namespace/needrestart.golden | 1 + 6 files changed, 197 insertions(+), 114 deletions(-) create mode 100644 lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/dropin.golden create mode 100644 lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/needrestart.golden create mode 100644 lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/dropin.golden create mode 100644 lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/needrestart.golden diff --git a/lib/autoupdate/agent/setup.go b/lib/autoupdate/agent/setup.go index 26f48a13789ab..9201e5406950e 100644 --- a/lib/autoupdate/agent/setup.go +++ b/lib/autoupdate/agent/setup.go @@ -27,6 +27,7 @@ import ( "os" "path/filepath" "regexp" + "strings" "text/template" "github.com/google/renameio/v2" @@ -37,13 +38,14 @@ import ( // Base paths for constructing namespaced directories. const ( - teleportOptDir = "/opt/teleport" - versionsDirName = "versions" - systemdAdminDir = "/etc/systemd/system" - systemdPIDFile = "/run/teleport.pid" - defaultNamespace = "default" - systemNamespace = "system" - lockFileName = "update.lock" + teleportOptDir = "/opt/teleport" + systemdAdminDir = "/etc/systemd/system" + systemdPIDFile = "/run/teleport.pid" + needrestartConfDir = "/etc/needrestart/conf.d" + versionsDirName = "versions" + lockFileName = "update.lock" + defaultNamespace = "default" + systemNamespace = "system" ) const ( @@ -68,10 +70,15 @@ RandomizedDelaySec=1m [Install] WantedBy={{.TeleportService}} +` + teleportDropInTemplate = `# teleport-update +# DO NOT EDIT THIS FILE +[Service] +Environment=TELEPORT_UPDATE_CONFIG_FILE={{.UpdaterConfigFile}} ` - // /etc/needrestart/conf.d/90-teleport.conf - needrestartDisableConf = `$nrconf{override_rc}{qr(^teleport\.service)} = 0;` + "\n" + needrestartConfTemplate = `$nrconf{override_rc}{qr(^{{replace .TeleportService "." "\\."}})} = 0; +` ) // Namespace represents a namespace within various system paths for a isolated installation of Teleport. @@ -101,6 +108,10 @@ type Namespace struct { updaterServiceFile string // updaterTimerFile is the systemd timer path for the updater updaterTimerFile string + // dropInFile is the Teleport systemd drop-in path extending Teleport + dropInFile string + // needrestartConfFile is the path to needrestart configuration for Teleport + needrestartConfFile string } var alphanum = regexp.MustCompile("^[a-zA-Z0-9-]*$") @@ -123,19 +134,21 @@ func NewNamespace(log *slog.Logger, name, dataDir, linkDir string) (*Namespace, linkDir = DefaultLinkDir } return &Namespace{ - log: log, - name: name, - dataDir: dataDir, - linkDir: linkDir, - versionsDir: filepath.Join(namespaceDir(name), versionsDirName), - serviceFile: filepath.Join("/", serviceDir, serviceName), - configFile: defaults.ConfigFilePath, - pidFile: systemdPIDFile, - updaterLockFile: filepath.Join(namespaceDir(name), lockFileName), - updaterConfigFile: filepath.Join(namespaceDir(name), updateConfigName), - updaterBinFile: filepath.Join(linkDir, BinaryName), - updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+".service"), - updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+".timer"), + log: log, + name: name, + dataDir: dataDir, + linkDir: linkDir, + versionsDir: filepath.Join(namespaceDir(name), versionsDirName), + serviceFile: filepath.Join("/", serviceDir, serviceName), + configFile: defaults.ConfigFilePath, + pidFile: systemdPIDFile, + updaterLockFile: filepath.Join(namespaceDir(name), lockFileName), + updaterConfigFile: filepath.Join(namespaceDir(name), updateConfigName), + updaterBinFile: filepath.Join(linkDir, BinaryName), + updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+".service"), + updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+".timer"), + dropInFile: filepath.Join(systemdAdminDir, "teleport.service.d", BinaryName+".conf"), + needrestartConfFile: filepath.Join(needrestartConfDir, BinaryName+".conf"), }, nil } @@ -147,19 +160,21 @@ func NewNamespace(log *slog.Logger, name, dataDir, linkDir string) (*Namespace, linkDir = filepath.Join(namespaceDir(name), "bin") } return &Namespace{ - log: log, - name: name, - dataDir: dataDir, - linkDir: linkDir, - versionsDir: filepath.Join(namespaceDir(name), versionsDirName), - serviceFile: filepath.Join(systemdAdminDir, prefix+".service"), - configFile: filepath.Join(filepath.Dir(defaults.ConfigFilePath), prefix+".yaml"), - pidFile: filepath.Join(filepath.Dir(systemdPIDFile), prefix+".pid"), - updaterLockFile: filepath.Join(namespaceDir(name), lockFileName), - updaterConfigFile: filepath.Join(namespaceDir(name), updateConfigName), - updaterBinFile: filepath.Join(linkDir, BinaryName), - updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".service"), - updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".timer"), + log: log, + name: name, + dataDir: dataDir, + linkDir: linkDir, + versionsDir: filepath.Join(namespaceDir(name), versionsDirName), + serviceFile: filepath.Join(systemdAdminDir, prefix+".service"), + configFile: filepath.Join(filepath.Dir(defaults.ConfigFilePath), prefix+".yaml"), + pidFile: filepath.Join(filepath.Dir(systemdPIDFile), prefix+".pid"), + updaterLockFile: filepath.Join(namespaceDir(name), lockFileName), + updaterConfigFile: filepath.Join(namespaceDir(name), updateConfigName), + updaterBinFile: filepath.Join(linkDir, BinaryName), + updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".service"), + updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".timer"), + dropInFile: filepath.Join(systemdAdminDir, "teleport.service.d", BinaryName+"_"+name+".conf"), + needrestartConfFile: filepath.Join(needrestartConfDir, BinaryName+"_"+name+".conf"), }, nil } @@ -181,7 +196,7 @@ func (ns *Namespace) Init() (lockFile string, err error) { // Setup installs service and timer files for the teleport-update binary. // Afterwords, Setup reloads systemd and enables the timer with --now. func (ns *Namespace) Setup(ctx context.Context) error { - err := ns.writeConfigFiles() + err := ns.writeConfigFiles(ctx) if err != nil { return trace.Wrap(err, "failed to write teleport-update systemd config files") } @@ -207,11 +222,15 @@ func (ns *Namespace) Teardown(ctx context.Context) error { if err := svc.Disable(ctx); err != nil { return trace.Wrap(err, "failed to disable teleport-update systemd timer") } - if err := os.Remove(ns.updaterServiceFile); err != nil && !errors.Is(err, fs.ErrNotExist) { - return trace.Wrap(err, "failed to remove teleport-update systemd service") - } - if err := os.Remove(ns.updaterTimerFile); err != nil && !errors.Is(err, fs.ErrNotExist) { - return trace.Wrap(err, "failed to remove teleport-update systemd timer") + for _, p := range []string{ + ns.updaterServiceFile, + ns.updaterTimerFile, + ns.dropInFile, + ns.needrestartConfFile, + } { + if err := os.Remove(p); err != nil && !errors.Is(err, fs.ErrNotExist) { + return trace.Wrap(err, "failed to remove %s", filepath.Base(p)) + } } if err := svc.Sync(ctx); err != nil { return trace.Wrap(err, "failed to sync systemd config") @@ -222,27 +241,63 @@ func (ns *Namespace) Teardown(ctx context.Context) error { return nil } -func (ns *Namespace) writeConfigFiles() error { +func (ns *Namespace) writeConfigFiles(ctx context.Context) error { var args string if ns.name != "" { args = " --install-suffix=" + ns.name } - err := writeTemplate( - ns.updaterServiceFile, updateServiceTemplate, - struct{ UpdaterCommand string }{ + err := writeTemplate(ns.updaterServiceFile, updateServiceTemplate, + struct { + UpdaterCommand string + }{ ns.updaterBinFile + args + " update", }, ) if err != nil { return trace.Wrap(err) } - err = writeTemplate( - ns.updaterTimerFile, updateTimerTemplate, - struct{ TeleportService string }{filepath.Base(ns.serviceFile)}, + teleportService := filepath.Base(ns.serviceFile) + err = writeTemplate(ns.updaterTimerFile, updateTimerTemplate, + struct { + TeleportService string + }{ + teleportService, + }, ) if err != nil { return trace.Wrap(err) } + err = writeTemplate(ns.dropInFile, teleportDropInTemplate, + struct { + UpdaterConfigFile string + }{ + ns.updaterConfigFile, + }, + ) + if err != nil { + return trace.Wrap(err) + } + // Needrestart config is non-critical for updater functionality. + _, err = os.Stat(filepath.Dir(ns.needrestartConfFile)) + if os.IsNotExist(err) { + return nil // needrestart is not present + } + if err != nil { + ns.log.ErrorContext(ctx, "Unable to disable needrestart.", errorKey, err) + return nil + } + ns.log.InfoContext(ctx, "Disabling needrestart.", unitKey, teleportService) + err = writeTemplate(ns.needrestartConfFile, needrestartConfTemplate, + struct { + TeleportService string + }{ + teleportService, + }, + ) + if err != nil { + ns.log.ErrorContext(ctx, "Unable to disable needrestart.", errorKey, err) + return nil + } return nil } @@ -261,7 +316,11 @@ func writeTemplate(path, t string, values any) error { } defer f.Cleanup() - tmpl, err := template.New(file).Parse(t) + tmpl, err := template.New(file).Funcs(template.FuncMap{ + "replace": func(s, old, new string) string { + return strings.Replace(s, old, new, -1) + }, + }).Parse(t) if err != nil { return trace.Wrap(err) } diff --git a/lib/autoupdate/agent/setup_test.go b/lib/autoupdate/agent/setup_test.go index 8892acb85e06c..97f224c985206 100644 --- a/lib/autoupdate/agent/setup_test.go +++ b/lib/autoupdate/agent/setup_test.go @@ -20,6 +20,7 @@ package agent import ( "bytes" + "context" "log/slog" "os" "path/filepath" @@ -42,17 +43,19 @@ func TestNewNamespace(t *testing.T) { { name: "no namespace", ns: &Namespace{ - dataDir: "/var/lib/teleport", - linkDir: "/usr/local/bin", - versionsDir: "/opt/teleport/default/versions", - serviceFile: "/lib/systemd/system/teleport.service", - configFile: "/etc/teleport.yaml", - pidFile: "/run/teleport.pid", - updaterLockFile: "/opt/teleport/default/update.lock", - updaterConfigFile: "/opt/teleport/default/update.yaml", - updaterBinFile: "/usr/local/bin/teleport-update", - updaterServiceFile: "/etc/systemd/system/teleport-update.service", - updaterTimerFile: "/etc/systemd/system/teleport-update.timer", + dataDir: "/var/lib/teleport", + linkDir: "/usr/local/bin", + versionsDir: "/opt/teleport/default/versions", + serviceFile: "/lib/systemd/system/teleport.service", + configFile: "/etc/teleport.yaml", + pidFile: "/run/teleport.pid", + updaterLockFile: "/opt/teleport/default/update.lock", + updaterConfigFile: "/opt/teleport/default/update.yaml", + updaterBinFile: "/usr/local/bin/teleport-update", + updaterServiceFile: "/etc/systemd/system/teleport-update.service", + updaterTimerFile: "/etc/systemd/system/teleport-update.timer", + dropInFile: "/etc/systemd/system/teleport.service.d/teleport-update.conf", + needrestartConfFile: "/etc/needrestart/conf.d/teleport-update.conf", }, }, { @@ -60,35 +63,39 @@ func TestNewNamespace(t *testing.T) { linkDir: "/link", dataDir: "/data", ns: &Namespace{ - dataDir: "/data", - linkDir: "/link", - versionsDir: "/opt/teleport/default/versions", - serviceFile: "/lib/systemd/system/teleport.service", - configFile: "/etc/teleport.yaml", - pidFile: "/run/teleport.pid", - updaterLockFile: "/opt/teleport/default/update.lock", - updaterConfigFile: "/opt/teleport/default/update.yaml", - updaterBinFile: "/link/teleport-update", - updaterServiceFile: "/etc/systemd/system/teleport-update.service", - updaterTimerFile: "/etc/systemd/system/teleport-update.timer", + dataDir: "/data", + linkDir: "/link", + versionsDir: "/opt/teleport/default/versions", + serviceFile: "/lib/systemd/system/teleport.service", + configFile: "/etc/teleport.yaml", + pidFile: "/run/teleport.pid", + updaterLockFile: "/opt/teleport/default/update.lock", + updaterConfigFile: "/opt/teleport/default/update.yaml", + updaterBinFile: "/link/teleport-update", + updaterServiceFile: "/etc/systemd/system/teleport-update.service", + updaterTimerFile: "/etc/systemd/system/teleport-update.timer", + dropInFile: "/etc/systemd/system/teleport.service.d/teleport-update.conf", + needrestartConfFile: "/etc/needrestart/conf.d/teleport-update.conf", }, }, { name: "test namespace", namespace: "test", ns: &Namespace{ - name: "test", - dataDir: "/var/lib/teleport_test", - linkDir: "/opt/teleport/test/bin", - versionsDir: "/opt/teleport/test/versions", - serviceFile: "/etc/systemd/system/teleport_test.service", - configFile: "/etc/teleport_test.yaml", - pidFile: "/run/teleport_test.pid", - updaterLockFile: "/opt/teleport/test/update.lock", - updaterConfigFile: "/opt/teleport/test/update.yaml", - updaterBinFile: "/opt/teleport/test/bin/teleport-update", - updaterServiceFile: "/etc/systemd/system/teleport-update_test.service", - updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer", + name: "test", + dataDir: "/var/lib/teleport_test", + linkDir: "/opt/teleport/test/bin", + versionsDir: "/opt/teleport/test/versions", + serviceFile: "/etc/systemd/system/teleport_test.service", + configFile: "/etc/teleport_test.yaml", + pidFile: "/run/teleport_test.pid", + updaterLockFile: "/opt/teleport/test/update.lock", + updaterConfigFile: "/opt/teleport/test/update.yaml", + updaterBinFile: "/opt/teleport/test/bin/teleport-update", + updaterServiceFile: "/etc/systemd/system/teleport-update_test.service", + updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer", + dropInFile: "/etc/systemd/system/teleport.service.d/teleport-update_test.conf", + needrestartConfFile: "/etc/needrestart/conf.d/teleport-update_test.conf", }, }, { @@ -97,18 +104,20 @@ func TestNewNamespace(t *testing.T) { linkDir: "/link", dataDir: "/data", ns: &Namespace{ - name: "test", - dataDir: "/data", - linkDir: "/link", - versionsDir: "/opt/teleport/test/versions", - serviceFile: "/etc/systemd/system/teleport_test.service", - configFile: "/etc/teleport_test.yaml", - pidFile: "/run/teleport_test.pid", - updaterLockFile: "/opt/teleport/test/update.lock", - updaterConfigFile: "/opt/teleport/test/update.yaml", - updaterBinFile: "/link/teleport-update", - updaterServiceFile: "/etc/systemd/system/teleport-update_test.service", - updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer", + name: "test", + dataDir: "/data", + linkDir: "/link", + versionsDir: "/opt/teleport/test/versions", + serviceFile: "/etc/systemd/system/teleport_test.service", + configFile: "/etc/teleport_test.yaml", + pidFile: "/run/teleport_test.pid", + updaterLockFile: "/opt/teleport/test/update.lock", + updaterConfigFile: "/opt/teleport/test/update.yaml", + updaterBinFile: "/link/teleport-update", + updaterServiceFile: "/etc/systemd/system/teleport-update_test.service", + updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer", + dropInFile: "/etc/systemd/system/teleport.service.d/teleport-update_test.conf", + needrestartConfFile: "/etc/needrestart/conf.d/teleport-update_test.conf", }, }, { @@ -157,28 +166,33 @@ func TestWriteConfigFiles(t *testing.T) { require.NoError(t, err) ns.updaterServiceFile = filepath.Join(linkDir, serviceDir, filepath.Base(ns.updaterServiceFile)) ns.updaterTimerFile = filepath.Join(linkDir, serviceDir, filepath.Base(ns.updaterTimerFile)) - err = ns.writeConfigFiles() + ns.dropInFile = filepath.Join(linkDir, serviceDir, filepath.Base(filepath.Dir(ns.dropInFile)), filepath.Base(ns.dropInFile)) + ns.needrestartConfFile = filepath.Join(linkDir, filepath.Base(ns.dropInFile)) + ctx := context.Background() + err = ns.writeConfigFiles(ctx) require.NoError(t, err) - data, err := os.ReadFile(ns.updaterServiceFile) - require.NoError(t, err) - data = replaceValues(data, map[string]string{ - DefaultLinkDir: linkDir, - }) - if golden.ShouldSet() { - golden.SetNamed(t, "service", data) - } - require.Equal(t, string(golden.GetNamed(t, "service")), string(data)) - - data, err = os.ReadFile(ns.updaterTimerFile) - require.NoError(t, err) - data = replaceValues(data, map[string]string{ - DefaultLinkDir: linkDir, - }) - if golden.ShouldSet() { - golden.SetNamed(t, "timer", data) + for _, tt := range []struct { + name string + path string + }{ + {name: "service", path: ns.updaterServiceFile}, + {name: "timer", path: ns.updaterTimerFile}, + {name: "dropin", path: ns.dropInFile}, + {name: "needrestart", path: ns.needrestartConfFile}, + } { + t.Run(tt.name, func(t *testing.T) { + data, err := os.ReadFile(tt.path) + require.NoError(t, err) + data = replaceValues(data, map[string]string{ + DefaultLinkDir: linkDir, + }) + if golden.ShouldSet() { + golden.Set(t, data) + } + require.Equal(t, string(golden.Get(t)), string(data)) + }) } - require.Equal(t, string(golden.GetNamed(t, "timer")), string(data)) }) } } diff --git a/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/dropin.golden b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/dropin.golden new file mode 100644 index 0000000000000..105c0060f1eb7 --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/dropin.golden @@ -0,0 +1,4 @@ +# teleport-update +# DO NOT EDIT THIS FILE +[Service] +Environment=TELEPORT_UPDATE_CONFIG_FILE=/opt/teleport/default/update.yaml diff --git a/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/needrestart.golden b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/needrestart.golden new file mode 100644 index 0000000000000..b5d6a74435cb2 --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/no_namespace/needrestart.golden @@ -0,0 +1 @@ +$nrconf{override_rc}{qr(^teleport\.service)} = 0; diff --git a/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/dropin.golden b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/dropin.golden new file mode 100644 index 0000000000000..a14fd0e5f028d --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/dropin.golden @@ -0,0 +1,4 @@ +# teleport-update +# DO NOT EDIT THIS FILE +[Service] +Environment=TELEPORT_UPDATE_CONFIG_FILE=/opt/teleport/test/update.yaml diff --git a/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/needrestart.golden b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/needrestart.golden new file mode 100644 index 0000000000000..ad6bd606a74cb --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestWriteConfigFiles/test_namespace/needrestart.golden @@ -0,0 +1 @@ +$nrconf{override_rc}{qr(^teleport_test\.service)} = 0; From 4cdfb5434e460031da1b24096738de1ed7f9b10a Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Tue, 10 Dec 2024 12:25:30 -0500 Subject: [PATCH 3/4] nit --- lib/autoupdate/agent/setup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/autoupdate/agent/setup.go b/lib/autoupdate/agent/setup.go index 9201e5406950e..9ef86cf40beb9 100644 --- a/lib/autoupdate/agent/setup.go +++ b/lib/autoupdate/agent/setup.go @@ -318,7 +318,7 @@ func writeTemplate(path, t string, values any) error { tmpl, err := template.New(file).Funcs(template.FuncMap{ "replace": func(s, old, new string) string { - return strings.Replace(s, old, new, -1) + return strings.ReplaceAll(s, old, new) }, }).Parse(t) if err != nil { From 3bd5e0a4b7c4231db731ffebcfc3ae8d3eacd419 Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Tue, 10 Dec 2024 16:53:08 -0500 Subject: [PATCH 4/4] feedback --- lib/autoupdate/agent/setup.go | 52 +++++++++++++++-------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/lib/autoupdate/agent/setup.go b/lib/autoupdate/agent/setup.go index 9ef86cf40beb9..c2575e0cc1e5f 100644 --- a/lib/autoupdate/agent/setup.go +++ b/lib/autoupdate/agent/setup.go @@ -76,11 +76,22 @@ WantedBy={{.TeleportService}} [Service] Environment=TELEPORT_UPDATE_CONFIG_FILE={{.UpdaterConfigFile}} ` - + // This configuration sets the default value for needrestart-trigger automatic restarts for teleport.service to disabled. + // Users may still choose to enable needrestart for teleport.service when installing packaging interactively (or via dpkg config), + // but doing so will result in a hard restart that disconnects the agent whenever any dependent libraries are updated. + // Other network services, like openvpn, follow this pattern. + // It is possible to configure needrestart to trigger a soft restart (via restart.d script), but given that Teleport subprocesses + // can use a wide variety of installed binaries (when executed by the user), this could trigger many unexpected reloads. needrestartConfTemplate = `$nrconf{override_rc}{qr(^{{replace .TeleportService "." "\\."}})} = 0; ` ) +type confParams struct { + TeleportService string + UpdaterCommand string + UpdaterConfigFile string +} + // Namespace represents a namespace within various system paths for a isolated installation of Teleport. type Namespace struct { log *slog.Logger @@ -246,34 +257,21 @@ func (ns *Namespace) writeConfigFiles(ctx context.Context) error { if ns.name != "" { args = " --install-suffix=" + ns.name } - err := writeTemplate(ns.updaterServiceFile, updateServiceTemplate, - struct { - UpdaterCommand string - }{ - ns.updaterBinFile + args + " update", - }, - ) + teleportService := filepath.Base(ns.serviceFile) + params := confParams{ + TeleportService: teleportService, + UpdaterCommand: ns.updaterBinFile + args + " update", + UpdaterConfigFile: ns.updaterConfigFile, + } + err := writeTemplate(ns.updaterServiceFile, updateServiceTemplate, params) if err != nil { return trace.Wrap(err) } - teleportService := filepath.Base(ns.serviceFile) - err = writeTemplate(ns.updaterTimerFile, updateTimerTemplate, - struct { - TeleportService string - }{ - teleportService, - }, - ) + err = writeTemplate(ns.updaterTimerFile, updateTimerTemplate, params) if err != nil { return trace.Wrap(err) } - err = writeTemplate(ns.dropInFile, teleportDropInTemplate, - struct { - UpdaterConfigFile string - }{ - ns.updaterConfigFile, - }, - ) + err = writeTemplate(ns.dropInFile, teleportDropInTemplate, params) if err != nil { return trace.Wrap(err) } @@ -287,13 +285,7 @@ func (ns *Namespace) writeConfigFiles(ctx context.Context) error { return nil } ns.log.InfoContext(ctx, "Disabling needrestart.", unitKey, teleportService) - err = writeTemplate(ns.needrestartConfFile, needrestartConfTemplate, - struct { - TeleportService string - }{ - teleportService, - }, - ) + err = writeTemplate(ns.needrestartConfFile, needrestartConfTemplate, params) if err != nil { ns.log.ErrorContext(ctx, "Unable to disable needrestart.", errorKey, err) return nil