TUN-3459: Make service install on linux use named tunnels
This commit is contained in:
parent
f0cfad8efa
commit
b6cd54d854
|
@ -326,6 +326,9 @@ func GetConfiguration() *Configuration {
|
||||||
func ReadConfigFile(c *cli.Context, log logger.Service) (*configFileSettings, error) {
|
func ReadConfigFile(c *cli.Context, log logger.Service) (*configFileSettings, error) {
|
||||||
configFile := c.String("config")
|
configFile := c.String("config")
|
||||||
if configuration.Source() == configFile || configFile == "" {
|
if configuration.Source() == configFile || configFile == "" {
|
||||||
|
if configuration.Source() == "" {
|
||||||
|
return nil, ErrNoConfigFile
|
||||||
|
}
|
||||||
return &configuration, nil
|
return &configuration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||||
"github.com/cloudflare/cloudflared/logger"
|
"github.com/cloudflare/cloudflared/logger"
|
||||||
"github.com/pkg/errors"
|
|
||||||
cli "github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
|
func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
|
||||||
|
@ -23,6 +24,12 @@ func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
|
||||||
Name: "install",
|
Name: "install",
|
||||||
Usage: "Install Argo Tunnel as a system service",
|
Usage: "Install Argo Tunnel as a system service",
|
||||||
Action: cliutil.ErrorHandler(installLinuxService),
|
Action: cliutil.ErrorHandler(installLinuxService),
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "legacy",
|
||||||
|
Usage: "Generate service file for non-named tunnels",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.Command{
|
&cli.Command{
|
||||||
Name: "uninstall",
|
Name: "uninstall",
|
||||||
|
@ -40,6 +47,7 @@ const (
|
||||||
serviceConfigDir = "/etc/cloudflared"
|
serviceConfigDir = "/etc/cloudflared"
|
||||||
serviceConfigFile = "config.yml"
|
serviceConfigFile = "config.yml"
|
||||||
serviceCredentialFile = "cert.pem"
|
serviceCredentialFile = "cert.pem"
|
||||||
|
serviceConfigPath = serviceConfigDir + "/" + serviceConfigFile
|
||||||
)
|
)
|
||||||
|
|
||||||
var systemdTemplates = []ServiceTemplate{
|
var systemdTemplates = []ServiceTemplate{
|
||||||
|
@ -52,7 +60,7 @@ After=network.target
|
||||||
[Service]
|
[Service]
|
||||||
TimeoutStartSec=0
|
TimeoutStartSec=0
|
||||||
Type=notify
|
Type=notify
|
||||||
ExecStart={{ .Path }} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --no-autoupdate
|
ExecStart={{ .Path }} --config /etc/cloudflared/config.yml --no-autoupdate{{ range .ExtraArgs }} {{ . }}{{ end }}
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5s
|
RestartSec=5s
|
||||||
|
|
||||||
|
@ -102,7 +110,7 @@ var sysvTemplate = ServiceTemplate{
|
||||||
# Description: Argo Tunnel agent
|
# Description: Argo Tunnel agent
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
name=$(basename $(readlink -f $0))
|
name=$(basename $(readlink -f $0))
|
||||||
cmd="{{.Path}} --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s"
|
cmd="{{.Path}} --config /etc/cloudflared/config.yml --pidfile /var/run/$name.pid --autoupdate-freq 24h0m0s{{ range .ExtraArgs }} {{ . }}{{ end }}"
|
||||||
pid_file="/var/run/$name.pid"
|
pid_file="/var/run/$name.pid"
|
||||||
stdout_log="/var/log/$name.log"
|
stdout_log="/var/log/$name.log"
|
||||||
stderr_log="/var/log/$name.err"
|
stderr_log="/var/log/$name.err"
|
||||||
|
@ -182,10 +190,6 @@ func isSystemd() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile string, logger logger.Service) error {
|
func copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile string, logger logger.Service) error {
|
||||||
if err := ensureConfigDirExists(serviceConfigDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
srcCredentialPath := filepath.Join(userConfigDir, userCredentialFile)
|
srcCredentialPath := filepath.Join(userConfigDir, userCredentialFile)
|
||||||
destCredentialPath := filepath.Join(serviceConfigDir, serviceCredentialFile)
|
destCredentialPath := filepath.Join(serviceConfigDir, serviceCredentialFile)
|
||||||
if srcCredentialPath != destCredentialPath {
|
if srcCredentialPath != destCredentialPath {
|
||||||
|
@ -216,23 +220,63 @@ func installLinuxService(c *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error determining executable path: %v", err)
|
return fmt.Errorf("error determining executable path: %v", err)
|
||||||
}
|
}
|
||||||
templateArgs := ServiceTemplateArgs{Path: etPath}
|
templateArgs := ServiceTemplateArgs{
|
||||||
|
Path: etPath,
|
||||||
|
}
|
||||||
|
|
||||||
userConfigDir := filepath.Dir(c.String("config"))
|
if err := ensureConfigDirExists(serviceConfigDir); err != nil {
|
||||||
userConfigFile := filepath.Base(c.String("config"))
|
|
||||||
userCredentialFile := config.DefaultCredentialFile
|
|
||||||
if err = copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile, logger); err != nil {
|
|
||||||
logger.Errorf("Failed to copy user configuration: %s. Before running the service, ensure that %s contains two files, %s and %s", err,
|
|
||||||
serviceConfigDir, serviceCredentialFile, serviceConfigFile)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if c.Bool("legacy") {
|
||||||
|
userConfigDir := filepath.Dir(c.String("config"))
|
||||||
|
userConfigFile := filepath.Base(c.String("config"))
|
||||||
|
userCredentialFile := config.DefaultCredentialFile
|
||||||
|
if err = copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile, logger); err != nil {
|
||||||
|
logger.Errorf("Failed to copy user configuration: %s. Before running the service, ensure that %s contains two files, %s and %s", err,
|
||||||
|
serviceConfigDir, serviceCredentialFile, serviceConfigFile)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templateArgs.ExtraArgs = []string{
|
||||||
|
"--origincert", serviceConfigDir + "/" + serviceCredentialFile,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
src, err := config.ReadConfigFile(c, logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't use context because this command doesn't define "credentials-file" flag
|
||||||
|
configPresent := func(s string) bool {
|
||||||
|
val, err := src.String(s)
|
||||||
|
return err == nil && val != ""
|
||||||
|
}
|
||||||
|
if src.TunnelID == "" || !configPresent("credentials-file") {
|
||||||
|
return fmt.Errorf(`Configuration file %s must contain entries for the tunnel to run and its associated credentials:
|
||||||
|
tunnel: TUNNEL-UUID
|
||||||
|
credentials-file: CREDENTIALS-FILE
|
||||||
|
`, src.Source())
|
||||||
|
}
|
||||||
|
if src.Source() != serviceConfigPath {
|
||||||
|
if exists, err := config.FileExists(serviceConfigPath); err != nil || exists {
|
||||||
|
return fmt.Errorf("Possible conflicting configuration in %[1]s and %[2]s. Either remove %[2]s or run `cloudflared --config %[2]s service install`", src.Source(), serviceConfigPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := copyFile(src.Source(), serviceConfigPath); err != nil {
|
||||||
|
return fmt.Errorf("failed to copy %s to %s: %w", src.Source(), serviceConfigPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templateArgs.ExtraArgs = []string{
|
||||||
|
"tunnel", "run",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isSystemd():
|
case isSystemd():
|
||||||
logger.Infof("Using Systemd")
|
logger.Infof("Using Systemd")
|
||||||
return installSystemd(&templateArgs, logger)
|
return installSystemd(&templateArgs, logger)
|
||||||
default:
|
default:
|
||||||
logger.Infof("Using Sysv")
|
logger.Infof("Using SysV")
|
||||||
return installSysv(&templateArgs, logger)
|
return installSysv(&templateArgs, logger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +335,7 @@ func uninstallLinuxService(c *cli.Context) error {
|
||||||
logger.Infof("Using Systemd")
|
logger.Infof("Using Systemd")
|
||||||
return uninstallSystemd(logger)
|
return uninstallSystemd(logger)
|
||||||
default:
|
default:
|
||||||
logger.Infof("Using Sysv")
|
logger.Infof("Using SysV")
|
||||||
return uninstallSysv(logger)
|
return uninstallSysv(logger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,9 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceTemplate struct {
|
type ServiceTemplate struct {
|
||||||
|
@ -21,7 +22,8 @@ type ServiceTemplate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceTemplateArgs struct {
|
type ServiceTemplateArgs struct {
|
||||||
Path string
|
Path string
|
||||||
|
ExtraArgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *ServiceTemplate) ResolvePath() (string, error) {
|
func (st *ServiceTemplate) ResolvePath() (string, error) {
|
||||||
|
@ -139,6 +141,33 @@ func copyCredential(srcCredentialPath, destCredentialPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dest string) error {
|
||||||
|
srcFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
destFile, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
defer func() {
|
||||||
|
destFile.Close()
|
||||||
|
if !ok {
|
||||||
|
_ = os.Remove(dest)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := io.Copy(destFile, srcFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func copyConfig(srcConfigPath, destConfigPath string) error {
|
func copyConfig(srcConfigPath, destConfigPath string) error {
|
||||||
// Copy or create config
|
// Copy or create config
|
||||||
destFile, exists, err := openFile(destConfigPath, true)
|
destFile, exists, err := openFile(destConfigPath, true)
|
||||||
|
|
Loading…
Reference in New Issue