mirror of
https://github.com/aljazceru/kata-containers.git
synced 2025-12-31 04:54:21 +01:00
Update the sandbox dir clean up logic to be more appropriate Add different seeds for randInt() method Fixes #2770 Signed-off-by: Feng Wang <feng.wang@databricks.com>
158 lines
4.0 KiB
Go
158 lines
4.0 KiB
Go
// Copyright (c) 2020 Ant Group
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
acceptEncodingHeader = "Accept-Encoding"
|
|
)
|
|
|
|
var utilsLog = logrus.WithFields(logrus.Fields{"source": "pkg/utils"})
|
|
|
|
// GzipAccepted returns whether the client will accept gzip-encoded content.
|
|
func GzipAccepted(header http.Header) bool {
|
|
a := header.Get(acceptEncodingHeader)
|
|
parts := strings.Split(a, ",")
|
|
for _, part := range parts {
|
|
part = strings.TrimSpace(part)
|
|
if part == "gzip" || strings.HasPrefix(part, "gzip;") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// String2Pointer make a string to a pointer to string
|
|
func String2Pointer(s string) *string {
|
|
return &s
|
|
}
|
|
|
|
// RunCommandFull returns the commands space-trimmed standard output and
|
|
// error on success. Note that if the command fails, the requested output will
|
|
// still be returned, along with an error.
|
|
func RunCommandFull(args []string, includeStderr bool) (string, error) {
|
|
cmd := exec.Command(args[0], args[1:]...)
|
|
var err error
|
|
var bytes []byte
|
|
|
|
if includeStderr {
|
|
bytes, err = cmd.CombinedOutput()
|
|
} else {
|
|
bytes, err = cmd.Output()
|
|
}
|
|
|
|
trimmed := strings.TrimSpace(string(bytes))
|
|
|
|
return trimmed, err
|
|
}
|
|
|
|
// RunCommand returns the commands space-trimmed standard output on success
|
|
func RunCommand(args []string) (string, error) {
|
|
return RunCommandFull(args, false)
|
|
}
|
|
|
|
// EnsureDir check if a directory exist, if not then create it
|
|
func EnsureDir(path string, mode os.FileMode) error {
|
|
if !filepath.IsAbs(path) {
|
|
return fmt.Errorf("Not an absolute path: %s", path)
|
|
}
|
|
|
|
if fi, err := os.Stat(path); err != nil {
|
|
if os.IsNotExist(err) {
|
|
if err = os.MkdirAll(path, mode); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
} else if !fi.IsDir() {
|
|
return fmt.Errorf("Not a directory: %s", path)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func FirstValidExecutable(paths []string) (string, error) {
|
|
for _, p := range paths {
|
|
info, err := os.Stat(p)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
return "", err
|
|
}
|
|
mode := info.Mode()
|
|
// check whether the file is an executable
|
|
if mode&0111 == 0 {
|
|
continue
|
|
}
|
|
return p, nil
|
|
}
|
|
return "", fmt.Errorf("all the executables are invalid")
|
|
}
|
|
|
|
// CreateVmmUser create a temp user for running Kata Containers under rootless mode.
|
|
func CreateVmmUser() (string, error) {
|
|
var (
|
|
err error
|
|
userName string
|
|
)
|
|
|
|
useraddPath, err := FirstValidExecutable([]string{"/usr/sbin/useradd", "/sbin/useradd", "/bin/useradd"})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
nologinPath, err := FirstValidExecutable([]string{"/usr/sbin/nologin", "/sbin/nologin", "/bin/nologin"})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Add retries to mitigate temporary errors and race conditions. For example, the user already exists
|
|
// or another instance of the runtime is also creating a user.
|
|
maxAttempt := 5
|
|
rand.Seed(time.Now().UnixNano())
|
|
for i := 0; i < maxAttempt; i++ {
|
|
userName = fmt.Sprintf("kata-%v", rand.Intn(100000))
|
|
_, err = RunCommand([]string{useraddPath, "-M", "-s", nologinPath, userName, "-c", "\"Kata Containers temporary hypervisor user\""})
|
|
if err == nil {
|
|
return userName, nil
|
|
}
|
|
utilsLog.WithField("attempt", i+1).WithField("username", userName).
|
|
WithError(err).Warn("failed to add user, will try again")
|
|
}
|
|
return "", fmt.Errorf("could not create VMM user: %v", err)
|
|
}
|
|
|
|
// RemoveVmmUser delete user created by CreateVmmUser.
|
|
func RemoveVmmUser(user string) error {
|
|
userdelPath, err := FirstValidExecutable([]string{"/usr/sbin/userdel", "/sbin/userdel", "/bin/userdel"})
|
|
if err != nil {
|
|
utilsLog.WithField("username", user).WithError(err).Warn("failed to remove user")
|
|
return err
|
|
}
|
|
|
|
// Add retries to mitigate temporary errors and race conditions.
|
|
for i := 0; i < 5; i++ {
|
|
if _, err = RunCommand([]string{userdelPath, "-f", user}); err == nil {
|
|
return nil
|
|
}
|
|
utilsLog.WithField("username", user).WithField("attempt", i+1).WithError(err).Warn("failed to remove user")
|
|
}
|
|
return err
|
|
}
|