Example #1
0
// setApp overrides the app's fields if any of them are specified in the
// container's spec.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions) error {
	// Override the exec.

	if len(c.Command) > 0 {
		app.Exec = c.Command
	}
	if len(c.Args) > 0 {
		app.Exec = append(app.Exec, c.Args...)
	}

	// TODO(yifan): Use non-root user in the future, see:
	// https://github.com/coreos/rkt/issues/820
	app.User, app.Group = "0", "0"

	// Override the working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Notes that we don't create Mounts section in the pod manifest here,
	// as Mounts will be automatically generated by rkt.
	mergeMounts(app, opts.Mounts)
	mergeEnv(app, opts.Envs)
	mergePortMappings(app, opts.PortMappings)

	// Override isolators.
	return setIsolators(app, c)
}
Example #2
0
// setApp merges the container spec with the image's manifest.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions, ctx *api.SecurityContext, podCtx *api.PodSecurityContext) error {
	// Override the exec.
	if len(c.Command) > 0 {
		app.Exec = c.Command
	}
	if len(c.Args) > 0 {
		app.Exec = append(app.Exec, c.Args...)
	}

	// Set UID and GIDs.
	if err := verifyNonRoot(app, ctx); err != nil {
		return err
	}
	if ctx != nil && ctx.RunAsUser != nil {
		app.User = strconv.Itoa(int(*ctx.RunAsUser))
	}
	setSupplementaryGIDs(app, podCtx)

	// Set working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Notes that we don't create Mounts section in the pod manifest here,
	// as Mounts will be automatically generated by rkt.
	mergeMounts(app, opts.Mounts)
	mergeEnv(app, opts.Envs)
	mergePortMappings(app, opts.PortMappings)

	return setIsolators(app, c, ctx)
}
Example #3
0
// setApp merges the container spec with the image's manifest.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions, ctx *api.SecurityContext, podCtx *api.PodSecurityContext) error {
	// TODO(yifan): If ENTRYPOINT and CMD are both specified in the image,
	// we cannot override just one of these at this point as they are already mixed.
	command, args := kubecontainer.ExpandContainerCommandAndArgs(c, opts.Envs)
	exec := append(command, args...)
	if len(exec) > 0 {
		app.Exec = exec
	}

	// Set UID and GIDs.
	if err := verifyNonRoot(app, ctx); err != nil {
		return err
	}
	if ctx != nil && ctx.RunAsUser != nil {
		app.User = strconv.Itoa(int(*ctx.RunAsUser))
	}
	setSupplementaryGIDs(app, podCtx)

	// Set working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Notes that we don't create Mounts section in the pod manifest here,
	// as Mounts will be automatically generated by rkt.
	mergeMounts(app, opts.Mounts)
	mergeEnv(app, opts.Envs)
	mergePortMappings(app, opts.PortMappings)

	return setIsolators(app, c, ctx)
}
Example #4
0
func setSupplementaryGIDs(app *appctypes.App, podCtx *api.PodSecurityContext) {
	if podCtx != nil {
		app.SupplementaryGIDs = app.SupplementaryGIDs[:0]
		for _, v := range podCtx.SupplementalGroups {
			app.SupplementaryGIDs = append(app.SupplementaryGIDs, int(v))
		}
		if podCtx.FSGroup != nil {
			app.SupplementaryGIDs = append(app.SupplementaryGIDs, int(*podCtx.FSGroup))
		}
	}
}
Example #5
0
// mergeEnv merges the optEnv with the image's environments.
// The environments defined in the image will be overridden by
// the ones with the same name in optEnv.
func mergeEnv(app *appctypes.App, optEnv []kubecontainer.EnvVar) {
	envMap := make(map[string]string)
	for _, e := range app.Environment {
		envMap[e.Name] = e.Value
	}
	for _, e := range optEnv {
		envMap[e.Name] = e.Value
	}
	app.Environment = nil
	for name, value := range envMap {
		app.Environment = append(app.Environment, appctypes.EnvironmentVariable{
			Name:  name,
			Value: value,
		})
	}
}
Example #6
0
// mergeIsolators replaces the app.Isolators with isolators.
func mergeIsolators(app *appctypes.App, isolators []appctypes.Isolator) {
	for _, is := range isolators {
		found := false
		for j, js := range app.Isolators {
			if is.Name.Equals(js.Name) {
				switch is.Name {
				case appctypes.LinuxCapabilitiesRetainSetName:
					// TODO(yifan): More fine grain merge for capability set instead of override.
					fallthrough
				case appctypes.LinuxCapabilitiesRevokeSetName:
					fallthrough
				case appctypes.ResourceCPUName:
					fallthrough
				case appctypes.ResourceMemoryName:
					app.Isolators[j] = is
				default:
					panic(fmt.Sprintf("unexpected isolator name: %v", is.Name))
				}
				found = true
				break
			}
		}
		if !found {
			app.Isolators = append(app.Isolators, is)
		}
	}
}
Example #7
0
// mergePortMappings merges the optPortMappings with the image's port mappings.
// The port mappings defined in the image will be overridden by the ones
// with the same name in optPortMappings.
func mergePortMappings(app *appctypes.App, optPortMappings []kubecontainer.PortMapping) {
	portMap := make(map[appctypes.ACName]appctypes.Port)
	for _, p := range app.Ports {
		portMap[p.Name] = p
	}
	for _, p := range optPortMappings {
		pName := convertToACName(p.Name)
		portMap[pName] = appctypes.Port{
			Name:     pName,
			Protocol: string(p.Protocol),
			Port:     uint(p.ContainerPort),
		}
	}
	app.Ports = nil
	for _, port := range portMap {
		app.Ports = append(app.Ports, port)
	}
}
Example #8
0
// mergeMounts merges the optMounts with the image's mount points.
// The mount points defined in the image will be overridden by the ones
// with the same name in optMounts.
func mergeMounts(app *appctypes.App, optMounts []kubecontainer.Mount) {
	mountMap := make(map[appctypes.ACName]appctypes.MountPoint)
	for _, m := range app.MountPoints {
		mountMap[m.Name] = m
	}
	for _, m := range optMounts {
		mpName := convertToACName(m.Name)
		mountMap[mpName] = appctypes.MountPoint{
			Name:     mpName,
			Path:     m.ContainerPath,
			ReadOnly: m.ReadOnly,
		}
	}
	app.MountPoints = nil
	for _, mount := range mountMap {
		app.MountPoints = append(app.MountPoints, mount)
	}
}
Example #9
0
func (this *oci2rkt) genImageManifest() {

	// 1. Assemble "acKind" field
	this.imageManifest.ACKind = "ImageManifest"

	// 2. Assemble "acVersion" field
	this.imageManifest.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	this.imageManifest.Name = "oci"

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = this.linuxSpec.Version
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = this.linuxSpec.Platform.OS
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = this.linuxSpec.Platform.Arch
	this.imageManifest.Labels = append(this.imageManifest.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	//fmt.Printf("this.linuxSpec.Process.Args=%v\n", this.linuxSpec.Process.Args)
	app.Exec = this.linuxSpec.Process.Args
	// 5.2 "user"
	app.User = fmt.Sprintf("%d", this.linuxSpec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", this.linuxSpec.Process.User.GID)

	this.imageManifest.App = app
}
Example #10
0
// setApp overrides the app's fields if any of them are specified in the
// container's spec.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions) error {
	// Override the exec.

	if len(c.Command) > 0 {
		app.Exec = c.Command
	}
	if len(c.Args) > 0 {
		app.Exec = append(app.Exec, c.Args...)
	}

	// TODO(yifan): Use non-root user in the future, see:
	// https://github.com/coreos/rkt/issues/820
	app.User, app.Group = "0", "0"

	// Override the working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Merge the environment. Override the image with the ones defined in the spec if necessary.
	for _, env := range opts.Envs {
		if ix := findEnvInList(app.Environment, env); ix >= 0 {
			app.Environment[ix].Value = env.Value
			continue
		}
		app.Environment = append(app.Environment, appctypes.EnvironmentVariable{
			Name:  env.Name,
			Value: env.Value,
		})
	}

	// Override the mount points.
	if len(opts.Mounts) > 0 {
		app.MountPoints = []appctypes.MountPoint{}
	}
	for _, m := range opts.Mounts {
		mountPointName, err := appctypes.NewACName(m.Name)
		if err != nil {
			return err
		}
		app.MountPoints = append(app.MountPoints, appctypes.MountPoint{
			Name:     *mountPointName,
			Path:     m.ContainerPath,
			ReadOnly: m.ReadOnly,
		})
	}

	// Override the ports.
	if len(opts.PortMappings) > 0 {
		app.Ports = []appctypes.Port{}
	}
	for _, p := range opts.PortMappings {
		name, err := appctypes.SanitizeACName(p.Name)
		if err != nil {
			return err
		}
		portName := appctypes.MustACName(name)
		app.Ports = append(app.Ports, appctypes.Port{
			Name:     *portName,
			Protocol: string(p.Protocol),
			Port:     uint(p.ContainerPort),
		})
	}

	// Override isolators.
	return setIsolators(app, c)
}
Example #11
0
File: manifest.go Project: nak3/rkt
func patchManifest(im *schema.ImageManifest) error {

	if patchName != "" {
		name, err := types.NewACIdentifier(patchName)
		if err != nil {
			return err
		}
		im.Name = *name
	}

	var app *types.App = im.App
	if patchExec != "" {
		if app == nil {
			// if the original manifest was missing an app and
			// patchExec is set let's assume the user is trying to
			// inject one...
			im.App = &types.App{}
			app = im.App
		}
		app.Exec = strings.Split(patchExec, " ")
	}

	if patchUser != "" ||
		patchGroup != "" ||
		patchSupplementaryGIDs != "" ||
		patchCaps != "" ||
		patchRevokeCaps != "" ||
		patchMounts != "" ||
		patchPorts != "" ||
		patchIsolators != "" {
		// ...but if we still don't have an app and the user is trying
		// to patch one of its other parameters, it's an error
		if app == nil {
			return fmt.Errorf("no app in the supplied manifest and no exec command provided")
		}
	}

	if patchUser != "" {
		app.User = patchUser
	}

	if patchGroup != "" {
		app.Group = patchGroup
	}

	if patchSupplementaryGIDs != "" {
		app.SupplementaryGIDs = []int{}
		gids := strings.Split(patchSupplementaryGIDs, ",")
		for _, g := range gids {
			gid, err := strconv.Atoi(g)
			if err != nil {
				return fmt.Errorf("invalid supplementary group %q: %v", g, err)
			}
			app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid)
		}
	}

	if patchCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists (os/linux/capabilities-retain-set)")
		}

		// Instantiate a Isolator with the content specified by the --capability
		// parameter.
		caps, err := types.NewLinuxCapabilitiesRetainSet(strings.Split(patchCaps, ",")...)
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err)
		}
		isolator, err = caps.AsIsolator()
		if err != nil {
			return err
		}
		app.Isolators = append(app.Isolators, *isolator)
	}
	if patchRevokeCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRevokeSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists (os/linux/capabilities-remove-set)")
		}

		// Instantiate a Isolator with the content specified by the --revoke-capability
		// parameter.
		caps, err := types.NewLinuxCapabilitiesRevokeSet(strings.Split(patchRevokeCaps, ",")...)
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchRevokeCaps, err)
		}
		isolator, err = caps.AsIsolator()
		if err != nil {
			return err
		}
		app.Isolators = append(app.Isolators, *isolator)
	}

	if patchMounts != "" {
		mounts := strings.Split(patchMounts, ":")
		for _, m := range mounts {
			mountPoint, err := types.MountPointFromString(m)
			if err != nil {
				return fmt.Errorf("cannot parse mount point %q: %v", m, err)
			}
			app.MountPoints = append(app.MountPoints, *mountPoint)
		}
	}

	if patchPorts != "" {
		ports := strings.Split(patchPorts, ":")
		for _, p := range ports {
			port, err := types.PortFromString(p)
			if err != nil {
				return fmt.Errorf("cannot parse port %q: %v", p, err)
			}
			app.Ports = append(app.Ports, *port)
		}
	}

	// Parse seccomp args and override existing seccomp isolators
	if patchSeccompMode != "" {
		seccompIsolator, err := parseSeccompArgs(patchSeccompMode, patchSeccompSet)
		if err != nil {
			return err
		}
		seccompReps := []types.ACIdentifier{types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName}
		app.Isolators.ReplaceIsolatorsByName(*seccompIsolator, seccompReps)
	} else if patchSeccompSet != "" {
		return fmt.Errorf("--seccomp-set specified without --seccomp-mode")
	}

	if patchIsolators != "" {
		isolators := strings.Split(patchIsolators, ":")
		for _, is := range isolators {
			name, isolatorStr, err := isolatorStrFromString(is)
			if err != nil {
				return fmt.Errorf("cannot parse isolator %q: %v", is, err)
			}

			_, ok := types.ResourceIsolatorNames[name]

			switch name {
			case types.LinuxNoNewPrivilegesName:
				ok = true
				kv := strings.Split(is, ",")
				if len(kv) != 2 {
					return fmt.Errorf("isolator %s: invalid format", name)
				}
				isolatorStr = fmt.Sprintf(`{ "name": "%s", "value": %s }`, name, kv[1])
			case types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName:
				ok = false
			}

			if !ok {
				return fmt.Errorf("isolator %s is not supported for patching", name)
			}

			isolator := &types.Isolator{}
			if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil {
				return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err)
			}
			app.Isolators = append(app.Isolators, *isolator)
		}
	}
	return nil
}
Example #12
0
func genManifest(path string) *schema.ImageManifest {
	// Get runtime.json and config.json
	runtimePath := path + "/runtime.json"
	configPath := path + "/config.json"

	runtime, err := ioutil.ReadFile(runtimePath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file runtime.json failed: %v", err)
		}
		return nil
	}

	config, err := ioutil.ReadFile(configPath)
	if err != nil {
		if debugEnabled {
			log.Printf("Open file config.json failed: %v", err)
		}
		return nil
	}

	var spec specs.LinuxSpec
	err = json.Unmarshal(config, &spec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal config.json failed: %v", err)
		}
		return nil
	}

	var runSpec specs.LinuxRuntimeSpec
	err = json.Unmarshal(runtime, &runSpec)
	if err != nil {
		if debugEnabled {
			log.Printf("Unmarshal runtime.json failed: %v", err)
		}
		return nil
	}
	// Begin to convert runtime.json/config.json to manifest
	m := new(schema.ImageManifest)

	// 1. Assemble "acKind" field
	m.ACKind = schema.ImageManifestKind

	// 2. Assemble "acVersion" field
	m.ACVersion = schema.AppContainerVersion

	// 3. Assemble "name" field
	m.Name = types.ACIdentifier(manifestName)

	// 4. Assemble "labels" field
	// 4.1 "version"
	label := new(types.Label)
	label.Name = types.ACIdentifier("version")
	label.Value = spec.Version
	m.Labels = append(m.Labels, *label)
	// 4.2 "os"
	label = new(types.Label)
	label.Name = types.ACIdentifier("os")
	label.Value = spec.Platform.OS
	m.Labels = append(m.Labels, *label)
	// 4.3 "arch"
	label = new(types.Label)
	label.Name = types.ACIdentifier("arch")
	label.Value = spec.Platform.Arch
	m.Labels = append(m.Labels, *label)

	// 5. Assemble "app" field
	app := new(types.App)
	// 5.1 "exec"
	app.Exec = spec.Process.Args

	prefixDir := ""
	//var exeStr string
	if app.Exec == nil {
		app.Exec = append(app.Exec, "/bin/sh")
	} else {
		if !filepath.IsAbs(app.Exec[0]) {
			if spec.Process.Cwd == "" {
				prefixDir = "/"
			} else {
				prefixDir = spec.Process.Cwd
			}
		}
		app.Exec[0] = prefixDir + app.Exec[0]
	}

	// 5.2 "user"
	app.User = fmt.Sprintf("%d", spec.Process.User.UID)
	// 5.3 "group"
	app.Group = fmt.Sprintf("%d", spec.Process.User.GID)
	// 5.4 "eventHandlers"
	event := new(types.EventHandler)
	event.Name = "pre-start"
	for index := range runSpec.Hooks.Prestart {
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Prestart[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	event = new(types.EventHandler)
	event.Name = "post-stop"
	for index := range runSpec.Hooks.Poststop {
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Path)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Args...)
		event.Exec = append(event.Exec, runSpec.Hooks.Poststop[index].Env...)
	}
	if len(event.Exec) == 0 {
		event.Exec = append(event.Exec, "/bin/echo")
		event.Exec = append(event.Exec, "-n")
	}
	app.EventHandlers = append(app.EventHandlers, *event)
	// 5.5 "workingDirectory"
	app.WorkingDirectory = spec.Process.Cwd
	// 5.6 "environment"
	env := new(types.EnvironmentVariable)
	for index := range spec.Process.Env {
		s := strings.Split(spec.Process.Env[index], "=")
		env.Name = s[0]
		env.Value = s[1]
		app.Environment = append(app.Environment, *env)
	}

	// 5.7 "mountPoints"
	for index := range spec.Mounts {
		mount := new(types.MountPoint)
		mount.Name = types.ACName(spec.Mounts[index].Name)
		mount.Path = spec.Mounts[index].Path
		mount.ReadOnly = false
		app.MountPoints = append(app.MountPoints, *mount)
	}

	// 5.8 "ports"

	// 5.9 "isolators"
	if runSpec.Linux.Resources != nil {
		if runSpec.Linux.Resources.CPU.Quota != 0 {
			cpuLimt := new(ResourceCPU)
			cpuLimt.Limit = fmt.Sprintf("%dm", runSpec.Linux.Resources.CPU.Quota)
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/cpu")
			bytes, _ := json.Marshal(cpuLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
		if runSpec.Linux.Resources.Memory.Limit != 0 {
			memLimt := new(ResourceMem)
			memLimt.Limit = fmt.Sprintf("%dG", runSpec.Linux.Resources.Memory.Limit/(1024*1024*1024))
			isolator := new(types.Isolator)
			isolator.Name = types.ACIdentifier("resource/memory")
			bytes, _ := json.Marshal(memLimt)

			valueRaw := json.RawMessage(bytes)
			isolator.ValueRaw = &valueRaw

			app.Isolators = append(app.Isolators, *isolator)
		}
	}

	if len(spec.Linux.Capabilities) != 0 {
		isolatorCapSet := new(IsolatorCapSet)
		isolatorCapSet.Sets = append(isolatorCapSet.Sets, spec.Linux.Capabilities...)

		isolator := new(types.Isolator)
		isolator.Name = types.ACIdentifier(types.LinuxCapabilitiesRetainSetName)
		bytes, _ := json.Marshal(isolatorCapSet)

		valueRaw := json.RawMessage(bytes)
		isolator.ValueRaw = &valueRaw

		app.Isolators = append(app.Isolators, *isolator)
	}

	// 6. "annotations"

	// 7. "dependencies"

	// 8. "pathWhitelist"

	m.App = app

	return m
}
Example #13
0
func patchManifest(im *schema.ImageManifest) error {

	if patchName != "" {
		name, err := types.NewACIdentifier(patchName)
		if err != nil {
			return err
		}
		im.Name = *name
	}

	var app *types.App = im.App
	if patchExec != "" {
		if app == nil {
			// if the original manifest was missing an app and
			// patchExec is set let's assume the user is trying to
			// inject one...
			im.App = &types.App{}
			app = im.App
		}
		app.Exec = strings.Split(patchExec, " ")
	}

	if patchUser != "" ||
		patchGroup != "" ||
		patchSupplementaryGIDs != "" ||
		patchCaps != "" ||
		patchRevokeCaps != "" ||
		patchMounts != "" ||
		patchPorts != "" ||
		patchIsolators != "" {
		// ...but if we still don't have an app and the user is trying
		// to patch one of its other parameters, it's an error
		if app == nil {
			return fmt.Errorf("no app in the supplied manifest and no exec command provided")
		}
	}

	if patchUser != "" {
		app.User = patchUser
	}

	if patchGroup != "" {
		app.Group = patchGroup
	}

	if patchSupplementaryGIDs != "" {
		app.SupplementaryGIDs = []int{}
		gids := strings.Split(patchSupplementaryGIDs, ",")
		for _, g := range gids {
			gid, err := strconv.Atoi(g)
			if err != nil {
				return fmt.Errorf("invalid supplementary group %q: %v", g, err)
			}
			app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid)
		}
	}

	if patchCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists (os/linux/capabilities-retain-set)")
		}

		// Instantiate a Isolator with the content specified by the --capability
		// parameter.
		caps, err := types.NewLinuxCapabilitiesRetainSet(strings.Split(patchCaps, ",")...)
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err)
		}
		app.Isolators = append(app.Isolators, caps.AsIsolator())
	}
	if patchRevokeCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRevokeSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists (os/linux/capabilities-remove-set)")
		}

		// Instantiate a Isolator with the content specified by the --revoke-capability
		// parameter.
		caps, err := types.NewLinuxCapabilitiesRevokeSet(strings.Split(patchRevokeCaps, ",")...)
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchRevokeCaps, err)
		}
		app.Isolators = append(app.Isolators, caps.AsIsolator())
	}

	if patchMounts != "" {
		mounts := strings.Split(patchMounts, ":")
		for _, m := range mounts {
			mountPoint, err := types.MountPointFromString(m)
			if err != nil {
				return fmt.Errorf("cannot parse mount point %q: %v", m, err)
			}
			app.MountPoints = append(app.MountPoints, *mountPoint)
		}
	}

	if patchPorts != "" {
		ports := strings.Split(patchPorts, ":")
		for _, p := range ports {
			port, err := types.PortFromString(p)
			if err != nil {
				return fmt.Errorf("cannot parse port %q: %v", p, err)
			}
			app.Ports = append(app.Ports, *port)
		}
	}

	if patchIsolators != "" {
		isolators := strings.Split(patchIsolators, ":")
		for _, is := range isolators {
			name, isolatorStr, err := isolatorStrFromString(is)
			if err != nil {
				return fmt.Errorf("cannot parse isolator %q: %v", is, err)
			}

			if _, ok := types.ResourceIsolatorNames[name]; !ok {
				return fmt.Errorf("isolator %s is not supported for patching", name)
			}

			isolator := &types.Isolator{}
			if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil {
				return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err)
			}
			app.Isolators = append(app.Isolators, *isolator)
		}
	}
	return nil
}
Example #14
0
func patchManifest(im *schema.ImageManifest) error {

	if patchName != "" {
		name, err := types.NewACIdentifier(patchName)
		if err != nil {
			return err
		}
		im.Name = *name
	}

	var app *types.App = im.App
	if patchExec != "" {
		if app == nil {
			// if the original manifest was missing an app and
			// patchExec is set let's assume the user is trying to
			// inject one...
			im.App = &types.App{}
			app = im.App
		}
		app.Exec = strings.Split(patchExec, " ")
	}

	if patchUser != "" || patchGroup != "" || patchSupplementaryGIDs != "" || patchCaps != "" || patchMounts != "" || patchPorts != "" || patchIsolators != "" {
		// ...but if we still don't have an app and the user is trying
		// to patch one of its other parameters, it's an error
		if app == nil {
			return fmt.Errorf("no app in the supplied manifest and no exec command provided")
		}
	}

	if patchUser != "" {
		app.User = patchUser
	}

	if patchGroup != "" {
		app.Group = patchGroup
	}

	if patchSupplementaryGIDs != "" {
		app.SupplementaryGIDs = []int{}
		gids := strings.Split(patchSupplementaryGIDs, ",")
		for _, g := range gids {
			gid, err := strconv.Atoi(g)
			if err != nil {
				return fmt.Errorf("invalid supplementary group %q: %v", g, err)
			}
			app.SupplementaryGIDs = append(app.SupplementaryGIDs, gid)
		}
	}

	if patchCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists")
		}

		// Instantiate a Isolator with the content specified by the --capability
		// parameter.

		// TODO: Instead of creating a JSON and then unmarshalling it, the isolator
		// should be instantiated directory. But it requires a constructor, see:
		// https://github.com/appc/spec/issues/268
		capsList := strings.Split(patchCaps, ",")
		caps := fmt.Sprintf(`"set": ["%s"]`, strings.Join(capsList, `", "`))
		isolatorStr := getIsolatorStr(types.LinuxCapabilitiesRetainSetName, caps)
		isolator = &types.Isolator{}
		err := isolator.UnmarshalJSON([]byte(isolatorStr))
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err)
		}
		app.Isolators = append(app.Isolators, *isolator)
	}

	if patchMounts != "" {
		mounts := strings.Split(patchMounts, ":")
		for _, m := range mounts {
			mountPoint, err := types.MountPointFromString(m)
			if err != nil {
				return fmt.Errorf("cannot parse mount point %q: %v", m, err)
			}
			app.MountPoints = append(app.MountPoints, *mountPoint)
		}
	}

	if patchPorts != "" {
		ports := strings.Split(patchPorts, ":")
		for _, p := range ports {
			port, err := types.PortFromString(p)
			if err != nil {
				return fmt.Errorf("cannot parse port %q: %v", p, err)
			}
			app.Ports = append(app.Ports, *port)
		}
	}

	if patchIsolators != "" {
		isolators := strings.Split(patchIsolators, ":")
		for _, is := range isolators {
			name, isolatorStr, err := isolatorStrFromString(is)
			if err != nil {
				return fmt.Errorf("cannot parse isolator %q: %v", is, err)
			}

			if _, ok := types.ResourceIsolatorNames[name]; !ok {
				return fmt.Errorf("isolator %s is not supported for patching", name)
			}

			isolator := &types.Isolator{}
			if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil {
				return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err)
			}
			app.Isolators = append(app.Isolators, *isolator)
		}
	}
	return nil
}
Example #15
0
func patchManifest(im *schema.ImageManifest) error {

	if patchName != "" {
		name, err := types.NewACIdentifier(patchName)
		if err != nil {
			return err
		}
		im.Name = *name
	}

	if patchExec != "" {
		im.App.Exec = strings.Split(patchExec, " ")
	}

	if patchUser != "" {
		im.App.User = patchUser
	}
	if patchGroup != "" {
		im.App.Group = patchGroup
	}

	var app *types.App
	if patchCaps != "" || patchMounts != "" || patchPorts != "" || patchIsolators != "" {
		app = im.App
		if app == nil {
			return fmt.Errorf("no app in the manifest")
		}
	}

	if patchCaps != "" {
		isolator := app.Isolators.GetByName(types.LinuxCapabilitiesRetainSetName)
		if isolator != nil {
			return fmt.Errorf("isolator already exists")
		}

		// Instantiate a Isolator with the content specified by the --capability
		// parameter.

		// TODO: Instead of creating a JSON and then unmarshalling it, the isolator
		// should be instantiated directory. But it requires a constructor, see:
		// https://github.com/appc/spec/issues/268
		capsList := strings.Split(patchCaps, ",")
		caps := fmt.Sprintf(`"set": ["%s"]`, strings.Join(capsList, `", "`))
		isolatorStr := getIsolatorStr(types.LinuxCapabilitiesRetainSetName, caps)
		isolator = &types.Isolator{}
		err := isolator.UnmarshalJSON([]byte(isolatorStr))
		if err != nil {
			return fmt.Errorf("cannot parse capability %q: %v", patchCaps, err)
		}
		app.Isolators = append(app.Isolators, *isolator)
	}

	if patchMounts != "" {
		mounts := strings.Split(patchMounts, ":")
		for _, m := range mounts {
			mountPoint, err := types.MountPointFromString(m)
			if err != nil {
				return fmt.Errorf("cannot parse mount point %q: %v", m, err)
			}
			app.MountPoints = append(app.MountPoints, *mountPoint)
		}
	}

	if patchPorts != "" {
		ports := strings.Split(patchPorts, ":")
		for _, p := range ports {
			port, err := types.PortFromString(p)
			if err != nil {
				return fmt.Errorf("cannot parse port %q: %v", p, err)
			}
			app.Ports = append(app.Ports, *port)
		}
	}

	if patchIsolators != "" {
		isolators := strings.Split(patchIsolators, ":")
		for _, is := range isolators {
			name, isolatorStr, err := isolatorStrFromString(is)
			if err != nil {
				return fmt.Errorf("cannot parse isolator %q: %v", is, err)
			}

			if _, ok := types.ResourceIsolatorNames[name]; !ok {
				return fmt.Errorf("isolator %s is not supported for patching", name)
			}

			isolator := &types.Isolator{}
			if err := isolator.UnmarshalJSON([]byte(isolatorStr)); err != nil {
				return fmt.Errorf("cannot unmarshal isolator %v: %v", isolatorStr, err)
			}
			app.Isolators = append(app.Isolators, *isolator)
		}
	}
	return nil
}
Example #16
0
// setIsolators overrides the isolators of the pod manifest if necessary.
// TODO need an apply config in security context for rkt
func setIsolators(app *appctypes.App, c *api.Container) error {
	hasCapRequests := securitycontext.HasCapabilitiesRequest(c)
	if hasCapRequests || len(c.Resources.Limits) > 0 || len(c.Resources.Requests) > 0 {
		app.Isolators = []appctypes.Isolator{}
	}

	// Retained capabilities/privileged.
	privileged := false
	if c.SecurityContext != nil && c.SecurityContext.Privileged != nil {
		privileged = *c.SecurityContext.Privileged
	}

	var addCaps string
	if privileged {
		addCaps = getAllCapabilities()
	} else {
		if hasCapRequests {
			addCaps = getCapabilities(c.SecurityContext.Capabilities.Add)
		}
	}
	if len(addCaps) > 0 {
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     "os/linux/capabilities-retain-set",
			ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, addCaps)),
		}
		app.Isolators = append(app.Isolators, isolator)
	}

	// Removed capabilities.
	var dropCaps string
	if hasCapRequests {
		dropCaps = getCapabilities(c.SecurityContext.Capabilities.Drop)
	}
	if len(dropCaps) > 0 {
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     "os/linux/capabilities-remove-set",
			ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, dropCaps)),
		}
		app.Isolators = append(app.Isolators, isolator)
	}

	// Resources.
	resources := make(map[api.ResourceName]resource)
	for name, quantity := range c.Resources.Limits {
		resources[name] = resource{limit: quantity.String()}
	}
	for name, quantity := range c.Resources.Requests {
		r, ok := resources[name]
		if !ok {
			r = resource{}
		}
		r.request = quantity.String()
		resources[name] = r
	}
	var acName appctypes.ACName
	for name, res := range resources {
		switch name {
		case api.ResourceCPU:
			acName = "resource/cpu"
		case api.ResourceMemory:
			acName = "resource/memory"
		default:
			return fmt.Errorf("resource type not supported: %v", name)
		}
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     acName,
			ValueRaw: rawRequestLimit(res.request, res.limit),
		}
		app.Isolators = append(app.Isolators, isolator)
	}
	return nil
}
Example #17
0
// setApp overrides the app's fields if any of them are specified in the
// container's spec.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions) error {
	// Override the exec.
	// TOOD(yifan): Revisit this for the overriding rule.
	if len(c.Command) > 0 || len(c.Args) > 0 {
		app.Exec = append(c.Command, c.Args...)
	}

	// TODO(yifan): Use non-root user in the future, see:
	// https://github.com/coreos/rkt/issues/820
	app.User, app.Group = "0", "0"

	// Override the working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Override the environment.
	if len(opts.Envs) > 0 {
		app.Environment = []appctypes.EnvironmentVariable{}
	}
	for _, env := range c.Env {
		app.Environment = append(app.Environment, appctypes.EnvironmentVariable{
			Name:  env.Name,
			Value: env.Value,
		})
	}

	// Override the mount points.
	if len(opts.Mounts) > 0 {
		app.MountPoints = []appctypes.MountPoint{}
	}
	for _, m := range opts.Mounts {
		mountPointName, err := appctypes.NewACName(m.Name)
		if err != nil {
			return err
		}
		app.MountPoints = append(app.MountPoints, appctypes.MountPoint{
			Name:     *mountPointName,
			Path:     m.ContainerPath,
			ReadOnly: m.ReadOnly,
		})
	}

	// Override the ports.
	if len(opts.PortMappings) > 0 {
		app.Ports = []appctypes.Port{}
	}
	for _, p := range opts.PortMappings {
		name, err := appctypes.SanitizeACName(p.Name)
		if err != nil {
			return err
		}
		portName := appctypes.MustACName(name)
		app.Ports = append(app.Ports, appctypes.Port{
			Name:     *portName,
			Protocol: string(p.Protocol),
			Port:     uint(p.ContainerPort),
		})
	}

	// Override isolators.
	return setIsolators(app, c)
}
Example #18
0
// prepareIsolators merges the CLI app parameters with the manifest's app
func prepareIsolators(setup *apps.App, app *types.App) error {
	if memoryOverride := setup.MemoryLimit; memoryOverride != nil {
		isolator := memoryOverride.AsIsolator()
		app.Isolators = append(app.Isolators, isolator)
	}

	if cpuOverride := setup.CPULimit; cpuOverride != nil {
		isolator := cpuOverride.AsIsolator()
		app.Isolators = append(app.Isolators, isolator)
	}

	if cpuSharesOverride := setup.CPUShares; cpuSharesOverride != nil {
		isolator := cpuSharesOverride.AsIsolator()
		app.Isolators.ReplaceIsolatorsByName(isolator, []types.ACIdentifier{types.LinuxCPUSharesName})
	}

	if oomAdjOverride := setup.OOMScoreAdj; oomAdjOverride != nil {
		app.Isolators.ReplaceIsolatorsByName(oomAdjOverride.AsIsolator(), []types.ACIdentifier{types.LinuxOOMScoreAdjName})
	}

	if setup.CapsRetain != nil && setup.CapsRemove != nil {
		return fmt.Errorf("error: cannot use both --caps-retain and --caps-remove on the same image")
	}

	// Delete existing caps isolators if the user wants to override
	// them with either --caps-retain or --caps-remove
	if setup.CapsRetain != nil || setup.CapsRemove != nil {
		for i := len(app.Isolators) - 1; i >= 0; i-- {
			isolator := app.Isolators[i]
			if _, ok := isolator.Value().(types.LinuxCapabilitiesSet); ok {
				app.Isolators = append(app.Isolators[:i],
					app.Isolators[i+1:]...)
			}
		}
	}

	if capsRetain := setup.CapsRetain; capsRetain != nil {
		isolator, err := capsRetain.AsIsolator()
		if err != nil {
			return err
		}
		app.Isolators = append(app.Isolators, *isolator)
	} else if capsRemove := setup.CapsRemove; capsRemove != nil {
		isolator, err := capsRemove.AsIsolator()
		if err != nil {
			return err
		}
		app.Isolators = append(app.Isolators, *isolator)
	}

	// Override seccomp isolators via --seccomp CLI switch
	if setup.SeccompFilter != "" {
		var is *types.Isolator
		mode, errno, set, err := setup.SeccompOverride()
		if err != nil {
			return err
		}
		switch mode {
		case "retain":
			lss, err := types.NewLinuxSeccompRetainSet(errno, set...)
			if err != nil {
				return err
			}
			if is, err = lss.AsIsolator(); err != nil {
				return err
			}
		case "remove":
			lss, err := types.NewLinuxSeccompRemoveSet(errno, set...)
			if err != nil {
				return err
			}
			if is, err = lss.AsIsolator(); err != nil {
				return err
			}
		default:
			return apps.ErrInvalidSeccompMode
		}
		app.Isolators.ReplaceIsolatorsByName(*is, []types.ACIdentifier{types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName})
	}
	return nil
}