Skip to content

Commit

Permalink
More flexible sudo/doas/elevated access usage (#192)
Browse files Browse the repository at this point in the history
* More flexible sudo/doas/elevated access usage

* Sprintf does not understand exec.Sudo

* Everything was broken

* Rig was totally broken

* exec.Sudo is not a string

* Bring in rig from a branch for debug info

* Hmm?

* Dont know how to properly point to a branch

* Wait for k0s stop

* More logging

* Phase ordering seems to have some problems

* Rig 0.4.4 final
  • Loading branch information
kke authored Aug 23, 2021
1 parent bbdc32a commit 428bedd
Show file tree
Hide file tree
Showing 18 changed files with 121 additions and 49 deletions.
4 changes: 2 additions & 2 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ var applyCommand = &cli.Command{
&phase.PrepareHosts{},
&phase.GatherFacts{},
&phase.DownloadBinaries{},
&phase.UploadBinaries{},
&phase.DownloadK0s{},
&phase.UploadFiles{},
&phase.ValidateHosts{},
&phase.GatherK0sFacts{},
&phase.ValidateFacts{SkipDowngradeCheck: ctx.Bool("disable-downgrade-check")},
&phase.UploadBinaries{},
&phase.DownloadK0s{},
&phase.RunHooks{Stage: "before", Action: "apply"},
&phase.ConfigureK0s{},
&phase.Restore{
Expand Down
39 changes: 32 additions & 7 deletions config/cluster/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,13 @@ func (h *Host) K0sInstallCommand() string {
flags.AddOrReplace(fmt.Sprintf("--kubelet-extra-args=%s", strconv.Quote(extra.Join())))
}

return h.Configurer.K0sCmdf("install %s %s", role, flags.Join())
cmd := h.Configurer.K0sCmdf("install %s %s", role, flags.Join())
sudocmd, err := h.Sudo(cmd)
if err != nil {
log.Warnf("%s: %s", h, err.Error())
return cmd
}
return sudocmd
}

// K0sBackupCommand returns a full command to be used as run k0s backup
Expand Down Expand Up @@ -233,7 +239,7 @@ func (h *Host) K0sServiceName() string {
// UpdateK0sBinary updates the binary on the host either by downloading or uploading, based on the config
func (h *Host) UpdateK0sBinary(version string) error {
if h.K0sBinaryPath != "" {
if err := h.Upload(h.K0sBinaryPath, h.Configurer.K0sBinaryPath()); err != nil {
if err := h.Upload(h.K0sBinaryPath, h.Configurer.K0sBinaryPath(), exec.Sudo(h)); err != nil {
return err
}
if err := h.Configurer.Chmod(h, h.Configurer.K0sBinaryPath(), "0700"); err != nil {
Expand All @@ -244,7 +250,7 @@ func (h *Host) UpdateK0sBinary(version string) error {
return err
}

output, err := h.ExecOutput(h.Configurer.K0sCmdf("version"))
output, err := h.ExecOutput(h.Configurer.K0sCmdf("version"), exec.Sudo(h))
if err != nil {
return fmt.Errorf("downloaded k0s binary is invalid: %s", err.Error())
}
Expand All @@ -270,7 +276,7 @@ type kubeNodeStatus struct {

// KubeNodeReady runs kubectl on the host and returns true if the given node is marked as ready
func (h *Host) KubeNodeReady(node *Host) (bool, error) {
output, err := h.ExecOutput(h.Configurer.KubectlCmdf("get node -l kubernetes.io/hostname=%s -o json", node.Metadata.Hostname), exec.HideOutput())
output, err := h.ExecOutput(h.Configurer.KubectlCmdf("get node -l kubernetes.io/hostname=%s -o json", node.Metadata.Hostname), exec.HideOutput(), exec.Sudo(h))
if err != nil {
return false, err
}
Expand Down Expand Up @@ -314,12 +320,12 @@ func (h *Host) WaitKubeNodeReady(node *Host) error {

// DrainNode drains the given node
func (h *Host) DrainNode(node *Host) error {
return h.Exec(h.Configurer.KubectlCmdf("drain --grace-period=120 --force --timeout=5m --ignore-daemonsets --delete-local-data %s", node.Metadata.Hostname))
return h.Exec(h.Configurer.KubectlCmdf("drain --grace-period=120 --force --timeout=5m --ignore-daemonsets --delete-local-data %s", node.Metadata.Hostname), exec.Sudo(h))
}

// UncordonNode marks the node schedulable again
func (h *Host) UncordonNode(node *Host) error {
return h.Exec(h.Configurer.KubectlCmdf("uncordon %s", node.Metadata.Hostname))
return h.Exec(h.Configurer.KubectlCmdf("uncordon %s", node.Metadata.Hostname), exec.Sudo(h))
}

// CheckHTTPStatus will perform a web request to the url and return an error if the http status is not the expected
Expand Down Expand Up @@ -359,7 +365,26 @@ func (h *Host) WaitK0sServiceRunning() error {
if !h.Configurer.ServiceIsRunning(h, h.K0sServiceName()) {
return fmt.Errorf("not running")
}
return h.Exec(h.Configurer.K0sCmdf("status"))
return h.Exec(h.Configurer.K0sCmdf("status"), exec.Sudo(h))
},
retry.DelayType(retry.CombineDelay(retry.FixedDelay, retry.RandomDelay)),
retry.MaxJitter(time.Second*2),
retry.Delay(time.Second*3),
retry.Attempts(60),
)
}

// WaitK0sServiceStopped blocks until the k0s service is no longer running on the host
func (h *Host) WaitK0sServiceStopped() error {
return retry.Do(
func() error {
if h.Configurer.ServiceIsRunning(h, h.K0sServiceName()) {
return fmt.Errorf("k0s still running")
}
if h.Exec(h.Configurer.K0sCmdf("status"), exec.Sudo(h)) == nil {
return fmt.Errorf("k0s still running")
}
return nil
},
retry.DelayType(retry.CombineDelay(retry.FixedDelay, retry.RandomDelay)),
retry.MaxJitter(time.Second*2),
Expand Down
4 changes: 2 additions & 2 deletions config/cluster/k0s.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (k *K0s) SetDefaults() {
func (k K0s) GenerateToken(h *Host, role string, expiry time.Duration) (token string, err error) {
err = retry.Do(
func() error {
output, err := h.ExecOutput(h.Configurer.K0sCmdf("token create --config %s --role %s --expiry %s", h.K0sConfigPath(), role, expiry.String()), exec.HideOutput())
output, err := h.ExecOutput(h.Configurer.K0sCmdf("token create --config %s --role %s --expiry %s", h.K0sConfigPath(), role, expiry.String()), exec.HideOutput(), exec.Sudo(h))
if err != nil {
return err
}
Expand All @@ -74,5 +74,5 @@ func (k K0s) GenerateToken(h *Host, role string, expiry time.Duration) (token st

// GetClusterID uses kubectl to fetch the kube-system namespace uid
func (k K0s) GetClusterID(h *Host) (string, error) {
return h.ExecOutput(h.Configurer.KubectlCmdf("get -n kube-system namespace kube-system -o template={{.metadata.uid}}"))
return h.ExecOutput(h.Configurer.KubectlCmdf("get -n kube-system namespace kube-system -o template={{.metadata.uid}}"), exec.Sudo(h))
}
13 changes: 7 additions & 6 deletions configurer/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strconv"
"strings"

"github.com/k0sproject/rig/exec"
"github.com/k0sproject/rig/os"
)

Expand Down Expand Up @@ -40,12 +41,12 @@ func (l Linux) Arch(h os.Host) (string, error) {

// Chmod changes file permissions
func (l Linux) Chmod(h os.Host, path, chmod string) error {
return h.Execf("sudo chmod %s %s", chmod, path)
return h.Execf("chmod %s %s", chmod, path, exec.Sudo(h))
}

// K0sCmdf can be used to construct k0s commands in sprintf style.
func (l Linux) K0sCmdf(template string, args ...interface{}) string {
return fmt.Sprintf("sudo %s %s", l.K0sBinaryPath(), fmt.Sprintf(template, args...))
return fmt.Sprintf("%s %s", l.K0sBinaryPath(), fmt.Sprintf(template, args...))
}

// K0sBinaryPath returns the location of k0s binary
Expand Down Expand Up @@ -86,7 +87,7 @@ func (l Linux) DownloadK0s(h os.Host, version, arch string) error {
return err
}

return h.Execf(`sudo install -m 0750 -o root -g adm "%s" "%s"`, tmp, l.K0sBinaryPath())
return h.Execf(`install -m 0750 -o root -g adm "%s" "%s"`, tmp, l.K0sBinaryPath(), exec.Sudo(h))
}

// ReplaceK0sTokenPath replaces the config path in the service stub
Expand All @@ -96,17 +97,17 @@ func (l Linux) ReplaceK0sTokenPath(h os.Host, spath string) error {

// FileContains returns true if a file contains the substring
func (l Linux) FileContains(h os.Host, path, s string) bool {
return h.Execf(`sudo grep -q "%s" "%s"`, s, path) == nil
return h.Execf(`grep -q "%s" "%s"`, s, path, exec.Sudo(h)) == nil
}

// MoveFile moves a file on the host
func (l Linux) MoveFile(h os.Host, src, dst string) error {
return h.Execf(`sudo mv "%s" "%s"`, src, dst)
return h.Execf(`mv "%s" "%s"`, src, dst, exec.Sudo(h))
}

// DeleteFile deletes a file on the host
func (l Linux) DeleteFile(h os.Host, path string) error {
return h.Execf(`sudo rm -f "%s"`, path)
return h.Execf(`rm -f "%s"`, path, exec.Sudo(h))
}

// KubeconfigPath returns the path to a kubeconfig on the host
Expand Down
7 changes: 2 additions & 5 deletions configurer/linux/alpine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/k0sproject/k0sctl/configurer"
"github.com/k0sproject/rig"
"github.com/k0sproject/rig/exec"
"github.com/k0sproject/rig/os"
"github.com/k0sproject/rig/os/registry"
)
Expand Down Expand Up @@ -33,13 +34,9 @@ func init() {

// InstallPackage installs packages via slackpkg
func (l Alpine) InstallPackage(h os.Host, pkg ...string) error {
return h.Execf("sudo apk add --update %s", strings.Join(pkg, " "))
return h.Execf("apk add --update %s", strings.Join(pkg, " "), exec.Sudo(h))
}

func (l Alpine) Prepare(h os.Host) error {
if !l.CommandExist(h, "sudo") {
return h.Exec("apk add --update sudo")
}

return l.InstallPackage(h, "findutils", "coreutils")
}
12 changes: 11 additions & 1 deletion configurer/linux/slackware.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package linux

import (
"fmt"
"strings"

"github.com/k0sproject/rig"
Expand All @@ -27,5 +28,14 @@ func init() {

// InstallPackage installs packages via slackpkg
func (l Slackware) InstallPackage(h os.Host, pkg ...string) error {
return h.Execf("sudo slackpkg update && sudo slackpkg install --priority ADD %s", strings.Join(pkg, " "))
updatecmd, err := h.Sudo("slackpkg update")
if err != nil {
return err
}
installcmd, err := h.Sudo(fmt.Sprintf("slackpkg install --priority ADD %s", strings.Join(pkg, " ")))
if err != nil {
return err
}

return h.Execf("%s && %s", updatecmd, installcmd)
}
13 changes: 11 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ go 1.16

require (
github.com/AlecAivazis/survey/v2 v2.2.8
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 // indirect
github.com/Masterminds/semver v1.5.0
github.com/avast/retry-go v3.0.0+incompatible
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/creasty/defaults v1.5.1
github.com/denisbrodbeck/machineid v1.0.1
github.com/gammazero/workerpool v1.1.1
github.com/go-playground/validator/v10 v10.4.1
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/hashicorp/go-version v1.2.1
github.com/k0sproject/dig v0.2.0
github.com/k0sproject/rig v0.3.23
github.com/k0sproject/rig v0.4.4
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
github.com/masterzen/winrm v0.0.0-20210623064412-3b76017826b0 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/segmentio/analytics-go v3.1.0+incompatible
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
Expand All @@ -23,7 +28,11 @@ require (
github.com/stretchr/testify v1.7.0
github.com/urfave/cli/v2 v2.3.0
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sys v0.0.0-20210819072135-bce67f096156
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.4.0
k8s.io/client-go v0.19.3
)
Loading

0 comments on commit 428bedd

Please sign in to comment.