From 8cf07b2ad1ed8c6646c48a74e9ecbb2bfeecb322 Mon Sep 17 00:00:00 2001 From: baude Date: Wed, 1 Nov 2017 13:59:11 -0500 Subject: libpod create and run patched version of the same code that went into crio Signed-off-by: baude --- cmd/kpod/spec.go | 490 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 cmd/kpod/spec.go (limited to 'cmd/kpod/spec.go') diff --git a/cmd/kpod/spec.go b/cmd/kpod/spec.go new file mode 100644 index 000000000..4b05005bd --- /dev/null +++ b/cmd/kpod/spec.go @@ -0,0 +1,490 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/projectatomic/libpod/libpod" + ann "github.com/projectatomic/libpod/pkg/annotations" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + "golang.org/x/sys/unix" +) + +// Parses information needed to create a container into an OCI runtime spec +func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) { + spec := config.GetDefaultLinuxSpec() + spec.Process.Cwd = config.workDir + spec.Process.Args = config.command + + spec.Process.Terminal = config.tty + + // User and Group must go together + spec.Process.User.UID = config.user + spec.Process.User.GID = config.group + spec.Process.User.AdditionalGids = config.groupAdd + + spec.Process.Env = config.env + + //TODO + // Need examples of capacity additions so I can load that properly + + spec.Root.Readonly = config.readOnlyRootfs + spec.Hostname = config.hostname + + // BIND MOUNTS + spec.Mounts = append(spec.Mounts, config.GetVolumeMounts()...) + + // TMPFS MOUNTS + spec.Mounts = append(spec.Mounts, config.GetTmpfsMounts()...) + + // RESOURCES - MEMORY + spec.Linux.Sysctl = config.sysctl + + if config.resources.memory != 0 { + spec.Linux.Resources.Memory.Limit = &config.resources.memory + } + if config.resources.memoryReservation != 0 { + spec.Linux.Resources.Memory.Reservation = &config.resources.memoryReservation + } + if config.resources.memorySwap != 0 { + spec.Linux.Resources.Memory.Swap = &config.resources.memorySwap + } + if config.resources.kernelMemory != 0 { + spec.Linux.Resources.Memory.Kernel = &config.resources.kernelMemory + } + if config.resources.memorySwapiness != 0 { + spec.Linux.Resources.Memory.Swappiness = &config.resources.memorySwapiness + } + if config.resources.disableOomKiller { + spec.Linux.Resources.Memory.DisableOOMKiller = &config.resources.disableOomKiller + } + + // RESOURCES - CPU + + if config.resources.cpuShares != 0 { + spec.Linux.Resources.CPU.Shares = &config.resources.cpuShares + } + if config.resources.cpuQuota != 0 { + spec.Linux.Resources.CPU.Quota = &config.resources.cpuQuota + } + if config.resources.cpuPeriod != 0 { + spec.Linux.Resources.CPU.Period = &config.resources.cpuPeriod + } + if config.resources.cpuRtRuntime != 0 { + spec.Linux.Resources.CPU.RealtimeRuntime = &config.resources.cpuRtRuntime + } + if config.resources.cpuRtPeriod != 0 { + spec.Linux.Resources.CPU.RealtimePeriod = &config.resources.cpuRtPeriod + } + if config.resources.cpus != "" { + spec.Linux.Resources.CPU.Cpus = config.resources.cpus + } + if config.resources.cpusetMems != "" { + spec.Linux.Resources.CPU.Mems = config.resources.cpusetMems + } + + // RESOURCES - PIDS + if config.resources.pidsLimit != 0 { + spec.Linux.Resources.Pids.Limit = config.resources.pidsLimit + } + + /* + Capabilities: &spec.LinuxCapabilities{ + // Rlimits []PosixRlimit // Where does this come from + // Type string + // Hard uint64 + // Limit uint64 + // NoNewPrivileges bool // No user input for this + // ApparmorProfile string // No user input for this + OOMScoreAdj: &config.resources.oomScoreAdj, + // Selinuxlabel + }, + Hooks: &spec.Hooks{}, + //Annotations + Resources: &spec.LinuxResources{ + Devices: config.GetDefaultDevices(), + BlockIO: &blkio, + //HugepageLimits: + Network: &spec.LinuxNetwork{ + // ClassID *uint32 + // Priorites []LinuxInterfacePriority + }, + }, + //CgroupsPath: + //Namespaces: []LinuxNamespace + //Devices + Seccomp: &spec.LinuxSeccomp{ + // DefaultAction: + // Architectures + // Syscalls: + }, + // RootfsPropagation + // MaskedPaths + // ReadonlyPaths: + // MountLabel + // IntelRdt + }, + } + */ + return &spec, nil +} + +func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) { + bio := spec.LinuxBlockIO{} + bio.Weight = &c.resources.blkioWeight + if len(c.resources.blkioDevice) > 0 { + var lwds []spec.LinuxWeightDevice + for _, i := range c.resources.blkioDevice { + wd, err := validateweightDevice(i) + if err != nil { + return bio, errors.Wrapf(err, "invalid values for blkio-weight-device") + } + wdStat := getStatFromPath(wd.path) + lwd := spec.LinuxWeightDevice{ + Weight: &wd.weight, + } + lwd.Major = int64(unix.Major(wdStat.Rdev)) + lwd.Minor = int64(unix.Minor(wdStat.Rdev)) + lwds = append(lwds, lwd) + } + } + if len(c.resources.deviceReadBps) > 0 { + readBps, err := makeThrottleArray(c.resources.deviceReadBps) + if err != nil { + return bio, err + } + bio.ThrottleReadBpsDevice = readBps + } + if len(c.resources.deviceWriteBps) > 0 { + writeBpds, err := makeThrottleArray(c.resources.deviceWriteBps) + if err != nil { + return bio, err + } + bio.ThrottleWriteBpsDevice = writeBpds + } + if len(c.resources.deviceReadIops) > 0 { + readIops, err := makeThrottleArray(c.resources.deviceReadIops) + if err != nil { + return bio, err + } + bio.ThrottleReadIOPSDevice = readIops + } + if len(c.resources.deviceWriteIops) > 0 { + writeIops, err := makeThrottleArray(c.resources.deviceWriteIops) + if err != nil { + return bio, err + } + bio.ThrottleWriteIOPSDevice = writeIops + } + + return bio, nil +} + +func (c *createConfig) GetDefaultMounts() []spec.Mount { + // Default to 64K default per man page + shmSize := "65536k" + if c.resources.shmSize != "" { + shmSize = c.resources.shmSize + } + return []spec.Mount{ + { + Destination: "/proc", + Type: "proc", + Source: "proc", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/dev", + Type: "tmpfs", + Source: "tmpfs", + Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, + }, + { + Destination: "/dev/pts", + Type: "devpts", + Source: "devpts", + Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, + }, + { + Destination: "/sys", + Type: "sysfs", + Source: "sysfs", + Options: []string{"nosuid", "noexec", "nodev", "ro"}, + }, + { + Destination: "/sys/fs/cgroup", + Type: "cgroup", + Source: "cgroup", + Options: []string{"ro", "nosuid", "noexec", "nodev"}, + }, + { + Destination: "/dev/mqueue", + Type: "mqueue", + Source: "mqueue", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/dev/shm", + Type: "tmpfs", + Source: "shm", + Options: []string{"nosuid", "noexec", "nodev", "mode=1777", fmt.Sprintf("size=%s", shmSize)}, + }, + } +} + +func iPtr(i int64) *int64 { return &i } + +func (c *createConfig) GetDefaultDevices() []spec.LinuxDeviceCgroup { + return []spec.LinuxDeviceCgroup{ + { + Allow: false, + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(1), + Minor: iPtr(5), + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(1), + Minor: iPtr(3), + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(1), + Minor: iPtr(9), + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(1), + Minor: iPtr(8), + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(5), + Minor: iPtr(0), + Access: "rwm", + }, + { + Allow: true, + Type: "c", + Major: iPtr(5), + Minor: iPtr(1), + Access: "rwm", + }, + { + Allow: false, + Type: "c", + Major: iPtr(10), + Minor: iPtr(229), + Access: "rwm", + }, + } +} + +func defaultCapabilities() []string { + return []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + } +} + +func (c *createConfig) GetDefaultLinuxSpec() spec.Spec { + s := spec.Spec{ + Version: spec.Version, + Root: &spec.Root{}, + } + s.Annotations = c.GetAnnotations() + s.Mounts = c.GetDefaultMounts() + s.Process = &spec.Process{ + Capabilities: &spec.LinuxCapabilities{ + Bounding: defaultCapabilities(), + Permitted: defaultCapabilities(), + Inheritable: defaultCapabilities(), + Effective: defaultCapabilities(), + }, + } + s.Linux = &spec.Linux{ + MaskedPaths: []string{ + "/proc/kcore", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + }, + ReadonlyPaths: []string{ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger", + }, + Namespaces: []spec.LinuxNamespace{ + {Type: "mount"}, + {Type: "network"}, + {Type: "uts"}, + {Type: "pid"}, + {Type: "ipc"}, + }, + Devices: []spec.LinuxDevice{}, + Resources: &spec.LinuxResources{ + Devices: c.GetDefaultDevices(), + }, + } + + return s +} + +// GetAnnotations returns the all the annotations for the container +func (c *createConfig) GetAnnotations() map[string]string { + a := getDefaultAnnotations() + // TODO + // Which annotations do we want added by default + if c.tty { + a["io.kubernetes.cri-o.TTY"] = "true" + } + return a +} + +func getDefaultAnnotations() map[string]string { + var annotations map[string]string + annotations = make(map[string]string) + annotations[ann.Annotations] = "" + annotations[ann.ContainerID] = "" + annotations[ann.ContainerName] = "" + annotations[ann.ContainerType] = "" + annotations[ann.Created] = "" + annotations[ann.HostName] = "" + annotations[ann.IP] = "" + annotations[ann.Image] = "" + annotations[ann.ImageName] = "" + annotations[ann.ImageRef] = "" + annotations[ann.KubeName] = "" + annotations[ann.Labels] = "" + annotations[ann.LogPath] = "" + annotations[ann.Metadata] = "" + annotations[ann.Name] = "" + annotations[ann.PrivilegedRuntime] = "" + annotations[ann.ResolvPath] = "" + annotations[ann.HostnamePath] = "" + annotations[ann.SandboxID] = "" + annotations[ann.SandboxName] = "" + annotations[ann.ShmPath] = "" + annotations[ann.MountPoint] = "" + annotations[ann.TrustedSandbox] = "" + annotations[ann.TTY] = "false" + annotations[ann.Stdin] = "" + annotations[ann.StdinOnce] = "" + annotations[ann.Volumes] = "" + + return annotations +} + +//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs +func (c *createConfig) GetVolumeMounts() []spec.Mount { + var m []spec.Mount + var options []string + for _, i := range c.volumes { + // We need to handle SELinux options better here, specifically :Z + spliti := strings.Split(i, ":") + if len(spliti) > 2 { + options = strings.Split(spliti[2], ",") + } + // always add rbind bc mount ignores the bind filesystem when mounting + options = append(options, "rbind") + m = append(m, spec.Mount{ + Destination: spliti[1], + Type: string(TypeBind), + Source: spliti[0], + Options: options, + }) + } + return m +} + +//GetTmpfsMounts takes user provided input for tmpfs mounts and creates Mount structs +func (c *createConfig) GetTmpfsMounts() []spec.Mount { + var m []spec.Mount + for _, i := range c.tmpfs { + // Default options if nothing passed + options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"} + spliti := strings.Split(i, ":") + destPath := spliti[0] + if len(spliti) > 1 { + options = strings.Split(spliti[1], ",") + } + m = append(m, spec.Mount{ + Destination: destPath, + Type: string(TypeTmpfs), + Options: options, + Source: string(TypeTmpfs), + }) + } + return m +} + +func (c *createConfig) GetContainerCreateOptions(cli *cli.Context) ([]libpod.CtrCreateOption, error) { + var options []libpod.CtrCreateOption + + // Uncomment after talking to mheon about unimplemented funcs + // options = append(options, libpod.WithLabels(c.labels)) + + if c.interactive { + options = append(options, libpod.WithStdin()) + } + if c.name != "" { + logrus.Debug("appending name %s", c.name) + options = append(options, libpod.WithName(c.name)) + } + + return options, nil +} + +func getStatFromPath(path string) unix.Stat_t { + s := unix.Stat_t{} + _ = unix.Stat(path, &s) + return s +} + +func makeThrottleArray(throttleInput []string) ([]spec.LinuxThrottleDevice, error) { + var ltds []spec.LinuxThrottleDevice + for _, i := range throttleInput { + t, err := validateBpsDevice(i) + if err != nil { + return []spec.LinuxThrottleDevice{}, err + } + ltd := spec.LinuxThrottleDevice{} + ltd.Rate = t.rate + ltdStat := getStatFromPath(t.path) + ltd.Major = int64(unix.Major(ltdStat.Rdev)) + ltd.Minor = int64(unix.Major(ltdStat.Rdev)) + ltds = append(ltds, ltd) + } + return ltds, nil +} -- cgit v1.2.3-54-g00ecf