// parseSeccompArgs parses seccomp mode and set CLI flags, preparing an // appropriate seccomp isolator. func parseSeccompArgs(patchSeccompMode string, patchSeccompSet string) (*types.Isolator, error) { // Parse mode flag and additional keyed arguments. var errno, mode string args := strings.Split(patchSeccompMode, ",") for _, a := range args { kv := strings.Split(a, "=") switch len(kv) { case 1: // mode, either "remove" or "retain" mode = kv[0] case 2: // k=v argument, only "errno" allowed for now if kv[0] == "errno" { errno = kv[1] } else { return nil, fmt.Errorf("invalid seccomp-mode optional argument: %s", a) } default: return nil, fmt.Errorf("cannot parse seccomp-mode argument: %s", a) } } // Instantiate an Isolator with the content specified by the --seccomp-set parameter. var err error var seccomp types.AsIsolator switch mode { case "remove": seccomp, err = types.NewLinuxSeccompRemoveSet(errno, strings.Split(patchSeccompSet, ",")...) case "retain": seccomp, err = types.NewLinuxSeccompRetainSet(errno, strings.Split(patchSeccompSet, ",")...) default: err = fmt.Errorf("unknown seccomp mode %s", mode) } if err != nil { return nil, fmt.Errorf("cannot parse seccomp isolator: %s", err) } seccompIsolator, err := seccomp.AsIsolator() if err != nil { return nil, err } return seccompIsolator, nil }
// generatePodManifest creates the pod manifest from the command line input. // It returns the pod manifest as []byte on success. // This is invoked if no pod manifest is specified at the command line. func generatePodManifest(cfg PrepareConfig, dir string) ([]byte, error) { pm := schema.PodManifest{ ACKind: "PodManifest", Apps: make(schema.AppList, 0), } v, err := types.NewSemVer(version.Version) if err != nil { return nil, errwrap.Wrap(errors.New("error creating version"), err) } pm.ACVersion = *v if err := cfg.Apps.Walk(func(app *apps.App) error { img := app.ImageID am, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return errwrap.Wrap(errors.New("error getting the manifest"), err) } appName, err := imageNameToAppName(am.Name) if err != nil { return errwrap.Wrap(errors.New("error converting image name to app name"), err) } if err := prepareAppImage(cfg, *appName, img, dir, cfg.UseOverlay); err != nil { return errwrap.Wrap(fmt.Errorf("error setting up image %s", img), err) } if pm.Apps.Get(*appName) != nil { return fmt.Errorf("error: multiple apps with name %s", am.Name) } if am.App == nil && app.Exec == "" { return fmt.Errorf("error: image %s has no app section and --exec argument is not provided", img) } ra := schema.RuntimeApp{ // TODO(vc): leverage RuntimeApp.Name for disambiguating the apps Name: *appName, App: am.App, Image: schema.RuntimeImage{ Name: &am.Name, ID: img, Labels: am.Labels, }, Annotations: am.Annotations, Mounts: MergeMounts(cfg.Apps.Mounts, app.Mounts), } if execOverride := app.Exec; execOverride != "" { // Create a minimal App section if not present if am.App == nil { ra.App = &types.App{ User: strconv.Itoa(os.Getuid()), Group: strconv.Itoa(os.Getgid()), } } ra.App.Exec = []string{execOverride} } if execAppends := app.Args; execAppends != nil { ra.App.Exec = append(ra.App.Exec, execAppends...) } if memoryOverride := app.MemoryLimit; memoryOverride != nil { isolator := memoryOverride.AsIsolator() ra.App.Isolators = append(ra.App.Isolators, isolator) } if cpuOverride := app.CPULimit; cpuOverride != nil { isolator := cpuOverride.AsIsolator() ra.App.Isolators = append(ra.App.Isolators, isolator) } if app.CapsRetain != nil && app.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 app.CapsRetain != nil || app.CapsRemove != nil { for i := len(ra.App.Isolators) - 1; i >= 0; i-- { isolator := ra.App.Isolators[i] if _, ok := isolator.Value().(types.LinuxCapabilitiesSet); ok { ra.App.Isolators = append(ra.App.Isolators[:i], ra.App.Isolators[i+1:]...) } } } if capsRetain := app.CapsRetain; capsRetain != nil { isolator, err := capsRetain.AsIsolator() if err != nil { return err } ra.App.Isolators = append(ra.App.Isolators, *isolator) } else if capsRemove := app.CapsRemove; capsRemove != nil { isolator, err := capsRemove.AsIsolator() if err != nil { return err } ra.App.Isolators = append(ra.App.Isolators, *isolator) } // Override seccomp isolators via --seccomp CLI switch if app.SeccompFilter != "" { var is *types.Isolator mode, errno, set, err := app.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 } ra.App.Isolators.ReplaceIsolatorsByName(*is, []types.ACIdentifier{types.LinuxSeccompRemoveSetName, types.LinuxSeccompRetainSetName}) } if user := app.User; user != "" { ra.App.User = user } if group := app.Group; group != "" { ra.App.Group = group } // loading the environment from the lowest priority to highest if cfg.InheritEnv { // Inherit environment does not override app image environment mergeEnvs(&ra.App.Environment, os.Environ(), false) } mergeEnvs(&ra.App.Environment, cfg.EnvFromFile, true) mergeEnvs(&ra.App.Environment, cfg.ExplicitEnv, true) pm.Apps = append(pm.Apps, ra) return nil }); err != nil { return nil, err } // TODO(jonboulle): check that app mountpoint expectations are // satisfied here, rather than waiting for stage1 pm.Volumes = cfg.Apps.Volumes pm.Ports = cfg.Ports pmb, err := json.Marshal(pm) if err != nil { return nil, errwrap.Wrap(errors.New("error marshalling pod manifest"), err) } return pmb, nil }
// 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 }