// AppsForPod returns the apps of the pod with the given uuid in the given data directory. // If appName is non-empty, then only the app with the given name will be returned. func AppsForPod(uuid, dataDir string, appName string) ([]*App, error) { p, err := pkgPod.PodFromUUIDString(dataDir, uuid) if err != nil { return nil, err } defer p.Close() _, podManifest, err := p.PodManifest() if err != nil { return nil, err } var apps []*App for _, ra := range podManifest.Apps { if appName != "" && appName != ra.Name.String() { continue } app, err := newApp(&ra, podManifest, p) if err != nil { fmt.Fprintf(os.Stderr, "Cannot get app status: %v", err) continue } apps = append(apps, app) } return apps, nil }
func runStatus(cmd *cobra.Command, args []string) (exit int) { if len(args) != 1 { cmd.Usage() return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() if flagWait { if err := p.WaitExited(); err != nil { stderr.PrintE("unable to wait for pod", err) return 254 } } if err = printStatus(p); err != nil { stderr.PrintE("unable to print status", err) return 254 } return 0 }
func runAppStart(cmd *cobra.Command, args []string) (exit int) { if len(args) < 1 { stderr.Print("must provide the pod UUID") return 1 } if flagAppName == "" { stderr.Print("must provide the app to start") return 1 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 1 } defer p.Close() if p.State() != pkgPod.Running { stderr.Printf("pod %q isn't currently running", p.UUID) return 1 } appName, err := types.NewACName(flagAppName) if err != nil { stderr.PrintE("invalid app name", err) } podPID, err := p.ContainerPid1() if err != nil { stderr.PrintE(fmt.Sprintf("unable to determine the pid for pod %q", p.UUID), err) return 1 } cfg := stage0.CommonConfig{ DataDir: getDataDir(), UUID: p.UUID, Debug: globalFlags.Debug, } scfg := stage0.StartConfig{ CommonConfig: &cfg, PodPath: p.Path(), AppName: appName, PodPID: podPID, } if globalFlags.Debug { stage0.InitDebug() } err = stage0.StartApp(scfg) if err != nil { stderr.PrintE("error starting app", err) return 1 } return 0 }
func runStop(cmd *cobra.Command, args []string) (exit int) { var podUUIDs []string var errors int ret := 0 switch { case len(args) == 0 && flagUUIDFile != "": podUUID, err := pkgPod.ReadUUIDFromFile(flagUUIDFile) if err != nil { stderr.PrintE("unable to resolve UUID from file", err) ret = 1 } else { podUUIDs = append(podUUIDs, podUUID) } case len(args) > 0 && flagUUIDFile == "": podUUIDs = args default: cmd.Usage() return 254 } for _, podUUID := range podUUIDs { p, err := pkgPod.PodFromUUIDString(getDataDir(), podUUID) if err != nil { errors++ stderr.PrintE("cannot get pod", err) continue } if p.AfterRun() { stdout.Printf("pod %q is already stopped", p.UUID) continue } if p.State() != pkgPod.Running { stderr.Error(fmt.Errorf("pod %q is not running", p.UUID)) errors++ continue } if err := stage0.StopPod(p.Path(), flagForce, p.UUID); err == nil { stdout.Printf("%q", p.UUID) } else { stderr.PrintE(fmt.Sprintf("error stopping %q", p.UUID), err) errors++ } } if errors > 0 { stderr.Error(fmt.Errorf("failed to stop %d pod(s)", errors)) return 254 } return ret }
func StopApp(cfg StopConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } defer pod.Close() _, pm, err := pod.PodManifest() if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot start application") } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // exit status 5 comes from systemctl and means the unit doesn't exist if status == 5 { return fmt.Errorf("app %q is not running", app.Name) } return err } return nil }
func StartApp(cfg StartConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() _, pm, err := pod.PodManifest() if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot start application") } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--app=%s", cfg.AppName), } if _, err := os.Create(common.AppStartedPath(cfg.PodPath, cfg.AppName.String())); err != nil { log.FatalE(fmt.Sprintf("error creating %s-started file", cfg.AppName.String()), err) } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStartEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { return err } return nil }
func (s *v1AlphaAPIServer) InspectPod(ctx context.Context, request *v1alpha.InspectPodRequest) (*v1alpha.InspectPodResponse, error) { p, err := pkgPod.PodFromUUIDString(getDataDir(), request.Id) if err != nil { stderr.PrintE(fmt.Sprintf("failed to get pod %q", request.Id), err) return nil, err } defer p.Close() pod := s.getBasicPod(p) fillPodDetails(s.store, p, pod) return &v1alpha.InspectPodResponse{Pod: pod}, nil }
func (s *v1AlphaAPIServer) constrainedGetLogs(request *v1alpha.GetLogsRequest, server v1alpha.PublicAPI_GetLogsServer) error { pod, err := pkgPod.PodFromUUIDString(getDataDir(), request.PodId) if err != nil { return err } defer pod.Close() path, err := pod.JournalLogPath() if _, err := os.Stat(path); os.IsNotExist(err) { return fmt.Errorf("logging unsupported for pod %q", request.PodId) } jconf := sdjournal.JournalReaderConfig{ Path: path, } if request.AppName != "" { jconf.Matches = []sdjournal.Match{ { Field: sdjournal.SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER, Value: request.AppName, }, } } if request.SinceTime != 0 { t := time.Unix(request.SinceTime, 0) jconf.Since = -time.Since(t) } if request.Lines != 0 { jconf.NumFromTail = uint64(request.Lines) } jr, err := sdjournal.NewJournalReader(jconf) if err != nil { return err } defer jr.Close() if request.Follow { return jr.Follow(nil, LogsStreamWriter{server: server}) } data, err := ioutil.ReadAll(jr) if err != nil { return err } return server.Send(&v1alpha.GetLogsResponse{Lines: common.RemoveEmptyLines(string(data))}) }
func runStatus(cmd *cobra.Command, args []string) (exit int) { if len(args) != 1 { cmd.Usage() return 254 } dWait, err := parseDuration(flagWait) if err != nil { cmd.Usage() return 254 } dReady, err := parseDuration(flagWaitReady) if err != nil { cmd.Usage() return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() if dReady != 0 { if err := p.WaitReady(newContext(dReady)); err != nil { stderr.PrintE("error waiting for pod readiness", err) return 254 } } if dWait != 0 { if err := p.WaitFinished(newContext(dWait)); err != nil { stderr.PrintE("error waiting for pod to finish", err) return 254 } } if err = printStatus(p); err != nil { stderr.PrintE("unable to print status", err) return 254 } return 0 }
func StopApp(cfg StopConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } defer pod.Close() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot stop application"), err) } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // exit status 5 comes from systemctl and means the unit doesn't exist if status == 5 { return fmt.Errorf("app %q is not running", app.Name) } return err } return nil }
func StartApp(cfg StartConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot start application"), err) } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--app=%s", cfg.AppName), } if _, err := os.Create(common.AppStartedPath(cfg.PodPath, cfg.AppName.String())); err != nil { log.FatalE(fmt.Sprintf("error creating %s-started file", cfg.AppName.String()), err) } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStartEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { return err } return nil }
func RmApp(cfg RmConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() debug("locking sandbox manifest") if err := pod.ExclusiveLockManifest(); err != nil { return errwrap.Wrap(errors.New("failed to lock sandbox manifest"), err) } defer pod.UnlockManifest() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot remove application, sandbox validation failed"), err) } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } if cfg.PodPID > 0 { // Call app-stop and app-rm entrypoint only if the pod is still running. // Otherwise, there's not much we can do about it except unmounting/removing // the file system. args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // ignore nonexistent units failing to stop. Exit status 5 // comes from systemctl and means the unit doesn't exist if err != nil { return err } else if status != 5 { return fmt.Errorf("exit status %d", status) } } ce.EntrypointName = appRmEntrypoint if err := ce.Run(); err != nil { return err } } if cfg.UsesOverlay { treeStoreID, err := ioutil.ReadFile(common.AppTreeStoreIDPath(cfg.PodPath, *cfg.AppName)) if err != nil { return err } appRootfs := common.AppRootfsPath(cfg.PodPath, *cfg.AppName) if err := syscall.Unmount(appRootfs, 0); err != nil { return err } ts := filepath.Join(cfg.PodPath, "overlay", string(treeStoreID)) if err := os.RemoveAll(ts); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } } appInfoDir := common.AppInfoPath(cfg.PodPath, *cfg.AppName) if err := os.RemoveAll(appInfoDir); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } if err := os.RemoveAll(common.AppPath(cfg.PodPath, *cfg.AppName)); err != nil { return err } appStatusPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "status", cfg.AppName.String()) if err := os.Remove(appStatusPath); err != nil && !os.IsNotExist(err) { return err } envPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "env", cfg.AppName.String()) if err := os.Remove(envPath); err != nil && !os.IsNotExist(err) { return err } for i, app := range pm.Apps { if app.Name == *cfg.AppName { pm.Apps = append(pm.Apps[:i], pm.Apps[i+1:]...) break } } return pod.UpdateManifest(pm, cfg.PodPath) }
func runAppAdd(cmd *cobra.Command, args []string) (exit int) { if len(args) < 2 { stderr.Print("must provide the pod UUID and an IMAGEID") return 254 } err := parseApps(&rktApps, args[1:], cmd.Flags(), true) if err != nil { stderr.PrintE("error parsing app image arguments", err) return 254 } if rktApps.Count() > 1 { stderr.Print("must give only one app") return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() if p.State() != pkgPod.Running { stderr.Printf("pod %q isn't currently running", p.UUID) return 254 } if !p.IsSupervisorReady() { stderr.Printf("supervisor for pod %q is not yet ready", p.UUID) return 254 } s, err := imagestore.NewStore(storeDir()) if err != nil { stderr.PrintE("cannot open store", err) return 254 } ts, err := treestore.NewStore(treeStoreDir(), s) if err != nil { stderr.PrintE("cannot open treestore", err) return 254 } fn := &image.Finder{ S: s, Ts: ts, Ks: getKeystore(), StoreOnly: true, NoStore: false, } img, err := fn.FindImage(args[1], "") if err != nil { stderr.PrintE("error finding images", err) return 254 } podPID, err := p.ContainerPid1() if err != nil { stderr.PrintE(fmt.Sprintf("unable to determine the pid for pod %q", p.UUID), err) return 254 } ccfg := stage0.CommonConfig{ DataDir: getDataDir(), Store: s, TreeStore: ts, UUID: p.UUID, Debug: globalFlags.Debug, } rktgid, err := common.LookupGid(common.RktGroup) if err != nil { stderr.Printf("group %q not found, will use default gid when rendering images", common.RktGroup) rktgid = -1 } cfg := stage0.AddConfig{ CommonConfig: &ccfg, Image: *img, Apps: &rktApps, RktGid: rktgid, UsesOverlay: p.UsesOverlay(), PodPath: p.Path(), PodPID: podPID, } if globalFlags.Debug { stage0.InitDebug() } err = stage0.AddApp(cfg) if err != nil { stderr.PrintE("error adding app to pod", err) return 254 } return 0 }
func runRunPrepared(cmd *cobra.Command, args []string) (exit int) { if len(args) != 1 { cmd.Usage() return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() s, err := imagestore.NewStore(storeDir()) if err != nil { stderr.PrintE("cannot open store", err) return 254 } ts, err := treestore.NewStore(treeStoreDir(), s) if err != nil { stderr.PrintE("cannot open treestore", err) return 254 } if p.State() != pkgPod.Prepared { stderr.Printf("pod %q is not prepared", p.UUID) return 254 } _, manifest, err := p.PodManifest() if err != nil { stderr.PrintE("cannot read pod manifest", err) return 254 } if flagInteractive { if len(manifest.Apps) > 1 { stderr.Print("interactive option only supports pods with one app") return 254 } } // Make sure we have a metadata service available before we move to // run state so that the user can rerun the command without needing // to prepare the image again. if flagMDSRegister { if err := stage0.CheckMdsAvailability(); err != nil { stderr.Error(err) return 254 } } if err := p.ToRun(); err != nil { stderr.PrintE("cannot transition to run", err) return 254 } lfd, err := p.Fd() if err != nil { stderr.PrintE("unable to get lock fd", err) return 254 } rktgid, err := common.LookupGid(common.RktGroup) if err != nil { stderr.Printf("group %q not found, will use default gid when rendering images", common.RktGroup) rktgid = -1 } ovlOk := true if err := common.PathSupportsOverlay(getDataDir()); err != nil { if oerr, ok := err.(common.ErrOverlayUnsupported); ok { stderr.Printf("disabling overlay support: %q", oerr.Error()) ovlOk = false } else { stderr.PrintE("error determining overlay support", err) return 254 } } ovlPrep := p.UsesOverlay() // should not happen, maybe the data directory moved from an overlay-enabled fs to another location // between prepare and run-prepared if ovlPrep && !ovlOk { stderr.Print("unable to run prepared overlay-enabled pod: overlay not supported") return 254 } DNSConfMode, DNSConfig, HostsEntries, err := parseDNSFlags(flagHostsEntries, flagDNS, flagDNSSearch, flagDNSOpt, flagDNSDomain) if err != nil { stderr.PrintE("error with dns flags", err) return 254 } rcfg := stage0.RunConfig{ CommonConfig: &stage0.CommonConfig{ DataDir: getDataDir(), Store: s, TreeStore: ts, UUID: p.UUID, Debug: globalFlags.Debug, }, Net: flagNet, LockFd: lfd, Interactive: flagInteractive, DNSConfMode: DNSConfMode, DNSConfig: DNSConfig, HostsEntries: *HostsEntries, MDSRegister: flagMDSRegister, Apps: manifest.Apps, RktGid: rktgid, Hostname: flagHostname, InsecureCapabilities: globalFlags.InsecureFlags.SkipCapabilities(), InsecurePaths: globalFlags.InsecureFlags.SkipPaths(), InsecureSeccomp: globalFlags.InsecureFlags.SkipSeccomp(), UseOverlay: ovlPrep && ovlOk, } if globalFlags.Debug { stage0.InitDebug() } stage0.Run(rcfg, p.Path(), getDataDir()) // execs, never returns return 254 }
func runEnter(cmd *cobra.Command, args []string) (exit int) { if len(args) < 1 { cmd.Usage() return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() if p.State() != pkgPod.Running { stderr.Printf("pod %q isn't currently running", p.UUID) return 254 } podPID, err := p.ContainerPid1() if err != nil { stderr.PrintE(fmt.Sprintf("unable to determine the pid for pod %q", p.UUID), err) return 254 } appName, err := getAppName(p) if err != nil { stderr.PrintE("unable to determine app name", err) return 254 } argv, err := getEnterArgv(p, args) if err != nil { stderr.PrintE("enter failed", err) return 254 } s, err := imagestore.NewStore(storeDir()) if err != nil { stderr.PrintE("cannot open store", err) return 254 } ts, err := treestore.NewStore(treeStoreDir(), s) if err != nil { stderr.PrintE("cannot open store", err) return 254 } stage1TreeStoreID, err := p.GetStage1TreeStoreID() if err != nil { stderr.PrintE("error getting stage1 treeStoreID", err) return 254 } stage1RootFS := ts.GetRootFS(stage1TreeStoreID) if err = stage0.Enter(p.Path(), podPID, *appName, stage1RootFS, argv); err != nil { stderr.PrintE("enter failed", err) return 254 } // not reached when stage0.Enter execs /enter return 0 }
func AddApp(cfg AddConfig) error { // there should be only one app in the config app := cfg.Apps.Last() if app == nil { return errors.New("no image specified") } am, err := cfg.Store.GetImageManifest(cfg.Image.String()) if err != nil { return err } var appName *types.ACName if app.Name != "" { appName, err = types.NewACName(app.Name) if err != nil { return err } } else { appName, err = imageNameToAppName(am.Name) if err != nil { return err } } pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() debug("locking pod manifest") if err := pod.ExclusiveLockManifest(); err != nil { return errwrap.Wrap(errors.New("failed to lock pod manifest"), err) } defer pod.UnlockManifest() pm, err := pod.SandboxManifest() if err != nil { return errwrap.Wrap(errors.New("cannot add application"), err) } if pm.Apps.Get(*appName) != nil { return fmt.Errorf("error: multiple apps with name %s", *appName) } if am.App == nil && app.Exec == "" { return fmt.Errorf("error: image %s has no app section and --exec argument is not provided", cfg.Image) } appInfoDir := common.AppInfoPath(cfg.PodPath, *appName) if err := os.MkdirAll(appInfoDir, common.DefaultRegularDirPerm); err != nil { return errwrap.Wrap(errors.New("error creating apps info directory"), err) } pcfg := PrepareConfig{ CommonConfig: cfg.CommonConfig, PrivateUsers: user.NewBlankUidRange(), } if cfg.UsesOverlay { privateUsers, err := preparedWithPrivateUsers(cfg.PodPath) if err != nil { log.FatalE("error reading user namespace information", err) } if err := pcfg.PrivateUsers.Deserialize([]byte(privateUsers)); err != nil { return err } } treeStoreID, err := prepareAppImage(pcfg, *appName, cfg.Image, cfg.PodPath, cfg.UsesOverlay) if err != nil { return errwrap.Wrap(fmt.Errorf("error preparing image %s", cfg.Image), err) } rcfg := RunConfig{ CommonConfig: cfg.CommonConfig, UseOverlay: cfg.UsesOverlay, RktGid: cfg.RktGid, } if err := setupAppImage(rcfg, *appName, cfg.Image, cfg.PodPath, cfg.UsesOverlay); err != nil { return fmt.Errorf("error setting up app image: %v", err) } if cfg.UsesOverlay { imgDir := filepath.Join(cfg.PodPath, "overlay", treeStoreID) if err := os.Chown(imgDir, -1, cfg.RktGid); err != nil { return err } } ra := schema.RuntimeApp{ Name: *appName, App: am.App, Image: schema.RuntimeImage{ Name: &am.Name, ID: cfg.Image, 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 } 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)) } // Let the app level environment override the environment variables. mergeEnvs(&ra.App.Environment, envs, true) } env := ra.App.Environment env.Set("AC_APP_NAME", appName.String()) envFilePath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "env", appName.String()) if err := common.WriteEnvFile(env, pcfg.PrivateUsers, envFilePath); err != nil { return err } debug("adding app to sandbox") pm.Apps = append(pm.Apps, ra) if err := pod.UpdateManifest(pm, cfg.PodPath); err != nil { return err } args := []string{ fmt.Sprintf("--debug=%t", cfg.Debug), fmt.Sprintf("--uuid=%s", cfg.UUID), fmt.Sprintf("--app=%s", appName), } if _, err := os.Create(common.AppCreatedPath(pod.Path(), appName.String())); err != nil { return err } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: appName.String(), EntrypointName: appAddEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { return err } return nil }
func runExport(cmd *cobra.Command, args []string) (exit int) { if len(args) != 2 { cmd.Usage() return 254 } outACI := args[1] ext := filepath.Ext(outACI) if ext != schema.ACIExtension { stderr.Printf("extension must be %s (given %s)", schema.ACIExtension, outACI) return 254 } p, err := pkgPod.PodFromUUIDString(getDataDir(), args[0]) if err != nil { stderr.PrintE("problem retrieving pod", err) return 254 } defer p.Close() state := p.State() if state != pkgPod.Exited && state != pkgPod.ExitedGarbage { stderr.Print("pod is not exited. Only exited pods can be exported") return 254 } app, err := getApp(p) if err != nil { stderr.PrintE("unable to find app", err) return 254 } root := common.AppPath(p.Path(), app.Name) manifestPath := filepath.Join(common.AppInfoPath(p.Path(), app.Name), aci.ManifestFile) if p.UsesOverlay() { tmpDir := filepath.Join(getDataDir(), "tmp") if err := os.MkdirAll(tmpDir, common.DefaultRegularDirPerm); err != nil { stderr.PrintE("unable to create temp directory", err) return 254 } podDir, err := ioutil.TempDir(tmpDir, fmt.Sprintf("rkt-export-%s", p.UUID)) if err != nil { stderr.PrintE("unable to create export temp directory", err) return 254 } defer func() { if err := os.RemoveAll(podDir); err != nil { stderr.PrintE("problem removing temp directory", err) exit = 1 } }() mntDir := filepath.Join(podDir, "rootfs") if err := os.Mkdir(mntDir, common.DefaultRegularDirPerm); err != nil { stderr.PrintE("unable to create rootfs directory inside temp directory", err) return 254 } if err := mountOverlay(p, app, mntDir); err != nil { stderr.PrintE(fmt.Sprintf("couldn't mount directory at %s", mntDir), err) return 254 } defer func() { if err := syscall.Unmount(mntDir, 0); err != nil { stderr.PrintE(fmt.Sprintf("error unmounting directory %s", mntDir), err) exit = 1 } }() root = podDir } else { hasMPs, err := appHasMountpoints(p.Path(), app.Name) if err != nil { stderr.PrintE("error parsing mountpoints", err) return 254 } if hasMPs { stderr.Printf("pod has remaining mountpoints. Only pods using overlayfs or with no mountpoints can be exported") return 254 } } // Check for user namespace (--private-user), if in use get uidRange var uidRange *user.UidRange privUserFile := filepath.Join(p.Path(), common.PrivateUsersPreparedFilename) privUserContent, err := ioutil.ReadFile(privUserFile) if err == nil { uidRange = user.NewBlankUidRange() // The file was found, save uid & gid shift and count if err := uidRange.Deserialize(privUserContent); err != nil { stderr.PrintE(fmt.Sprintf("problem deserializing the content of %s", common.PrivateUsersPreparedFilename), err) return 254 } } if err = buildAci(root, manifestPath, outACI, uidRange); err != nil { stderr.PrintE("error building aci", err) return 254 } return 0 }
func RmApp(cfg RmConfig) error { pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String()) if err != nil { return errwrap.Wrap(errors.New("error loading pod"), err) } defer pod.Close() debug("locking pod manifest") if err := pod.ExclusiveManifestLock(); err != nil { return errwrap.Wrap(errors.New("failed to lock pod manifest"), err) } defer pod.ManifestUnlock() _, pm, err := pod.PodManifest() if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot remove application") } app := pm.Apps.Get(*cfg.AppName) if app == nil { return fmt.Errorf("error: nonexistent app %q", *cfg.AppName) } if cfg.PodPID > 0 { // Call app-stop and app-rm entrypoint only if the pod is still running. // Otherwise, there's not much we can do about it except unmounting/removing // the file system. args := []string{ fmt.Sprintf("--app=%s", cfg.AppName), } ce := CrossingEntrypoint{ PodPath: cfg.PodPath, PodPID: cfg.PodPID, AppName: cfg.AppName.String(), EntrypointName: appStopEntrypoint, EntrypointArgs: args, Interactive: false, } if err := ce.Run(); err != nil { status, err := common.GetExitStatus(err) // ignore nonexistent units failing to stop. Exit status 5 // comes from systemctl and means the unit doesn't exist if err != nil { return err } else if status != 5 { return fmt.Errorf("exit status %d", status) } } ce.EntrypointName = appRmEntrypoint if err := ce.Run(); err != nil { return err } } if cfg.UsesOverlay { treeStoreID, err := ioutil.ReadFile(common.AppTreeStoreIDPath(cfg.PodPath, *cfg.AppName)) if err != nil { return err } appRootfs := common.AppRootfsPath(cfg.PodPath, *cfg.AppName) if err := syscall.Unmount(appRootfs, 0); err != nil { return err } ts := filepath.Join(cfg.PodPath, "overlay", string(treeStoreID)) if err := os.RemoveAll(ts); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } } appInfoDir := common.AppInfoPath(cfg.PodPath, *cfg.AppName) if err := os.RemoveAll(appInfoDir); err != nil { return errwrap.Wrap(errors.New("error removing app info directory"), err) } if err := os.RemoveAll(common.AppPath(cfg.PodPath, *cfg.AppName)); err != nil { return err } appStatusPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "status", cfg.AppName.String()) if err := os.Remove(appStatusPath); err != nil && !os.IsNotExist(err) { return err } envPath := filepath.Join(common.Stage1RootfsPath(cfg.PodPath), "rkt", "env", cfg.AppName.String()) if err := os.Remove(envPath); err != nil && !os.IsNotExist(err) { return err } removeAppFromPodManifest(pm, cfg.AppName) if err := updatePodManifest(cfg.PodPath, pm); err != nil { return err } return nil }