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 all 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: %s", err.Error())
return
}
if inLXD {
var errMsgs []string
for _, pathToCheck := range pathsOwnershipCheck {
if err = cmdutil.ValidateRootOwnership(pathToCheck); err != nil {
errMsgs = append(errMsgs, err.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
56 changes: 56 additions & 0 deletions src/k8s/cmd/util/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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 the specified path is owned by the root user and root group.
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 a lxd container.
func InLXDContainer() (isLXD bool, err error) {
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