Ejemplo n.º 1
0
// getAppName returns the app name to enter
// If one was supplied in the flags then it's simply returned
// If the PM contains a single app, that app's name is returned
// If the PM has multiple apps, the names are printed and an error is returned
func getAppName(p *pkgPod.Pod) (*types.ACName, error) {
	if flagAppName != "" {
		return types.NewACName(flagAppName)
	}

	// figure out the app name, or show a list if multiple are present
	_, m, err := p.PodManifest()
	if err != nil {
		return nil, errwrap.Wrap(errors.New("error reading pod manifest"), err)
	}

	switch len(m.Apps) {
	case 0:
		return nil, fmt.Errorf("pod contains zero apps")
	case 1:
		return &m.Apps[0].Name, nil
	default:
	}

	stderr.Print("pod contains multiple apps:")
	for _, ra := range m.Apps {
		stderr.Printf("\t%v", ra.Name)
	}

	return nil, fmt.Errorf("specify app using \"rkt enter --app= ...\"")
}
Ejemplo n.º 2
0
func getPodManifestModTime(p *pkgPod.Pod) (time.Time, error) {
	podFile := filepath.Join(p.Path(), "pod")
	fi, err := os.Stat(podFile)
	if err != nil {
		return time.Time{}, err
	}
	return fi.ModTime(), nil
}
Ejemplo n.º 3
0
func getImageName(p *pkgPod.Pod, appName types.ACName) (string, error) {
	aim, err := p.AppImageManifest(appName.String())
	if err != nil {
		return "", errwrap.Wrap(errors.New("problem retrieving ImageManifests from pod"), err)
	}

	imageName := aim.Name.String()
	if version, ok := aim.Labels.Get("version"); ok {
		imageName = fmt.Sprintf("%s:%s", imageName, version)
	}

	return imageName, nil
}
Ejemplo n.º 4
0
func (s *v1AlphaAPIServer) getBasicPodFromDisk(p *pkgPod.Pod) (*v1alpha.Pod, error) {
	pod := &v1alpha.Pod{Id: p.UUID.String()}

	data, manifest, err := p.PodManifest()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("failed to get the pod manifest for pod %q", p.UUID), err)
	} else {
		pod.Annotations = convertAnnotationsToKeyValue(manifest.Annotations)
		pod.Apps = getApplist(manifest)
		pod.Manifest = data
		err = fillStaticAppInfo(s.store, p, pod)
	}

	return pod, err
}
Ejemplo n.º 5
0
// getExitStatuses returns a map of the statuses of the pod.
func getExitStatuses(p *pkgPod.Pod) (map[string]int, error) {
	_, manifest, err := p.PodManifest()
	if err != nil {
		return nil, err
	}

	stats := make(map[string]int)
	for _, app := range manifest.Apps {
		exitCode, err := p.AppExitCode(app.Name.String())
		if err != nil {
			continue
		}
		stats[app.Name.String()] = exitCode
	}
	return stats, nil
}
Ejemplo n.º 6
0
// getPodCgroup gets the cgroup path for a pod. This can be done in one of a couple ways:
//
// 1) stage1-coreos
//
// This one can be tricky because after machined registration, the cgroup might change.
// For these flavors, the cgroup it will end up in after machined moves it is
// written to a file named `subcgroup`, so we use that instead.
//
// 2) All others
//
// Assume that we can simply get the cgroup of the pod's init PID, and use that.
func getPodCgroup(p *pkgPod.Pod, pid int) (string, error) {
	// Note, this file should always exist if the pid is known since it is
	// written before the pid file
	// The contents are of the form:
	// machined-registration (whether it has happened or not, but if stage1 plans to do so):
	//   'machine.slice/machine-rkt\x2dbfb67ff1\x2dc745\x2d4aec\x2db1e1\x2d7ce85a1fd42b.scope'
	// no registration, ran as systemd-unit 'foo.service':
	//   'system.slice/foo.service'
	// stage1-fly: file does not exist
	subCgroupFile := filepath.Join(p.Path(), "subcgroup")
	data, err := ioutil.ReadFile(subCgroupFile)
	// normalize cgroup to include a leading '/'
	if err == nil {
		strCgroup := string(data)
		if strings.HasPrefix(strCgroup, "/") {
			return strCgroup, nil
		}
		return "/" + strCgroup, nil
	}

	if !os.IsNotExist(err) {
		return "", err
	}
	// if it is an "isNotExist", assume this is a stage1 flavor that won't change
	// cgroups. Just give the systemd cgroup of its pid
	// Get cgroup for the "name=systemd" controller; we assume the api-server is
	// running on a system using systemd for returning cgroups, and will just not
	// set it otherwise.
	cgroup, err := v1.GetCgroupPathByPid(pid, "name=systemd")
	if err != nil {
		return "", err
	}
	// If the stage1 systemd > v226, it will put the PID1 into "init.scope"
	// implicit scope unit in the root slice.
	// See https://github.com/coreos/rkt/pull/2331#issuecomment-203540543
	//
	// TODO(yifan): Revisit this when using unified cgroup hierarchy.
	cgroup = strings.TrimSuffix(cgroup, "/init.scope")
	return cgroup, nil
}
Ejemplo n.º 7
0
Archivo: export.go Proyecto: nhlfr/rkt
// mountOverlay mounts the app from the overlay-rendered pod to the destination directory.
func mountOverlay(pod *pkgPod.Pod, app *schema.RuntimeApp, dest string) error {
	if _, err := os.Stat(dest); err != nil {
		return err
	}

	s, err := imagestore.NewStore(getDataDir())
	if err != nil {
		return errwrap.Wrap(errors.New("cannot open store"), err)
	}

	ts, err := treestore.NewStore(treeStoreDir(), s)
	if err != nil {
		return errwrap.Wrap(errors.New("cannot open treestore"), err)
	}

	treeStoreID, err := pod.GetAppTreeStoreID(app.Name)
	if err != nil {
		return err
	}
	lower := ts.GetRootFS(treeStoreID)
	imgDir := filepath.Join(filepath.Join(pod.Path(), "overlay"), treeStoreID)
	if _, err := os.Stat(imgDir); err != nil {
		return err
	}
	upper := filepath.Join(imgDir, "upper", app.Name.String())
	if _, err := os.Stat(upper); err != nil {
		return err
	}
	work := filepath.Join(imgDir, "work", app.Name.String())
	if _, err := os.Stat(work); err != nil {
		return err
	}

	if err := overlay.Mount(&overlay.MountCfg{lower, upper, work, dest, ""}); err != nil {
		return errwrap.Wrap(errors.New("problem mounting overlayfs directory"), err)
	}

	return nil
}
Ejemplo n.º 8
0
// fillStaticAppInfo will modify the 'v1pod' in place with the information retrieved with 'pod'.
// Today, these information are static and will not change during the pod's lifecycle.
func fillStaticAppInfo(store *imagestore.Store, pod *pkgPod.Pod, v1pod *v1alpha.Pod) error {
	var errlist []error

	// Fill static app image info.
	for _, app := range v1pod.Apps {
		// Fill app's image info.
		app.Image = &v1alpha.Image{
			BaseFormat: &v1alpha.ImageFormat{
				// Only support appc image now. If it's a docker image, then it
				// will be transformed to appc before storing in the disk store.
				Type:    v1alpha.ImageType_IMAGE_TYPE_APPC,
				Version: schema.AppContainerVersion.String(),
			},
			Id: app.Image.Id,
			// Other information are not available because they require the image
			// info from store. Some of it is filled in below if possible.
		}

		im, err := pod.AppImageManifest(app.Name)
		if err != nil {
			stderr.PrintE(fmt.Sprintf("failed to get image manifests for app %q", app.Name), err)
			errlist = append(errlist, err)
		} else {
			app.Image.Name = im.Name.String()

			version, ok := im.Labels.Get("version")
			if !ok {
				version = "latest"
			}
			app.Image.Version = version
		}
	}

	if len(errlist) != 0 {
		return errs{errlist}
	}
	return nil
}
Ejemplo n.º 9
0
// NewPodFromInternalPod converts *pkgPod.Pod to *Pod
func NewPodFromInternalPod(p *pkgPod.Pod) (*Pod, error) {
	pod := &Pod{
		UUID:     p.UUID.String(),
		State:    p.State(),
		Networks: p.Nets,
	}

	startTime, err := p.StartTime()
	if err != nil {
		return nil, err
	}

	if !startTime.IsZero() {
		startedAt := startTime.Unix()
		pod.StartedAt = &startedAt
	}

	if !p.PodManifestAvailable() {
		return pod, nil
	}
	// TODO(vc): we should really hold a shared lock here to prevent gc of the pod
	_, manifest, err := p.PodManifest()
	if err != nil {
		return nil, err
	}

	for _, app := range manifest.Apps {
		pod.AppNames = append(pod.AppNames, app.Name.String())
	}

	if len(manifest.UserAnnotations) > 0 {
		pod.UserAnnotations = make(map[string]string)
		for name, value := range manifest.UserAnnotations {
			pod.UserAnnotations[name] = value
		}
	}

	if len(manifest.UserLabels) > 0 {
		pod.UserLabels = make(map[string]string)
		for name, value := range manifest.UserLabels {
			pod.UserLabels[name] = value
		}
	}

	return pod, nil
}
Ejemplo n.º 10
0
Archivo: export.go Proyecto: nhlfr/rkt
// getApp returns the app to export
// If one was supplied in the flags then it's returned if present
// If the PM contains a single app, that app is returned
// If the PM has multiple apps, the names are printed and an error is returned
func getApp(p *pkgPod.Pod) (*schema.RuntimeApp, error) {
	_, manifest, err := p.PodManifest()
	if err != nil {
		return nil, errwrap.Wrap(errors.New("problem getting the pod's manifest"), err)
	}

	apps := manifest.Apps

	if flagExportAppName != "" {
		exportAppName, err := types.NewACName(flagExportAppName)
		if err != nil {
			return nil, err
		}
		for _, ra := range apps {
			if *exportAppName == ra.Name {
				return &ra, nil
			}
		}
		return nil, fmt.Errorf("app %s is not present in pod", flagExportAppName)
	}

	switch len(apps) {
	case 0:
		return nil, fmt.Errorf("pod contains zero apps")
	case 1:
		return &apps[0], nil
	default:
	}

	stderr.Print("pod contains multiple apps:")
	for _, ra := range apps {
		stderr.Printf("\t%v", ra.Name)
	}

	return nil, fmt.Errorf("specify app using \"rkt export --app= ...\"")
}
Ejemplo n.º 11
0
Archivo: gc.go Proyecto: nhlfr/rkt
func mountPodStage1(ts *treestore.Store, p *pkgPod.Pod) error {
	if !p.UsesOverlay() {
		return nil
	}

	s1Id, err := p.GetStage1TreeStoreID()
	if err != nil {
		return errwrap.Wrap(errors.New("error getting stage1 treeStoreID"), err)
	}
	s1rootfs := ts.GetRootFS(s1Id)

	stage1Dir := common.Stage1RootfsPath(p.Path())
	overlayDir := filepath.Join(p.Path(), "overlay")
	imgDir := filepath.Join(overlayDir, s1Id)
	upperDir := filepath.Join(imgDir, "upper")
	workDir := filepath.Join(imgDir, "work")

	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", s1rootfs, upperDir, workDir)
	if err := syscall.Mount("overlay", stage1Dir, "overlay", 0, opts); err != nil {
		return errwrap.Wrap(errors.New("error mounting stage1"), err)
	}

	return nil
}
Ejemplo n.º 12
0
Archivo: app.go Proyecto: kinvolk/rkt
func appState(app *App, pod *pkgPod.Pod) error {
	app.State = AppStateUnknown

	defer func() {
		if pod.IsAfterRun() {
			// If the pod is hard killed, set the app to 'exited' state.
			// Other than this case, status file is guaranteed to be written.
			if app.State != AppStateExited {
				app.State = AppStateExited
				t, err := pod.GCMarkedTime()
				if err != nil {
					fmt.Fprintf(os.Stderr, "Cannot get GC marked time: %v", err)
				}
				if !t.IsZero() {
					finishedAt := t.UnixNano()
					app.FinishedAt = &finishedAt
				}
			}
		}
	}()

	// Check if the app is created.
	fi, err := os.Stat(common.AppCreatedPath(pod.Path(), app.Name))
	if err != nil {
		if !os.IsNotExist(err) {
			return fmt.Errorf("cannot stat app creation file: %v", err)
		}
		return nil
	}

	app.State = AppStateCreated
	createdAt := fi.ModTime().UnixNano()
	app.CreatedAt = &createdAt

	// Check if the app is started.
	fi, err = os.Stat(common.AppStartedPath(pod.Path(), app.Name))
	if err != nil {
		if !os.IsNotExist(err) {
			return fmt.Errorf("cannot stat app started file: %v", err)
		}
		return nil
	}

	app.State = AppStateRunning
	startedAt := fi.ModTime().UnixNano()
	app.StartedAt = &startedAt

	// Check if the app is exited.
	appStatusFile := common.AppStatusPath(pod.Path(), app.Name)
	fi, err = os.Stat(appStatusFile)
	if err != nil {
		if !os.IsNotExist(err) {
			return fmt.Errorf("cannot stat app exited file: %v", err)
		}
		return nil
	}

	app.State = AppStateExited
	finishedAt := fi.ModTime().UnixNano()
	app.FinishedAt = &finishedAt

	// Read exit code.
	exitCode, err := readExitCode(appStatusFile)
	if err != nil {
		return err
	}
	app.ExitCode = &exitCode

	return nil
}
Ejemplo n.º 13
0
Archivo: gc.go Proyecto: nhlfr/rkt
// deletePod cleans up files and resource associated with the pod
// pod must be under exclusive lock and be in either ExitedGarbage
// or Garbage state
func deletePod(p *pkgPod.Pod) {
	podState := p.State()
	if podState != pkgPod.ExitedGarbage && podState != pkgPod.Garbage {
		stderr.Panicf("logic error: deletePod called with non-garbage pod %q (status %q)", p.UUID, p.State())
	}

	if podState == pkgPod.ExitedGarbage {
		s, err := imagestore.NewStore(storeDir())
		if err != nil {
			stderr.PrintE("cannot open store", err)
			return
		}
		defer s.Close()

		ts, err := treestore.NewStore(treeStoreDir(), s)
		if err != nil {
			stderr.PrintE("cannot open store", err)
			return
		}

		if globalFlags.Debug {
			stage0.InitDebug()
		}

		if err := mountPodStage1(ts, p); err == nil {
			if err = stage0.GC(p.Path(), p.UUID); err != nil {
				stderr.PrintE(fmt.Sprintf("problem performing stage1 GC on %q", p.UUID), err)
			}
			// an overlay fs can be mounted over itself, let's unmount it here
			// if we mounted it before to avoid problems when running
			// stage0.MountGC
			if p.UsesOverlay() {
				stage1Mnt := common.Stage1RootfsPath(p.Path())
				if err := syscall.Unmount(stage1Mnt, 0); err != nil {
					stderr.PrintE("error unmounting stage1", err)
				}
			}
		} else {
			stderr.PrintE("skipping stage1 GC", err)
		}

		// unmount all leftover mounts
		if err := stage0.MountGC(p.Path(), p.UUID.String()); err != nil {
			stderr.PrintE(fmt.Sprintf("GC of leftover mounts for pod %q failed", p.UUID), err)
			return
		}
	}

	if err := os.RemoveAll(p.Path()); err != nil {
		stderr.PrintE(fmt.Sprintf("unable to remove pod %q", p.UUID), err)
		os.Exit(254)
	}
}
Ejemplo n.º 14
0
// fillPodDetails fills the v1pod's dynamic info in place, e.g. the pod's state,
// the pod's network info, the apps' state, etc. Such information can change
// during the lifecycle of the pod, so we need to read it in every request.
func fillPodDetails(store *imagestore.Store, p *pkgPod.Pod, v1pod *v1alpha.Pod) {
	v1pod.Pid = -1

	switch p.State() {
	case pkgPod.Embryo:
		v1pod.State = v1alpha.PodState_POD_STATE_EMBRYO
		// When a pod is in embryo state, there is not much
		// information to return.
		return
	case pkgPod.Preparing:
		v1pod.State = v1alpha.PodState_POD_STATE_PREPARING
	case pkgPod.AbortedPrepare:
		v1pod.State = v1alpha.PodState_POD_STATE_ABORTED_PREPARE
	case pkgPod.Prepared:
		v1pod.State = v1alpha.PodState_POD_STATE_PREPARED
	case pkgPod.Running:
		v1pod.State = v1alpha.PodState_POD_STATE_RUNNING
		v1pod.Networks = getNetworks(p)
	case pkgPod.Deleting:
		v1pod.State = v1alpha.PodState_POD_STATE_DELETING
	case pkgPod.Exited:
		v1pod.State = v1alpha.PodState_POD_STATE_EXITED
	case pkgPod.Garbage, pkgPod.ExitedGarbage:
		v1pod.State = v1alpha.PodState_POD_STATE_GARBAGE
	default:
		v1pod.State = v1alpha.PodState_POD_STATE_UNDEFINED
		return
	}

	createdAt, err := p.CreationTime()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("failed to get the creation time for pod %q", p.UUID), err)
	} else if !createdAt.IsZero() {
		v1pod.CreatedAt = createdAt.UnixNano()
	}

	startedAt, err := p.StartTime()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("failed to get the start time for pod %q", p.UUID), err)
	} else if !startedAt.IsZero() {
		v1pod.StartedAt = startedAt.UnixNano()

	}

	gcMarkedAt, err := p.GCMarkedTime()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("failed to get the gc marked time for pod %q", p.UUID), err)
	} else if !gcMarkedAt.IsZero() {
		v1pod.GcMarkedAt = gcMarkedAt.UnixNano()
	}

	pid, err := p.Pid()
	if err != nil {
		stderr.PrintE(fmt.Sprintf("failed to get the PID for pod %q", p.UUID), err)
	} else {
		v1pod.Pid = int32(pid)
	}

	if v1pod.State == v1alpha.PodState_POD_STATE_RUNNING {
		pid, err := p.ContainerPid1()
		if err != nil {
			stderr.PrintE(fmt.Sprintf("failed to get the container PID1 for pod %q", p.UUID), err)
		} else {
			cgroup, err := getPodCgroup(p, pid)
			if err != nil {
				stderr.PrintE(fmt.Sprintf("failed to get the cgroup path for pod %q", p.UUID), err)
			} else {
				v1pod.Cgroup = cgroup
			}
		}
	}

	for _, app := range v1pod.Apps {
		readStatus := false

		if p.State() == pkgPod.Running {
			readStatus = true
			app.State = v1alpha.AppState_APP_STATE_RUNNING
		} else if p.AfterRun() {
			readStatus = true
			app.State = v1alpha.AppState_APP_STATE_EXITED
		} else {
			app.State = v1alpha.AppState_APP_STATE_UNDEFINED
		}

		if readStatus {
			exitCode, err := p.AppExitCode(app.Name)
			if err != nil {
				stderr.PrintE(fmt.Sprintf("failed to read status for app %q", app.Name), err)
			}
			app.ExitCode = int32(exitCode)
		}
	}
}
Ejemplo n.º 15
0
// printStatus prints the pod's pid and per-app status codes
func printStatus(p *pkgPod.Pod) error {
	if flagFormat != outputFormatTabbed {
		pod, err := lib.NewPodFromInternalPod(p)
		if err != nil {
			return fmt.Errorf("error converting pod: %v", err)
		}
		switch flagFormat {
		case outputFormatJSON:
			result, err := json.Marshal(pod)
			if err != nil {
				return fmt.Errorf("error marshaling the pod: %v", err)
			}
			stdout.Print(string(result))
		case outputFormatPrettyJSON:
			result, err := json.MarshalIndent(pod, "", "\t")
			if err != nil {
				return fmt.Errorf("error marshaling the pod: %v", err)
			}
			stdout.Print(string(result))
		}
		return nil
	}

	state := p.State()
	stdout.Printf("state=%s", state)

	created, err := p.CreationTime()
	if err != nil {
		return fmt.Errorf("unable to get creation time for pod %q: %v", p.UUID, err)
	}
	createdStr := created.Format(defaultTimeLayout)

	stdout.Printf("created=%s", createdStr)

	started, err := p.StartTime()
	if err != nil {
		return fmt.Errorf("unable to get start time for pod %q: %v", p.UUID, err)
	}
	var startedStr string
	if !started.IsZero() {
		startedStr = started.Format(defaultTimeLayout)
		stdout.Printf("started=%s", startedStr)
	}

	if state == pkgPod.Running {
		stdout.Printf("networks=%s", fmtNets(p.Nets))
	}

	if state == pkgPod.Running || state == pkgPod.Deleting || state == pkgPod.ExitedDeleting || state == pkgPod.Exited || state == pkgPod.ExitedGarbage {
		var pid int
		pidCh := make(chan int, 1)

		// Wait slightly because the pid file might not be written yet when the state changes to 'Running'.
		go func() {
			for {
				pid, err := p.Pid()
				if err == nil {
					pidCh <- pid
					return
				}
				time.Sleep(time.Millisecond * 100)
			}
		}()

		select {
		case pid = <-pidCh:
		case <-time.After(time.Second):
			return fmt.Errorf("unable to get PID for pod %q: %v", p.UUID, err)
		}

		stdout.Printf("pid=%d\nexited=%t", pid, (state == pkgPod.Exited || state == pkgPod.ExitedGarbage))

		if state != pkgPod.Running {
			stats, err := getExitStatuses(p)
			if err != nil {
				return fmt.Errorf("unable to get exit statuses for pod %q: %v", p.UUID, err)
			}
			for app, stat := range stats {
				stdout.Printf("app-%s=%d", app, stat)
			}
		}
	}
	return nil
}
Ejemplo n.º 16
0
Archivo: status.go Proyecto: nhlfr/rkt
// printStatus prints the pod's pid and per-app status codes
func printStatus(p *pkgPod.Pod) error {
	state := p.State()
	stdout.Printf("state=%s", state)

	created, err := p.CreationTime()
	if err != nil {
		return fmt.Errorf("unable to get creation time for pod %q: %v", p.UUID, err)
	}
	createdStr := created.Format(defaultTimeLayout)

	stdout.Printf("created=%s", createdStr)

	started, err := p.StartTime()
	if err != nil {
		return fmt.Errorf("unable to get start time for pod %q: %v", p.UUID, err)
	}
	var startedStr string
	if !started.IsZero() {
		startedStr = started.Format(defaultTimeLayout)
		stdout.Printf("started=%s", startedStr)
	}

	if state == pkgPod.Running {
		stdout.Printf("networks=%s", fmtNets(p.Nets))
	}

	if state == pkgPod.Running || state == pkgPod.Deleting || state == pkgPod.ExitedDeleting || state == pkgPod.Exited || state == pkgPod.ExitedGarbage {
		var pid int
		pidCh := make(chan int, 1)

		// Wait slightly because the pid file might not be written yet when the state changes to 'Running'.
		go func() {
			for {
				pid, err := p.Pid()
				if err == nil {
					pidCh <- pid
					return
				}
				time.Sleep(time.Millisecond * 100)
			}
		}()

		select {
		case pid = <-pidCh:
		case <-time.After(time.Second):
			return fmt.Errorf("unable to get PID for pod %q: %v", p.UUID, err)
		}

		stdout.Printf("pid=%d\nexited=%t", pid, (state == pkgPod.Exited || state == pkgPod.ExitedGarbage))

		if state != pkgPod.Running {
			stats, err := getExitStatuses(p)
			if err != nil {
				return fmt.Errorf("unable to get exit statuses for pod %q: %v", p.UUID, err)
			}
			for app, stat := range stats {
				stdout.Printf("app-%s=%d", app, stat)
			}
		}
	}
	return nil
}