func AppAddMounts(p *stage1commontypes.Pod, ra *schema.RuntimeApp, enterCmd []string) error { sharedVolPath, err := common.CreateSharedVolumesPath(p.Root) if err != nil { return err } vols := make(map[types.ACName]types.Volume) for _, v := range p.Manifest.Volumes { vols[v.Name] = v } imageManifest := p.Images[ra.Name.String()] mounts, err := GenerateMounts(ra, p.Manifest.Volumes, ConvertedFromDocker(imageManifest)) if err != nil { log.FatalE("Could not generate mounts", err) os.Exit(254) } absRoot, err := filepath.Abs(p.Root) if err != nil { log.FatalE("could not determine pod's absolute path", err) } appRootfs := common.AppRootfsPath(absRoot, ra.Name) // This logic is mostly copied from appToNspawnArgs // TODO(cdc): deduplicate for _, m := range mounts { shPath := filepath.Join(sharedVolPath, m.Volume.Name.String()) // Evaluate symlinks within the app's rootfs - otherwise absolute // symlinks will be wrong. mntPath, err := EvaluateSymlinksInsideApp(appRootfs, m.Mount.Path) if err != nil { log.Fatalf("Could not evaluate path %v: %v", m.Mount.Path, err) } mntAbsPath := filepath.Join(appRootfs, mntPath) // Create the stage1 destination if err := PrepareMountpoints(shPath, mntAbsPath, &m.Volume, m.DockerImplicit); err != nil { log.FatalE("could not prepare mountpoint", err) } err = AppAddOneMount(p, ra, m.Source(absRoot), m.Mount.Path, m.ReadOnly, enterCmd) if err != nil { log.FatalE("Unable to setup app mounts", err) } } return nil }
func mountSharedVolumes(p *stage1commontypes.Pod, ra *schema.RuntimeApp) error { appName := ra.Name sharedVolPath, err := common.CreateSharedVolumesPath(p.Root) if err != nil { return err } imageManifest := p.Images[appName.String()] mounts, err := stage1initcommon.GenerateMounts(ra, p.Manifest.Volumes, stage1initcommon.ConvertedFromDocker(imageManifest)) if err != nil { return err } for _, m := range mounts { absRoot, err := filepath.Abs(p.Root) // Absolute path to the pod's rootfs. if err != nil { return errwrap.Wrap(errors.New("could not get pod's root absolute path"), err) } absAppRootfs := common.AppRootfsPath(absRoot, appName) if err != nil { return fmt.Errorf(`could not evaluate absolute path for application rootfs in app: %v`, appName) } mntPath, err := stage1initcommon.EvaluateSymlinksInsideApp(absAppRootfs, m.Mount.Path) if err != nil { return errwrap.Wrap(fmt.Errorf("could not evaluate path %v", m.Mount.Path), err) } absDestination := filepath.Join(absAppRootfs, mntPath) shPath := filepath.Join(sharedVolPath, m.Volume.Name.String()) if err := stage1initcommon.PrepareMountpoints(shPath, absDestination, &m.Volume, m.DockerImplicit); err != nil { return err } source := m.Source(p.Root) if cleanedSource, err := filepath.EvalSymlinks(source); err != nil { return errwrap.Wrap(fmt.Errorf("could not resolve symlink for source: %v", source), err) } else if err := ensureDestinationExists(cleanedSource, absDestination); err != nil { return errwrap.Wrap(fmt.Errorf("could not create destination mount point: %v", absDestination), err) } else if err := doBindMount(cleanedSource, absDestination, m.ReadOnly, m.Volume.Recursive); err != nil { return errwrap.Wrap(fmt.Errorf("could not bind mount path %v (s: %v, d: %v)", m.Mount.Path, source, absDestination), err) } } return nil }
// appToNspawnArgs transforms the given app manifest, with the given associated // app name, into a subset of applicable systemd-nspawn argument func appToNspawnArgs(p *stage1commontypes.Pod, ra *schema.RuntimeApp) ([]string, error) { var args []string appName := ra.Name app := ra.App sharedVolPath, err := common.CreateSharedVolumesPath(p.Root) if err != nil { return nil, err } vols := make(map[types.ACName]types.Volume) for _, v := range p.Manifest.Volumes { vols[v.Name] = v } imageManifest := p.Images[appName.String()] mounts, err := GenerateMounts(ra, p.Manifest.Volumes, ConvertedFromDocker(imageManifest)) if err != nil { return nil, errwrap.Wrap(fmt.Errorf("could not generate app %q mounts", appName), err) } for _, m := range mounts { shPath := filepath.Join(sharedVolPath, m.Volume.Name.String()) absRoot, err := filepath.Abs(p.Root) // Absolute path to the pod's rootfs. if err != nil { return nil, errwrap.Wrap(errors.New("could not get pod's root absolute path"), err) } appRootfs := common.AppRootfsPath(absRoot, appName) // Evaluate symlinks within the app's rootfs. This is needed because symlinks // within the container can be absolute, which will, of course, be wrong in our ns. // Systemd also gets this wrong, see https://github.com/systemd/systemd/issues/2860 // When the above issue is fixed, we can pass the un-evaluated path to --bind instead. mntPath, err := EvaluateSymlinksInsideApp(appRootfs, m.Mount.Path) if err != nil { return nil, errwrap.Wrap(fmt.Errorf("could not evaluate path %v", m.Mount.Path), err) } mntAbsPath := filepath.Join(appRootfs, mntPath) if err := PrepareMountpoints(shPath, mntAbsPath, &m.Volume, m.DockerImplicit); err != nil { return nil, err } opt := make([]string, 6) if m.ReadOnly { opt[0] = "--bind-ro=" } else { opt[0] = "--bind=" } opt[1] = m.Source(absRoot) opt[2] = ":" opt[3] = filepath.Join(common.RelAppRootfsPath(appName), mntPath) opt[4] = ":" // If Recursive is not set, default to recursive. recursive := true if m.Volume.Recursive != nil { recursive = *m.Volume.Recursive } // rbind/norbind options exist since systemd-nspawn v226 if recursive { opt[5] = "rbind" } else { opt[5] = "norbind" } args = append(args, strings.Join(opt, "")) } if !p.InsecureOptions.DisableCapabilities { capabilitiesStr, err := getAppCapabilities(app.Isolators) if err != nil { return nil, err } capList := strings.Join(capabilitiesStr, ",") args = append(args, "--capability="+capList) } return args, nil }