// 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) } var appName *types.ACName if app.Name != "" { appName, err = types.NewACName(app.Name) if err != nil { return errwrap.Wrap(errors.New("invalid app name format"), err) } } else { 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 preparing 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, }, Mounts: MergeMounts(cfg.Apps.Mounts, app.Mounts), ReadOnlyRootFS: app.ReadOnlyRootFS, } if app.Exec != "" { // 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{app.Exec} } if app.Args != nil { ra.App.Exec = append(ra.App.Exec, app.Args...) } if app.WorkingDir != "" { ra.App.WorkingDirectory = app.WorkingDir } if err := prepareIsolators(app, ra.App); err != nil { return err } if app.User != "" { ra.App.User = app.User } if app.Group != "" { ra.App.Group = app.Group } if app.SupplementaryGIDs != nil { ra.App.SupplementaryGIDs = app.SupplementaryGIDs } if app.UserAnnotations != nil { ra.App.UserAnnotations = app.UserAnnotations } if app.UserLabels != nil { ra.App.UserLabels = app.UserLabels } // 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) if app.Environments != nil { envs := make([]string, 0, len(app.Environments)) for name, value := range app.Environments { envs = append(envs, fmt.Sprintf("%s=%s", name, value)) } mergeEnvs(&ra.App.Environment, envs, 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 // Check to see if ports have any errors pm.Ports = cfg.Ports if _, err := commonnet.ForwardedPorts(&pm); err != nil { return nil, err } pm.Annotations = append(pm.Annotations, types.Annotation{ Name: "coreos.com/rkt/stage1/mutable", Value: strconv.FormatBool(cfg.Mutable), }) pm.UserAnnotations = cfg.UserAnnotations pm.UserLabels = cfg.UserLabels pmb, err := json.Marshal(pm) if err != nil { return nil, errwrap.Wrap(errors.New("error marshalling pod manifest"), err) } return pmb, nil }