Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warnings that k8s service may not work #657

Merged
merged 11 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/k8s/cmd/k8s/k8s_bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func newBootstrapCmd(env cmdutil.ExecutionEnvironment) *cobra.Command {
Use: "bootstrap",
Short: "Bootstrap a new Kubernetes cluster",
Long: "Generate certificates, configure service arguments and start the Kubernetes services.",
PreRun: chainPreRunHooks(hookRequireRoot(env), hookInitializeFormatter(env, &opts.outputFormat)),
PreRun: chainPreRunHooks(hookRequireRoot(env), hookInitializeFormatter(env, &opts.outputFormat), cmdutil.HookVerifyResources()),
Run: func(cmd *cobra.Command, args []string) {
if opts.interactive && opts.configFile != "" {
cmd.PrintErrln("Error: --interactive and --file flags cannot be set at the same time.")
Expand Down
5 changes: 3 additions & 2 deletions src/k8s/cmd/k8sd/k8sd.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ func addCommands(root *cobra.Command, group *cobra.Group, commands ...*cobra.Com

func NewRootCmd(env cmdutil.ExecutionEnvironment) *cobra.Command {
cmd := &cobra.Command{
Use: "k8sd",
Short: "Canonical Kubernetes orchestrator and clustering daemon",
Use: "k8sd",
Short: "Canonical Kubernetes orchestrator and clustering daemon",
PreRun: cmdutil.HookVerifyResources(),
Run: func(cmd *cobra.Command, args []string) {
// configure logging
log.Configure(log.Options{
Expand Down
92 changes: 92 additions & 0 deletions src/k8s/cmd/util/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cmdutil

import (
"errors"
"fmt"
"os"
"os/exec"
"strings"
"syscall"

"github.com/spf13/cobra"
)

// paths to validate if root in the owner
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
var pathsOwnershipCheck = []string{"/sys", "/proc", "/dev/kmsg"}

// HookVerifyResources checks ownership of dirs required for k8s to run.
// HookVerifyResources validates AppArmor configurations.
// If potential issue found pops up warning.
func HookVerifyResources() func(*cobra.Command, []string) {
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
return func(cmd *cobra.Command, args []string) {
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
var warnList []string
for _, path := range pathsOwnershipCheck {
if msg, err := validateRootOwnership(path); err != nil {
cmd.PrintErrf(err.Error())
} else {
warnList = append(warnList, msg)
}
}

if armor, err := checkAppArmor(); err != nil {
cmd.PrintErr(err.Error())
} else if len(armor) > 0 {
warnList = append(warnList, armor)
}

if len(warnList) > 0 {
cmd.PrintErrf("Warning: k8s may not run correctly due to reasons:\n%s"+
"If runnung inside LXD container refer to "+
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
"https://documentation.ubuntu.com/canonical-kubernetes/latest/snap/howto/install/lxd/.\n",
strings.Join(warnList, ""))
}
}
}

// validateRootOwnership checks if given path owner root and root group.
func validateRootOwnership(path string) (string, error) {

info, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return fmt.Sprintf("%s do not exist\n", path), nil
} else {
return "", err
}
}
var UID int
var GID int
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
UID = int(stat.Uid)
GID = int(stat.Gid)
} else {
return "", errors.New(fmt.Sprintf("cannot access path %s", path))
}
var warnList string
if UID != 0 {
warnList += fmt.Sprintf("owner of %s is user with UID %d expected 0\n", path, UID)
}
if GID != 0 {
warnList += fmt.Sprintf("owner of %s is group with GID %d expected 0\n", path, GID)
}
return warnList, nil
}

// checkAppArmor checks AppArmor status.
func checkAppArmor() (string, error) {
cmd := exec.Command("journalctl", "-u", "apparmor")
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
out, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
output := string(out)
// AppArmor configured for container or service not present
if strings.Contains(output, "Not starting AppArmor in container") || strings.Contains(output, "-- No entries --") {
return "", nil
// cannot read status of AppArmor
} else if strings.Contains(output, "Users in groups 'adm', 'systemd-journal' can see all messages.") {
return "could not validate AppArmor status\n", nil
}

return "AppArmor may block hosting of nested containers\n", nil
}
Loading