Example #1
0
// 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
}