From 35368e47fab2b455c01aad2a4be69511fdd49ab3 Mon Sep 17 00:00:00 2001 From: Anthony Emengo Date: Thu, 4 Apr 2019 11:35:46 -0400 Subject: [PATCH] Make linux work as normal user that escalates to root - Run servicew commands with sudo access - Retrieve dynamic IP address with sudo access - SudoShell -> Sudo --- driver/hyperkit/driver.go | 4 +-- driver/ip_linux.go | 23 +++++++++++-- driver/kvm/driver.go | 4 +-- .../fixtures/simple-darwin.yml | 0 .../fixtures/simple-linux.yml | 0 .../integration_suite_test.go | 2 +- .../integration_test.go | 2 +- pkg/servicew/client/client.go | 32 +++++-------------- runner/{sudo_shell.go => sudo.go} | 4 +-- 9 files changed, 36 insertions(+), 35 deletions(-) rename pkg/servicew/{integration => acceptance}/fixtures/simple-darwin.yml (100%) rename pkg/servicew/{integration => acceptance}/fixtures/simple-linux.yml (100%) rename pkg/servicew/{integration => acceptance}/integration_suite_test.go (96%) rename pkg/servicew/{integration => acceptance}/integration_test.go (98%) rename runner/{sudo_shell.go => sudo.go} (77%) diff --git a/driver/hyperkit/driver.go b/driver/hyperkit/driver.go index 3713de9..7e5515c 100644 --- a/driver/hyperkit/driver.go +++ b/driver/hyperkit/driver.go @@ -18,7 +18,7 @@ type Hyperkit struct { Config config.Config DaemonRunner driver.DaemonRunner CFDevD *client.Client - SudoShell *runner.SudoShell + SudoShell *runner.Sudo } func New( @@ -32,7 +32,7 @@ func New( Config: cfg, DaemonRunner: daemonRunner, CFDevD: cfdevdClient, - SudoShell: &runner.SudoShell{}, + SudoShell: &runner.Sudo{}, } } diff --git a/driver/ip_linux.go b/driver/ip_linux.go index db4d7a0..772a8a4 100644 --- a/driver/ip_linux.go +++ b/driver/ip_linux.go @@ -5,21 +5,33 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os/exec" "path/filepath" ) func IP(cfg config.Config) (string, error) { var ( + ipPath = filepath.Join(cfg.StateLinuxkit, "ip") macAddrPath = filepath.Join(cfg.StateLinuxkit, "mac-addr") - vBridgeInfoPath = filepath.Join("/var/lib/libvirt/dnsmasq/virbr0.status") + vBridgeInfoPath = "/var/lib/libvirt/dnsmasq/virbr0.status" ) - macAddr, err := ioutil.ReadFile(macAddrPath) + // The logic below is a bit of a hack. + // Since the services will get started as root, the qemu files containing the ip address will be written as root. + // We don't want to escalate to root every time we need the ip throughout the lifecycle of the program, so we write + // the ip address as a normal file when we first get it. This logic is making an assumption that root privileges + // has been retrieved as part of a prior step and has not yet timed out. + data, err := ioutil.ReadFile(ipPath) + if err == nil { + return string(data), nil + } + + macAddr, err := readAsSudo(macAddrPath) if err != nil { return "", err } - vBridgeInfo, err := ioutil.ReadFile(vBridgeInfoPath) + vBridgeInfo, err := readAsSudo(vBridgeInfoPath) if err != nil { return "", err } @@ -36,6 +48,8 @@ func IP(cfg config.Config) (string, error) { for _, result := range results { if result.MacAddr == string(macAddr) { + ioutil.WriteFile(ipPath, []byte(result.IPAddr), 0600) + return result.IPAddr, nil } } @@ -43,3 +57,6 @@ func IP(cfg config.Config) (string, error) { return "", fmt.Errorf("unable to find VM IP address from '%s'", vBridgeInfoPath) } +func readAsSudo(path string) ([]byte, error) { + return exec.Command("sudo", "-S", "cat", path).Output() +} diff --git a/driver/kvm/driver.go b/driver/kvm/driver.go index 67c147d..988b884 100644 --- a/driver/kvm/driver.go +++ b/driver/kvm/driver.go @@ -20,7 +20,7 @@ type KVM struct { UI driver.UI Config config.Config DaemonRunner driver.DaemonRunner - SudoShell *runner.SudoShell + SudoShell *runner.Sudo } func New( @@ -32,7 +32,7 @@ func New( UI: ui, Config: cfg, DaemonRunner: daemonRunner, - SudoShell: &runner.SudoShell{}, + SudoShell: &runner.Sudo{}, } } diff --git a/pkg/servicew/integration/fixtures/simple-darwin.yml b/pkg/servicew/acceptance/fixtures/simple-darwin.yml similarity index 100% rename from pkg/servicew/integration/fixtures/simple-darwin.yml rename to pkg/servicew/acceptance/fixtures/simple-darwin.yml diff --git a/pkg/servicew/integration/fixtures/simple-linux.yml b/pkg/servicew/acceptance/fixtures/simple-linux.yml similarity index 100% rename from pkg/servicew/integration/fixtures/simple-linux.yml rename to pkg/servicew/acceptance/fixtures/simple-linux.yml diff --git a/pkg/servicew/integration/integration_suite_test.go b/pkg/servicew/acceptance/integration_suite_test.go similarity index 96% rename from pkg/servicew/integration/integration_suite_test.go rename to pkg/servicew/acceptance/integration_suite_test.go index 49618a8..d9764d6 100644 --- a/pkg/servicew/integration/integration_suite_test.go +++ b/pkg/servicew/acceptance/integration_suite_test.go @@ -1,4 +1,4 @@ -package integration_test +package acceptance_test import ( "github.com/onsi/gomega/gexec" diff --git a/pkg/servicew/integration/integration_test.go b/pkg/servicew/acceptance/integration_test.go similarity index 98% rename from pkg/servicew/integration/integration_test.go rename to pkg/servicew/acceptance/integration_test.go index 837de82..b13419b 100644 --- a/pkg/servicew/integration/integration_test.go +++ b/pkg/servicew/acceptance/integration_test.go @@ -1,4 +1,4 @@ -package integration_test +package acceptance_test import ( "code.cloudfoundry.org/cfdev/pkg/servicew/client" diff --git a/pkg/servicew/client/client.go b/pkg/servicew/client/client.go index dc109b6..6a12e54 100644 --- a/pkg/servicew/client/client.go +++ b/pkg/servicew/client/client.go @@ -3,6 +3,7 @@ package client import ( "code.cloudfoundry.org/cfdev/pkg/servicew/config" "code.cloudfoundry.org/cfdev/pkg/servicew/program" + "code.cloudfoundry.org/cfdev/runner" "fmt" "gopkg.in/yaml.v2" "io" @@ -15,12 +16,14 @@ import ( type ServiceWrapper struct { binaryPath string workdir string + runner *runner.Sudo } func New(binaryPath string, workdir string) *ServiceWrapper { return &ServiceWrapper{ binaryPath: binaryPath, workdir: workdir, + runner: &runner.Sudo{}, } } @@ -46,13 +49,7 @@ func (s *ServiceWrapper) Install(cfg config.Config) error { return err } - command := exec.Command(swrapperPath, "install") - output, err := command.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to install '%s': %s: %s", cfg.Label, err, output) - } - - return nil + return s.runner.Run(swrapperPath, "install") } func (s *ServiceWrapper) Uninstall(label string) error { @@ -65,10 +62,9 @@ func (s *ServiceWrapper) Uninstall(label string) error { return nil } - command := exec.Command(swrapperPath, "uninstall") - output, err := command.CombinedOutput() + err := s.runner.Run(swrapperPath, "uninstall") if err != nil { - return fmt.Errorf("failed to uninstall '%s': %s: %s", label, err, output) + return fmt.Errorf("failed to uninstall '%s': %s", label, err) } err = os.RemoveAll(swrapperPath) @@ -80,13 +76,7 @@ func (s *ServiceWrapper) Uninstall(label string) error { } func (s *ServiceWrapper) Start(label string) error { - command := exec.Command(s.swrapperPath(label), "start") - output, err := command.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to start '%s': %s: %s", label, err, output) - } - - return nil + return s.runner.Run(s.swrapperPath(label), "start") } func (s *ServiceWrapper) Stop(label string) error { @@ -94,13 +84,7 @@ func (s *ServiceWrapper) Stop(label string) error { return nil } - command := exec.Command(s.swrapperPath(label), "stop") - output, err := command.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to stop '%s': %s: %s", label, err, output) - } - - return nil + return s.runner.Run(s.swrapperPath(label), "stop") } func (s *ServiceWrapper) IsRunning(label string) (bool, error) { diff --git a/runner/sudo_shell.go b/runner/sudo.go similarity index 77% rename from runner/sudo_shell.go rename to runner/sudo.go index 90c7e0e..c821f9d 100644 --- a/runner/sudo_shell.go +++ b/runner/sudo.go @@ -5,9 +5,9 @@ import ( "os/exec" ) -type SudoShell struct{} +type Sudo struct{} -func (s *SudoShell) Run(args ...string) error { +func (s *Sudo) Run(args ...string) error { var ( invocation = append([]string{"-S"}, args...) cmd = exec.Command("sudo", invocation...)