Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 53 additions & 30 deletions lib/autoupdate/agent/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const (
const (
// deprecatedTimerName is the timer for the deprecated upgrader should be disabled on setup.
deprecatedTimerName = "teleport-upgrade.timer"
// deprecatedServiceName is the service for the deprecated upgrader should be disabled on setup.
deprecatedServiceName = "teleport-upgrade.service"
)

const (
Expand Down Expand Up @@ -85,6 +87,13 @@ WantedBy={{.TeleportService}}
[Service]
Environment="TELEPORT_UPDATE_CONFIG_FILE={{escape .UpdaterConfigFile}}"
Environment="TELEPORT_UPDATE_INSTALL_DIR={{escape .InstallDir}}"
`

deprecatedDropInTemplate = `# teleport-update
# DO NOT EDIT THIS FILE
[Service]
ExecStart=
ExecStart=-/bin/echo "The teleport-upgrade script has been disabled by teleport-update. Please remove the teleport-ent-updater package."
`
// 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),
Expand Down Expand Up @@ -130,8 +139,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
// teleportDropInFile is the Teleport systemd drop-in path extending Teleport
teleportDropInFile string
// deprecatedDropInFile is the deprecated upgrader's systemd drop-in path
deprecatedDropInFile string
// needrestartConfFile is the path to needrestart configuration for Teleport
needrestartConfFile string
}
Expand All @@ -157,19 +168,20 @@ func NewNamespace(ctx context.Context, log *slog.Logger, name, installDir string
if name == "" {
linkDir := defaultPathDir
return &Namespace{
log: log,
name: name,
installDir: installDir,
defaultPathDir: linkDir,
dataDir: defaults.DataDir,
serviceFile: filepath.Join("/", serviceDir, serviceName),
configFile: defaults.ConfigFilePath,
pidFile: filepath.Join(systemdPIDDir, "teleport.pid"),
updaterIDFile: filepath.Join(os.TempDir(), BinaryName+".id"),
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"),
log: log,
name: name,
installDir: installDir,
defaultPathDir: linkDir,
dataDir: defaults.DataDir,
serviceFile: filepath.Join("/", serviceDir, serviceName),
configFile: defaults.ConfigFilePath,
pidFile: filepath.Join(systemdPIDDir, "teleport.pid"),
updaterIDFile: filepath.Join(os.TempDir(), BinaryName+".id"),
updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+".service"),
updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+".timer"),
teleportDropInFile: filepath.Join(systemdAdminDir, "teleport.service.d", BinaryName+".conf"),
deprecatedDropInFile: filepath.Join(systemdAdminDir, deprecatedServiceName+".d", BinaryName+".conf"),
needrestartConfFile: filepath.Join(needrestartConfDir, BinaryName+".conf"),
}, nil
}

Expand All @@ -187,8 +199,9 @@ func NewNamespace(ctx context.Context, log *slog.Logger, name, installDir string
updaterIDFile: filepath.Join(os.TempDir(), BinaryName+"_"+name+".id"),
updaterServiceFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".service"),
updaterTimerFile: filepath.Join(systemdAdminDir, BinaryName+"_"+name+".timer"),
dropInFile: filepath.Join(systemdAdminDir, prefix+".service.d", BinaryName+"_"+name+".conf"),
teleportDropInFile: filepath.Join(systemdAdminDir, prefix+".service.d", BinaryName+"_"+name+".conf"),
needrestartConfFile: filepath.Join(needrestartConfDir, BinaryName+"_"+name+".conf"),
// no deprecatedDropInFile, as teleport-upgrade does not conflict with namespaced installs
}, nil
}

Expand Down Expand Up @@ -250,11 +263,12 @@ func (ns *Namespace) Setup(ctx context.Context, path string) error {
}
if present {
if err := oldTimer.Disable(ctx, true); err != nil {
ns.log.ErrorContext(ctx, "The deprecated teleport-ent-updater package is installed on this server, and it cannot be disabled due to an error.", errorKey, err)
ns.log.ErrorContext(ctx, "The deprecated teleport-ent-updater package is installed on this server and cannot be disabled due to an error.", errorKey, err)
ns.log.ErrorContext(ctx, "You must remove the teleport-ent-updater package after verifying that teleport-update is working.", errorKey, err)
} else {
ns.log.WarnContext(ctx, "The deprecated teleport-ent-updater package is installed on this server.")
ns.log.WarnContext(ctx, "The systemd timer included in this package has been disabled to prevent conflicts.", "timer", deprecatedTimerName)
ns.log.WarnContext(ctx, "The systemd service included in this package will no longer perform updates.", "service", deprecatedServiceName)
ns.log.WarnContext(ctx, "Please remove the teleport-ent-updater package after verifying that teleport-update is working.")
}
}
Expand Down Expand Up @@ -283,9 +297,13 @@ func (ns *Namespace) Teardown(ctx context.Context) error {
for _, p := range []string{
ns.updaterServiceFile,
ns.updaterTimerFile,
ns.dropInFile,
ns.teleportDropInFile,
ns.deprecatedDropInFile,
ns.needrestartConfFile,
} {
if p == "" {
continue
}
if err := os.Remove(p); err != nil && !errors.Is(err, fs.ErrNotExist) {
return trace.Wrap(err, "failed to remove %s", filepath.Base(p))
}
Expand Down Expand Up @@ -336,20 +354,25 @@ func (ns *Namespace) writeConfigFiles(ctx context.Context, path string) error {
Path: path,
UpdaterConfigFile: filepath.Join(ns.Dir(), updateConfigName),
}
err := writeSystemTemplate(ns.updaterServiceFile, updateServiceTemplate, params)
if err != nil {
return trace.Wrap(err)
}
err = writeSystemTemplate(ns.updaterTimerFile, updateTimerTemplate, params)
if err != nil {
return trace.Wrap(err)
}
err = writeSystemTemplate(ns.dropInFile, teleportDropInTemplate, params)
if err != nil {
return trace.Wrap(err)

for _, v := range []struct {
path, tmpl string
}{
{ns.updaterServiceFile, updateServiceTemplate},
{ns.updaterTimerFile, updateTimerTemplate},
{ns.teleportDropInFile, teleportDropInTemplate},
{ns.deprecatedDropInFile, deprecatedDropInTemplate},
} {
if v.path == "" {
continue
}
err := writeSystemTemplate(v.path, v.tmpl, params)
if err != nil {
return trace.Wrap(err)
}
}
// Needrestart config is non-critical for updater functionality.
_, err = os.Stat(filepath.Dir(ns.needrestartConfFile))
_, err := os.Stat(filepath.Dir(ns.needrestartConfFile))
if os.IsNotExist(err) {
return nil // needrestart is not present
}
Expand Down
73 changes: 44 additions & 29 deletions lib/autoupdate/agent/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,36 @@ func TestNewNamespace(t *testing.T) {
{
name: "no namespace",
ns: &Namespace{
dataDir: "/var/lib/teleport",
installDir: "/opt/teleport",
defaultPathDir: "/usr/local/bin",
serviceFile: "/lib/systemd/system/teleport.service",
configFile: "/etc/teleport.yaml",
pidFile: "/run/teleport.pid",
updaterIDFile: "/TMP/teleport-update.id",
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",
dataDir: "/var/lib/teleport",
installDir: "/opt/teleport",
defaultPathDir: "/usr/local/bin",
serviceFile: "/lib/systemd/system/teleport.service",
configFile: "/etc/teleport.yaml",
pidFile: "/run/teleport.pid",
updaterIDFile: "/TMP/teleport-update.id",
updaterServiceFile: "/etc/systemd/system/teleport-update.service",
updaterTimerFile: "/etc/systemd/system/teleport-update.timer",
teleportDropInFile: "/etc/systemd/system/teleport.service.d/teleport-update.conf",
deprecatedDropInFile: "/etc/systemd/system/teleport-upgrade.service.d/teleport-update.conf",
needrestartConfFile: "/etc/needrestart/conf.d/teleport-update.conf",
},
},
{
name: "no namespace with dirs",
installDir: "/install",
ns: &Namespace{
dataDir: "/var/lib/teleport",
installDir: "/install",
defaultPathDir: "/usr/local/bin",
serviceFile: "/lib/systemd/system/teleport.service",
configFile: "/etc/teleport.yaml",
pidFile: "/run/teleport.pid",
updaterIDFile: "/TMP/teleport-update.id",
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",
dataDir: "/var/lib/teleport",
installDir: "/install",
defaultPathDir: "/usr/local/bin",
serviceFile: "/lib/systemd/system/teleport.service",
configFile: "/etc/teleport.yaml",
pidFile: "/run/teleport.pid",
updaterIDFile: "/TMP/teleport-update.id",
updaterServiceFile: "/etc/systemd/system/teleport-update.service",
updaterTimerFile: "/etc/systemd/system/teleport-update.timer",
teleportDropInFile: "/etc/systemd/system/teleport.service.d/teleport-update.conf",
deprecatedDropInFile: "/etc/systemd/system/teleport-upgrade.service.d/teleport-update.conf",
needrestartConfFile: "/etc/needrestart/conf.d/teleport-update.conf",
},
},
{
Expand All @@ -89,7 +91,7 @@ func TestNewNamespace(t *testing.T) {
updaterIDFile: "/TMP/teleport-update_test.id",
updaterServiceFile: "/etc/systemd/system/teleport-update_test.service",
updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer",
dropInFile: "/etc/systemd/system/teleport_test.service.d/teleport-update_test.conf",
teleportDropInFile: "/etc/systemd/system/teleport_test.service.d/teleport-update_test.conf",
needrestartConfFile: "/etc/needrestart/conf.d/teleport-update_test.conf",
},
},
Expand All @@ -108,7 +110,7 @@ func TestNewNamespace(t *testing.T) {
updaterIDFile: "/TMP/teleport-update_test.id",
updaterServiceFile: "/etc/systemd/system/teleport-update_test.service",
updaterTimerFile: "/etc/systemd/system/teleport-update_test.timer",
dropInFile: "/etc/systemd/system/teleport_test.service.d/teleport-update_test.conf",
teleportDropInFile: "/etc/systemd/system/teleport_test.service.d/teleport-update_test.conf",
needrestartConfFile: "/etc/needrestart/conf.d/teleport-update_test.conf",
},
},
Expand Down Expand Up @@ -161,10 +163,12 @@ func TestWriteConfigFiles(t *testing.T) {
ctx := context.Background()
ns, err := NewNamespace(ctx, log, p.namespace, "")
require.NoError(t, err)
ns.updaterServiceFile = filepath.Join(linkDir, serviceDir, filepath.Base(ns.updaterServiceFile))
ns.updaterTimerFile = filepath.Join(linkDir, serviceDir, filepath.Base(ns.updaterTimerFile))
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))
ns.updaterServiceFile = rebasePath(filepath.Join(linkDir, serviceDir), filepath.Base(ns.updaterServiceFile))
ns.updaterServiceFile = rebasePath(filepath.Join(linkDir, serviceDir), ns.updaterServiceFile)
ns.updaterTimerFile = rebasePath(filepath.Join(linkDir, serviceDir), ns.updaterTimerFile)
ns.teleportDropInFile = rebasePath(filepath.Join(linkDir, serviceDir, filepath.Base(filepath.Dir(ns.teleportDropInFile))), ns.teleportDropInFile)
ns.deprecatedDropInFile = rebasePath(filepath.Join(linkDir, serviceDir, filepath.Base(filepath.Dir(ns.deprecatedDropInFile))), ns.deprecatedDropInFile)
ns.needrestartConfFile = rebasePath(linkDir, filepath.Base(ns.needrestartConfFile))
err = ns.writeConfigFiles(ctx, linkDir)
require.NoError(t, err)

Expand All @@ -174,9 +178,13 @@ func TestWriteConfigFiles(t *testing.T) {
}{
{name: "service", path: ns.updaterServiceFile},
{name: "timer", path: ns.updaterTimerFile},
{name: "dropin", path: ns.dropInFile},
{name: "dropin", path: ns.teleportDropInFile},
{name: "deprecated", path: ns.deprecatedDropInFile},
{name: "needrestart", path: ns.needrestartConfFile},
} {
if tt.path == "" {
continue
}
t.Run(tt.name, func(t *testing.T) {
data, err := os.ReadFile(tt.path)
require.NoError(t, err)
Expand All @@ -193,6 +201,13 @@ func TestWriteConfigFiles(t *testing.T) {
}
}

func rebasePath(newBase, oldPath string) string {
if oldPath == "" {
return ""
}
return filepath.Join(newBase, filepath.Base(oldPath))
}

func replaceValues(data []byte, m map[string]string) []byte {
for k, v := range m {
data = bytes.ReplaceAll(data, []byte(v), []byte(k))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# teleport-update
# DO NOT EDIT THIS FILE
[Service]
ExecStart=
ExecStart=-/bin/echo "The teleport-upgrade script has been disabled by teleport-update. Please remove the teleport-ent-updater package."
18 changes: 1 addition & 17 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1164,23 +1164,7 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) {

switch upgraderKind {
case types.UpgraderKindTeleportUpdate:
isDefault, err := autoupdate.IsManagedAndDefault()
if err != nil {
return nil, trace.Wrap(err)
}
if !isDefault {
// Only write the nop schedule for the default updater.
// Suffixed installations of Teleport can coexist with the old upgrader system.
break
}
driver, err := uw.NewSystemdUnitDriver(uw.SystemdUnitDriverConfig{})
if err != nil {
return nil, trace.Wrap(err)
}
if err := driver.ForceNop(process.ExitContext()); err != nil {
process.logger.WarnContext(process.ExitContext(), "Unable to disable the teleport-upgrade command provided by the deprecated teleport-ent-updater package.", "error", err)
process.logger.WarnContext(process.ExitContext(), "If the deprecated teleport-ent-updater package is installed, please ensure /etc/teleport-upgrade.d/schedule contains 'nop'.")
}
// Exports are not required for teleport-update
case types.UpgraderKindSystemdUnit:
process.RegisterFunc("autoupdates.endpoint.export", func() error {
conn, err := waitForInstanceConnector(process, process.logger)
Expand Down
17 changes: 0 additions & 17 deletions lib/versioncontrol/upgradewindow/upgradewindow.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ const (

// unitScheduleFile is the name of the file to which the unit schedule is exported.
unitScheduleFile = "schedule"

// scheduleNop is the name of the no-op schedule.
scheduleNop = "nop"
)

// ExportFunc represents the ExportUpgradeWindows rpc exposed by auth servers.
Expand Down Expand Up @@ -317,12 +314,6 @@ type Driver interface {
// called if teleport experiences prolonged loss of auth connectivity, which may be an indicator
// that the control plane has been upgraded s.t. this agent is no longer compatible.
Reset(ctx context.Context) error

// ForceNop sets the NOP schedule, ensuring that updates do not happen.
// This schedule was originally only used for testing, but now it is also used by the
// teleport-update binary to protect against package updates that could interfere with
// the new update system.
ForceNop(ctx context.Context) error
}

// NewDriver sets up a new export driver corresponding to the specified upgrader kind.
Expand Down Expand Up @@ -374,10 +365,6 @@ func (e *kubeDriver) Sync(ctx context.Context, rsp proto.ExportUpgradeWindowsRes
return trace.Wrap(e.setSchedule(ctx, rsp.KubeControllerSchedule))
}

func (e *kubeDriver) ForceNop(ctx context.Context) error {
return trace.Wrap(e.setSchedule(ctx, scheduleNop))
}

func (e *kubeDriver) setSchedule(ctx context.Context, schedule string) error {
if schedule == "" {
return e.Reset(ctx)
Expand Down Expand Up @@ -428,10 +415,6 @@ func (e *systemdDriver) Sync(ctx context.Context, rsp proto.ExportUpgradeWindows
return trace.Wrap(e.setSchedule(ctx, rsp.SystemdUnitSchedule))
}

func (e *systemdDriver) ForceNop(ctx context.Context) error {
return trace.Wrap(e.setSchedule(ctx, scheduleNop))
}

func (e *systemdDriver) setSchedule(ctx context.Context, schedule string) error {
if len(schedule) == 0 {
// treat an empty schedule value as equivalent to a reset
Expand Down
Loading
Loading