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 9 commits
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
35 changes: 35 additions & 0 deletions src/k8s/cmd/k8s/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package k8s

import (
cmdutil "github.com/canonical/k8s/cmd/util"

bschimke95 marked this conversation as resolved.
Show resolved Hide resolved
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -34,3 +35,37 @@ func hookInitializeFormatter(env cmdutil.ExecutionEnvironment, format *string) f
}
}
}

// hookCheckLXD verifies the ownership of directories needed for Kubernetes to function.
// If a potential issue is detected, it displays a warning to the user.
func hookCheckLXD() func(*cobra.Command, []string) {
return func(cmd *cobra.Command, args []string) {
// pathsOwnershipCheck paths to validate root is the owner
var pathsOwnershipCheck = []string{"/sys", "/proc", "/dev/kmsg"}
inLXD, err := cmdutil.InLXDContainer()
if err != nil {
cmd.PrintErrf("Failed to check if running inside LXD container: %w", err)
return
}
if inLXD {
var errMsgs []string
for _, pathToCheck := range pathsOwnershipCheck {
if err2 := cmdutil.ValidateRootOwnership(pathToCheck); err2 != nil {
bschimke95 marked this conversation as resolved.
Show resolved Hide resolved
errMsgs = append(errMsgs, err2.Error())
}
}
if len(errMsgs) > 0 {
if debug, _ := cmd.Flags().GetBool("debug"); debug {
bschimke95 marked this conversation as resolved.
Show resolved Hide resolved
cmd.PrintErrln("Warning: When validating required resources potential issues found:")
for _, errMsg := range errMsgs {
cmd.PrintErrln("\t", errMsg)
}
}
cmd.PrintErrln("The lxc profile for Canonical Kubernetes might be missing.")
cmd.PrintErrln("For running k8s inside LXD container refer to " +
"https://documentation.ubuntu.com/canonical-kubernetes/latest/snap/howto/install/lxd/")
}
}
return
}
}
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), hookCheckLXD()),
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
2 changes: 1 addition & 1 deletion src/k8s/cmd/k8s/k8s_join_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func newJoinClusterCmd(env cmdutil.ExecutionEnvironment) *cobra.Command {
cmd := &cobra.Command{
Use: "join-cluster <join-token>",
Short: "Join a cluster using the provided token",
PreRun: chainPreRunHooks(hookRequireRoot(env), hookInitializeFormatter(env, &opts.outputFormat)),
PreRun: chainPreRunHooks(hookRequireRoot(env), hookInitializeFormatter(env, &opts.outputFormat), hookCheckLXD()),
Args: cmdutil.ExactArgs(env, 1),
Run: func(cmd *cobra.Command, args []string) {
token := args[0]
Expand Down
57 changes: 57 additions & 0 deletions src/k8s/cmd/util/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cmdutil

import (
"fmt"
"os"
"strings"
"syscall"
)

// getFileOwnerAndGroup retrieves the UID and GID of a file.
func getFileOwnerAndGroup(filePath string) (uid, gid uint32, err error) {
// Get file info using os.Stat
fileInfo, err := os.Stat(filePath)
if err != nil {
return 0, 0, fmt.Errorf("error getting file info: %w", err)
}
// Convert the fileInfo.Sys() to syscall.Stat_t to access UID and GID
stat, ok := fileInfo.Sys().(*syscall.Stat_t)
if !ok {
return 0, 0, fmt.Errorf("failed to cast to syscall.Stat_t")
}
// Return the UID and GID
return stat.Uid, stat.Gid, nil
}

// ValidateRootOwnership checks if given path owner root and root group.
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
func ValidateRootOwnership(path string) (err error) {
UID, GID, err := getFileOwnerAndGroup(path)
if err != nil {
return err
}
if UID != 0 {
return fmt.Errorf("owner of %s is user with UID %d expected 0", path, UID)
}
if GID != 0 {
return fmt.Errorf("owner of %s is group with GID %d expected 0", path, GID)
}
return nil
}

// InLXDContainer checks if k8s runs in lxd container.
maci3jka marked this conversation as resolved.
Show resolved Hide resolved
func InLXDContainer() (isLXD bool, err error) {

maci3jka marked this conversation as resolved.
Show resolved Hide resolved
initialProcessEnvironmentVariables := "/proc/1/environ"
bschimke95 marked this conversation as resolved.
Show resolved Hide resolved
content, err := os.ReadFile(initialProcessEnvironmentVariables)
if err != nil {
// if the permission to file is missing we still want to display info about lxd
if os.IsPermission(err) {
return true, fmt.Errorf("cannnot access %s to check if runing in LXD container: %w", initialProcessEnvironmentVariables, err)
}
return false, fmt.Errorf("cannnot read %s to check if runing in LXD container: %w", initialProcessEnvironmentVariables, err)
}
if strings.Contains(string(content), "container=lxc") {
return true, nil
}
return false, nil
}
Loading