mirror of
https://github.com/aljazceru/kata-containers.git
synced 2025-12-25 18:14:21 +01:00
- Container only is responsable of namespaces and cgroups inside the VM. - Sandbox will manage VM resources. The resouces has to be re-calculated and updated: - Create new Container: If a new container is created the cpus and memory may be updated. - Container update: The update call will change the cgroups of a container. the sandbox would need to resize the cpus and VM depending the update. To manage the resources from sandbox the hypervisor interaface adds two methods. - resizeMemory(). This function will be used by the sandbox to request increase or decrease the VM memory. - resizeCPUs() vcpus are requested to the hypervisor based on the sum of all the containers in the sandbox. The CPUs calculations use the container cgroup information all the time. This should allow do better calculations. For example. 2 containers in a pod. container 1 cpus = .5 container 2 cpus = .5 Now: Sandbox requested vcpus 1 Before: Sandbox requested vcpus 2 When a update request is done only some atributes have information. If cpu and quota are nil or 0 we dont update them. If we would updated them the sandbox calculations would remove already removed vcpus. This commit also moves the sandbox resource update call at container.update() just before the container cgroups information is updated. Fixes: #833 Signed-off-by: Jose Carlos Venegas Munoz <jose.carlos.venegas.munoz@intel.com>
225 lines
5.3 KiB
Go
225 lines
5.3 KiB
Go
// Copyright (c) 2017 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package utils
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
)
|
|
|
|
const cpBinaryName = "cp"
|
|
|
|
const fileMode0755 = os.FileMode(0755)
|
|
|
|
// MibToBytesShift the number to shift needed to convert MiB to Bytes
|
|
const MibToBytesShift = 20
|
|
|
|
// MaxSocketPathLen is the effective maximum Unix domain socket length.
|
|
//
|
|
// See unix(7).
|
|
const MaxSocketPathLen = 107
|
|
|
|
// VSockDevicePath path to vsock device
|
|
var VSockDevicePath = "/dev/vsock"
|
|
|
|
// VHostVSockDevicePath path to vhost-vsock device
|
|
var VHostVSockDevicePath = "/dev/vhost-vsock"
|
|
|
|
// FileCopy copys files from srcPath to dstPath
|
|
func FileCopy(srcPath, dstPath string) error {
|
|
if srcPath == "" {
|
|
return fmt.Errorf("Source path cannot be empty")
|
|
}
|
|
|
|
if dstPath == "" {
|
|
return fmt.Errorf("Destination path cannot be empty")
|
|
}
|
|
|
|
binPath, err := exec.LookPath(cpBinaryName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd := exec.Command(binPath, srcPath, dstPath)
|
|
|
|
return cmd.Run()
|
|
}
|
|
|
|
// GenerateRandomBytes generate n random bytes
|
|
func GenerateRandomBytes(n int) ([]byte, error) {
|
|
b := make([]byte, n)
|
|
_, err := rand.Read(b)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
// ReverseString reverses whole string
|
|
func ReverseString(s string) string {
|
|
r := []rune(s)
|
|
|
|
length := len(r)
|
|
for i, j := 0, length-1; i < length/2; i, j = i+1, j-1 {
|
|
r[i], r[j] = r[j], r[i]
|
|
}
|
|
|
|
return string(r)
|
|
}
|
|
|
|
// CleanupFds closed bundles of open fds in batch
|
|
func CleanupFds(fds []*os.File, numFds int) {
|
|
maxFds := len(fds)
|
|
|
|
if numFds < maxFds {
|
|
maxFds = numFds
|
|
}
|
|
|
|
for i := 0; i < maxFds; i++ {
|
|
_ = fds[i].Close()
|
|
}
|
|
}
|
|
|
|
// WriteToFile opens a file in write only mode and writes bytes to it
|
|
func WriteToFile(path string, data []byte) error {
|
|
f, err := os.OpenFile(path, os.O_WRONLY, fileMode0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
if _, err := f.Write(data); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ConstraintsToVCPUs converts CPU quota and period to vCPUs
|
|
func ConstraintsToVCPUs(quota int64, period uint64) uint {
|
|
if quota != 0 && period != 0 {
|
|
// Use some math magic to round up to the nearest whole vCPU
|
|
// (that is, a partial part of a quota request ends up assigning
|
|
// a whole vCPU, for instance, a request of 1.5 'cpu quotas'
|
|
// will give 2 vCPUs).
|
|
// This also has the side effect that we will always allocate
|
|
// at least 1 vCPU.
|
|
return uint((uint64(quota) + (period - 1)) / period)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// GetVirtDriveName returns the disk name format for virtio-blk
|
|
// Reference: https://github.com/torvalds/linux/blob/master/drivers/block/virtio_blk.c @c0aa3e0916d7e531e69b02e426f7162dfb1c6c0
|
|
func GetVirtDriveName(index int) (string, error) {
|
|
if index < 0 {
|
|
return "", fmt.Errorf("Index cannot be negative for drive")
|
|
}
|
|
|
|
// Prefix used for virtio-block devices
|
|
const prefix = "vd"
|
|
|
|
//Refer to DISK_NAME_LEN: https://github.com/torvalds/linux/blob/08c521a2011ff492490aa9ed6cc574be4235ce2b/include/linux/genhd.h#L61
|
|
diskNameLen := 32
|
|
base := 26
|
|
|
|
suffLen := diskNameLen - len(prefix)
|
|
diskLetters := make([]byte, suffLen)
|
|
|
|
var i int
|
|
|
|
for i = 0; i < suffLen && index >= 0; i++ {
|
|
letter := byte('a' + (index % base))
|
|
diskLetters[i] = letter
|
|
index = index/base - 1
|
|
}
|
|
|
|
if index >= 0 {
|
|
return "", fmt.Errorf("Index not supported")
|
|
}
|
|
|
|
diskName := prefix + ReverseString(string(diskLetters[:i]))
|
|
return diskName, nil
|
|
}
|
|
|
|
const maxSCSIDevices = 65535
|
|
|
|
// GetSCSIIdLun gets the SCSI id and lun, based on the index of the drive being inserted.
|
|
// qemu code suggests that scsi-id can take values from 0 to 255 inclusive, while lun can
|
|
// take values from 0 to 16383 inclusive. But lun values over 255 do not seem to follow
|
|
// consistent SCSI addressing. Hence we limit to 255.
|
|
func GetSCSIIdLun(index int) (int, int, error) {
|
|
if index < 0 {
|
|
return -1, -1, fmt.Errorf("Index cannot be negative")
|
|
}
|
|
|
|
if index > maxSCSIDevices {
|
|
return -1, -1, fmt.Errorf("Index cannot be greater than %d, maximum of %d devices are supported", maxSCSIDevices, maxSCSIDevices)
|
|
}
|
|
|
|
return index / 256, index % 256, nil
|
|
}
|
|
|
|
// GetSCSIAddress gets scsiID and lun from index, and combined them into a scsi ID
|
|
func GetSCSIAddress(index int) (string, error) {
|
|
scsiID, lun, err := GetSCSIIdLun(index)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return fmt.Sprintf("%d:%d", scsiID, lun), nil
|
|
}
|
|
|
|
// MakeNameID is generic function for creating a named-id for passing on the hypervisor commandline
|
|
func MakeNameID(namedType, id string, maxLen int) string {
|
|
nameID := fmt.Sprintf("%s-%s", namedType, id)
|
|
if len(nameID) > maxLen {
|
|
nameID = nameID[:maxLen]
|
|
}
|
|
|
|
return nameID
|
|
}
|
|
|
|
// BuildSocketPath concatenates the provided elements into a path and returns
|
|
// it. If the resulting path is longer than the maximum permitted socket path
|
|
// on Linux, it will return an error.
|
|
func BuildSocketPath(elements ...string) (string, error) {
|
|
result := filepath.Join(elements...)
|
|
|
|
if result == "" {
|
|
return "", errors.New("empty path")
|
|
}
|
|
|
|
l := len(result)
|
|
|
|
if l > MaxSocketPathLen {
|
|
return "", fmt.Errorf("path too long (got %v, max %v): %s", l, MaxSocketPathLen, result)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// SupportsVsocks returns true if vsocks are supported, otherwise false
|
|
func SupportsVsocks() bool {
|
|
if _, err := os.Stat(VSockDevicePath); err != nil {
|
|
return false
|
|
}
|
|
|
|
if _, err := os.Stat(VHostVSockDevicePath); err != nil {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|