Skip to content

Commit

Permalink
service and timer
Browse files Browse the repository at this point in the history
  • Loading branch information
sclevine committed Nov 20, 2024
1 parent 31df14d commit 82eecab
Show file tree
Hide file tree
Showing 10 changed files with 482 additions and 184 deletions.
116 changes: 116 additions & 0 deletions lib/autoupdate/agent/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package agent

import (
"context"
"log/slog"
"os"
"path/filepath"
"text/template"

"github.com/google/renameio/v2"
"github.com/gravitational/trace"
)

const (
updateServiceTemplate = `# teleport-update
[Unit]
Description=Teleport auto-update service
[Service]
Type=oneshot
ExecStart={{.LinkDir}}/bin/teleport-update update
`
updateTimerTemplate = `# teleport-update
[Unit]
Description=Teleport auto-update timer unit
[Timer]
OnActiveSec=1m
OnUnitActiveSec=5m
RandomizedDelaySec=1m
[Install]
WantedBy=teleport.service
`
)

func Setup(ctx context.Context, log *slog.Logger, linkDir, dataDir string) error {
err := writeConfigFiles(linkDir, dataDir)
if err != nil {
return trace.Errorf("failed to write teleport-update systemd config files: %w", err)
}
svc := &SystemdService{
ServiceName: "teleport-update.timer",
Log: log,
}
if err := svc.Sync(ctx); err != nil {
return trace.Errorf("failed to sync systemd config: %w", err)
}
if err := svc.Enable(ctx, true); err != nil {
return trace.Errorf("failed to enable teleport-update systemd timer: %w", err)
}
return nil
}

func writeConfigFiles(linkDir, dataDir string) error {
// TODO(sclevine): revert on failure

servicePath := filepath.Join(linkDir, serviceDir, updateServiceName)
err := writeTemplate(servicePath, updateServiceTemplate, linkDir, dataDir)
if err != nil {
return trace.Wrap(err)
}
timerPath := filepath.Join(linkDir, serviceDir, updateTimerName)
err = writeTemplate(timerPath, updateTimerTemplate, linkDir, dataDir)
if err != nil {
return trace.Wrap(err)
}

return nil
}

func writeTemplate(path, t, linkDir, dataDir string) error {
if err := os.MkdirAll(filepath.Dir(path), systemDirMode); err != nil {
return trace.Wrap(err)
}
opts := []renameio.Option{
renameio.WithPermissions(configFileMode),
renameio.WithExistingPermissions(),
}
f, err := renameio.NewPendingFile(path, opts...)
if err != nil {
return trace.Wrap(err)
}
defer f.Cleanup()

tmpl, err := template.New(filepath.Base(path)).Parse(t)
if err != nil {
return trace.Wrap(err)
}
err = tmpl.Execute(f, struct {
LinkDir string
DataDir string
}{linkDir, dataDir})
if err != nil {
return trace.Wrap(err)
}
return trace.Wrap(f.CloseAtomicallyReplace())
}
65 changes: 65 additions & 0 deletions lib/autoupdate/agent/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package agent

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

libdefaults "github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/utils/golden"
)

func TestWriteConfigFiles(t *testing.T) {
t.Parallel()
linkDir := t.TempDir()
dataDir := t.TempDir()
err := writeConfigFiles(linkDir, dataDir)
require.NoError(t, err)

for _, p := range []string{
filepath.Join(linkDir, serviceDir, updateServiceName),
filepath.Join(linkDir, serviceDir, updateTimerName),
} {
t.Run(filepath.Base(p), func(t *testing.T) {
data, err := os.ReadFile(p)
require.NoError(t, err)
data = replaceValues(data, map[string]string{
DefaultLinkDir: linkDir,
libdefaults.DataDir: dataDir,
})
if golden.ShouldSet() {
golden.Set(t, data)
}
require.Equal(t, string(golden.Get(t)), string(data))
})
}
}

func replaceValues(data []byte, m map[string]string) []byte {
for k, v := range m {
data = bytes.ReplaceAll(data, []byte(v),
[]byte(k))
}
return data
}
22 changes: 9 additions & 13 deletions lib/autoupdate/agent/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ const (
systemDirMode = 0755
)

var (
const (
// serviceDir contains the relative path to the Teleport SystemD service dir.
serviceDir = filepath.Join("lib", "systemd", "system")
serviceDir = "lib/systemd/system"
// serviceName contains the name of the Teleport SystemD service file.
serviceName = "teleport.service"
// updateServiceName contains the name of the Teleport Update Systemd service
updateServiceName = "teleport-update.service"
// updateTimerName contains the name of the Teleport Update Systemd timer
updateTimerName = "teleport-update.timer"
)

// LocalInstaller manages the creation and removal of installations
Expand Down Expand Up @@ -431,7 +435,7 @@ func (li *LocalInstaller) Link(ctx context.Context, version string) (revert func
return revert, nil
}

// LinkSystem links the system (package) version into the system LinkBinDir and LinkServiceDir.
// LinkSystem links the system (package) version into LinkBinDir and LinkServiceDir.
// The revert function restores the previous linking.
// See Installer interface for additional specs.
func (li *LocalInstaller) LinkSystem(ctx context.Context) (revert func(context.Context) bool, err error) {
Expand Down Expand Up @@ -539,7 +543,7 @@ func (li *LocalInstaller) forceLinks(ctx context.Context, binDir, svcDir string)
dst := filepath.Join(li.LinkServiceDir, serviceName)
orig, err := forceCopy(dst, src, maxServiceFileSize)
if err != nil && !errors.Is(err, os.ErrExist) {
return revert, trace.Errorf("failed to create file for %s: %w", serviceName, err)
return revert, trace.Errorf("failed to write file %s: %w", serviceName, err)
}
if orig != nil {
revertFiles = append(revertFiles, *orig)
Expand Down Expand Up @@ -782,13 +786,5 @@ func (li *LocalInstaller) isLinked(versionDir string) (bool, error) {
return true, nil
}
}
linkData, err := readFileN(filepath.Join(li.LinkServiceDir, serviceName), maxServiceFileSize)
if err != nil {
return false, nil
}
versionData, err := readFileN(filepath.Join(versionDir, serviceDir, serviceName), maxServiceFileSize)
if err != nil {
return false, nil
}
return bytes.Equal(linkData, versionData), nil
return false, nil
}
18 changes: 18 additions & 0 deletions lib/autoupdate/agent/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,24 @@ func (s SystemdService) Sync(ctx context.Context) error {
if code != 0 {
return trace.Errorf("unable to reload systemd configuration")
}
s.Log.InfoContext(ctx, "Systemd configuration synced.", unitKey, s.ServiceName)
return nil
}

// Enable the systemd service.
func (s SystemdService) Enable(ctx context.Context, now bool) error {
if err := s.checkSystem(ctx); err != nil {
return trace.Wrap(err)
}
args := []string{"enable", s.ServiceName}
if now {
args = append(args, "--now")
}
code := s.systemctl(ctx, slog.LevelError, args...)
if code != 0 {
return trace.Errorf("unable to enable systemd service")
}
s.Log.InfoContext(ctx, "Service enabled.", unitKey, s.ServiceName)
return nil
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# teleport-update
[Unit]
Description=Teleport auto-update service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/teleport-update update
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# teleport-update
[Unit]
Description=Teleport auto-update timer unit

[Timer]
OnActiveSec=1m
OnUnitActiveSec=5m
RandomizedDelaySec=1m

[Install]
WantedBy=teleport.service
Loading

0 comments on commit 82eecab

Please sign in to comment.