Example #1
0
// Run wraps the execution of a stage1 entrypoint which
// requires crossing the stage0/stage1/stage2 boundary during its execution,
// by setting up proper environment variables for enter.
func (ce CrossingEntrypoint) Run() error {
	enterCmd, err := getStage1Entrypoint(ce.PodPath, enterEntrypoint)
	if err != nil {
		return errwrap.Wrap(errors.New("error determining 'enter' entrypoint"), err)
	}

	previousDir, err := os.Getwd()
	if err != nil {
		return err
	}

	if err := os.Chdir(ce.PodPath); err != nil {
		return errwrap.Wrap(errors.New("failed changing to dir"), err)
	}

	ep, err := getStage1Entrypoint(ce.PodPath, ce.EntrypointName)
	if err != nil {
		return fmt.Errorf("%q not implemented for pod's stage1: %v", ce.EntrypointName, err)
	}
	execArgs := []string{filepath.Join(common.Stage1RootfsPath(ce.PodPath), ep)}
	execArgs = append(execArgs, ce.EntrypointArgs...)

	pathEnv := os.Getenv("PATH")
	if pathEnv == "" {
		pathEnv = common.DefaultPath
	}
	execEnv := []string{
		fmt.Sprintf("%s=%s", common.CrossingEnterCmd, filepath.Join(common.Stage1RootfsPath(ce.PodPath), enterCmd)),
		fmt.Sprintf("%s=%d", common.CrossingEnterPID, ce.PodPID),
		fmt.Sprintf("PATH=%s", pathEnv),
	}

	c := exec.Cmd{
		Path: execArgs[0],
		Args: execArgs,
		Env:  execEnv,
	}

	if ce.Interactive {
		c.Stdin = os.Stdin
		c.Stdout = os.Stdout
		c.Stderr = os.Stderr
		if err := c.Run(); err != nil {
			return fmt.Errorf("error executing stage1 entrypoint: %v", err)
		}
	} else {
		out, err := c.CombinedOutput()
		if err != nil {
			return fmt.Errorf("error executing stage1 entrypoint: %s", string(out))
		}
	}

	if err := os.Chdir(previousDir); err != nil {
		return errwrap.Wrap(errors.New("failed changing to dir"), err)
	}

	return nil
}
Example #2
0
/*
 Bind-mount the hosts /etc/hosts in to the stage1's /etc/rkt-hosts
 That file will then be bind-mounted in to the stage2 by perpare-app.c
*/
func UseHostHosts(mnt fs.MountUnmounter, podRoot string) error {
	return BindMount(
		mnt,
		"/etc/hosts",
		filepath.Join(_common.Stage1RootfsPath(podRoot), "etc/rkt-hosts"),
		true)
}
Example #3
0
/*
 Bind-mount the hosts /etc/resolv.conf in to the stage1's /etc/rkt-resolv.conf.
 That file will then be bind-mounted in to the stage2 by perpare-app.c
*/
func UseHostResolv(mnt fs.MountUnmounter, podRoot string) error {
	return BindMount(
		mnt,
		"/etc/resolv.conf",
		filepath.Join(_common.Stage1RootfsPath(podRoot), "etc/rkt-resolv.conf"),
		true)
}
Example #4
0
// Loads nets specified by user and default one from stage1
func (e *podEnv) loadNets() ([]activeNet, error) {
	nets, err := loadUserNets(e.localConfig, e.netsLoadList)
	if err != nil {
		return nil, err
	}

	if e.netsLoadList.None() {
		return nets, nil
	}

	if !netExists(nets, "default") && !netExists(nets, "default-restricted") {
		var defaultNet string
		if e.netsLoadList.Specific("default") || e.netsLoadList.All() {
			defaultNet = DefaultNetPath
		} else {
			defaultNet = DefaultRestrictedNetPath
		}
		defPath := path.Join(common.Stage1RootfsPath(e.podRoot), defaultNet)
		n, err := loadNet(defPath)
		if err != nil {
			return nil, err
		}
		nets = append(nets, *n)
	}

	missing := missingNets(e.netsLoadList, nets)
	if len(missing) > 0 {
		return nil, fmt.Errorf("networks not found: %v", strings.Join(missing, ", "))
	}

	return nets, nil
}
Example #5
0
File: main.go Project: nak3/rkt
func copyResolv(p *stage1commontypes.Pod) error {
	ra := p.Manifest.Apps[0]

	stage1Rootfs := common.Stage1RootfsPath(p.Root)
	resolvPath := filepath.Join(stage1Rootfs, "etc", "rkt-resolv.conf")

	appRootfs := common.AppRootfsPath(p.Root, ra.Name)
	targetEtc := filepath.Join(appRootfs, "etc")
	targetResolvPath := filepath.Join(targetEtc, "resolv.conf")

	_, err := os.Stat(resolvPath)
	switch {
	case os.IsNotExist(err):
		return nil
	case err != nil:
		return err
	}

	_, err = os.Stat(targetResolvPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	return fileutil.CopyRegularFile(resolvPath, targetResolvPath)
}
Example #6
0
// mirrorLocalZoneInfo tries to reproduce the /etc/localtime target in stage1/ to satisfy systemd-nspawn
func mirrorLocalZoneInfo(root string) {
	zif, err := os.Readlink(localtimePath)
	if err != nil {
		return
	}

	// On some systems /etc/localtime is a relative symlink, make it absolute
	if !filepath.IsAbs(zif) {
		zif = filepath.Join(filepath.Dir(localtimePath), zif)
		zif = filepath.Clean(zif)
	}

	src, err := os.Open(zif)
	if err != nil {
		return
	}
	defer src.Close()

	destp := filepath.Join(common.Stage1RootfsPath(root), zif)

	if err = os.MkdirAll(filepath.Dir(destp), 0755); err != nil {
		return
	}

	dest, err := os.OpenFile(destp, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return
	}
	defer dest.Close()

	_, _ = io.Copy(dest, src)
}
Example #7
0
func gcNetworking(podID *types.UUID) error {
	var flavor string
	// we first try to read the flavor from stage1 for backwards compatibility
	flavor, err := os.Readlink(filepath.Join(common.Stage1RootfsPath("."), "flavor"))
	if err != nil {
		// if we couldn't read the flavor from stage1 it could mean the overlay
		// filesystem is already unmounted (e.g. the system has been rebooted).
		// In that case we try to read it from the pod's root directory
		flavor, err = os.Readlink("flavor")
		if err != nil {
			return errwrap.Wrap(errors.New("failed to get stage1 flavor"), err)
		}
	}

	n, err := networking.Load(".", podID)
	switch {
	case err == nil:
		n.Teardown(flavor, debug)
	case os.IsNotExist(err):
		// probably ran with --net=host
	default:
		return errwrap.Wrap(errors.New("failed loading networking state"), err)
	}

	return nil
}
Example #8
0
File: pod.go Project: aaronlevy/rkt
// PodToSystemd creates the appropriate systemd service unit files for
// all the constituent apps of the Pod
func (p *Pod) PodToSystemd(interactive bool, flavor string, privateUsers string) error {

	if flavor == "kvm" {
		// prepare all applications names to become dependency for mount units
		// all host-shared folder has to become available before applications starts
		var appNames []types.ACName
		for _, runtimeApp := range p.Manifest.Apps {
			appNames = append(appNames, runtimeApp.Name)
		}

		// mount host volumes through some remote file system e.g. 9p to /mnt/volumeName location
		// order is important here: podToSystemHostMountUnits prepares folders that are checked by each appToSystemdMountUnits later
		err := kvm.PodToSystemdHostMountUnits(common.Stage1RootfsPath(p.Root), p.Manifest.Volumes, appNames, unitsDir)
		if err != nil {
			return fmt.Errorf("failed to transform pod volumes into mount units: %v", err)
		}
	}

	for i := range p.Manifest.Apps {
		ra := &p.Manifest.Apps[i]
		if err := p.appToSystemd(ra, interactive, flavor, privateUsers); err != nil {
			return fmt.Errorf("failed to transform app %q into systemd service: %v", ra.Name, err)
		}
	}
	return nil
}
Example #9
0
// GC enters the pod by fork/exec()ing the stage1's /gc similar to /init.
// /gc can expect to have its CWD set to the pod root.
func GC(pdir string, uuid *types.UUID) error {
	err := unregisterPod(pdir, uuid)
	if err != nil {
		// Probably not worth abandoning the rest
		log.PrintE("warning: could not unregister pod with metadata service", err)
	}

	stage1Path := common.Stage1RootfsPath(pdir)

	ep, err := getStage1Entrypoint(pdir, gcEntrypoint)
	if err != nil {
		return errwrap.Wrap(errors.New("error determining 'gc' entrypoint"), err)
	}

	args := []string{filepath.Join(stage1Path, ep)}
	if debugEnabled {
		args = append(args, "--debug")
	}
	args = append(args, uuid.String())

	c := exec.Cmd{
		Path:   args[0],
		Args:   args,
		Stderr: os.Stderr,
		Dir:    pdir,
	}
	return c.Run()
}
Example #10
0
File: pod.go Project: matomesc/rkt
// WritePrepareAppTemplate writes service unit files for preparing the pod's applications
func WritePrepareAppTemplate(p *stage1commontypes.Pod) error {
	opts := []*unit.UnitOption{
		unit.NewUnitOption("Unit", "Description", "Prepare minimum environment for chrooted applications"),
		unit.NewUnitOption("Unit", "DefaultDependencies", "false"),
		unit.NewUnitOption("Unit", "OnFailureJobMode", "fail"),
		unit.NewUnitOption("Unit", "Requires", "systemd-journald.service"),
		unit.NewUnitOption("Unit", "After", "systemd-journald.service"),
		unit.NewUnitOption("Service", "Type", "oneshot"),
		unit.NewUnitOption("Service", "Restart", "no"),
		unit.NewUnitOption("Service", "ExecStart", "/prepare-app %I"),
		unit.NewUnitOption("Service", "User", "0"),
		unit.NewUnitOption("Service", "Group", "0"),
		unit.NewUnitOption("Service", "CapabilityBoundingSet", "CAP_SYS_ADMIN CAP_DAC_OVERRIDE"),
	}

	unitsPath := filepath.Join(common.Stage1RootfsPath(p.Root), UnitsDir)
	file, err := os.OpenFile(filepath.Join(unitsPath, "[email protected]"), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("failed to create service unit file: %v", err)
	}
	defer file.Close()

	if _, err = io.Copy(file, unit.Serialize(opts)); err != nil {
		return fmt.Errorf("failed to write service unit file: %v", err)
	}

	return nil
}
Example #11
0
File: pod.go Project: matomesc/rkt
func writeAppReaper(p *stage1commontypes.Pod, appName string) error {
	opts := []*unit.UnitOption{
		unit.NewUnitOption("Unit", "Description", fmt.Sprintf("%s Reaper", appName)),
		unit.NewUnitOption("Unit", "DefaultDependencies", "false"),
		unit.NewUnitOption("Unit", "StopWhenUnneeded", "yes"),
		unit.NewUnitOption("Unit", "Wants", "shutdown.service"),
		unit.NewUnitOption("Unit", "After", "shutdown.service"),
		unit.NewUnitOption("Unit", "Conflicts", "exit.target"),
		unit.NewUnitOption("Unit", "Conflicts", "halt.target"),
		unit.NewUnitOption("Unit", "Conflicts", "poweroff.target"),
		unit.NewUnitOption("Service", "RemainAfterExit", "yes"),
		unit.NewUnitOption("Service", "ExecStop", fmt.Sprintf("/reaper.sh %s", appName)),
	}

	unitsPath := filepath.Join(common.Stage1RootfsPath(p.Root), UnitsDir)
	file, err := os.OpenFile(filepath.Join(unitsPath, fmt.Sprintf("reaper-%s.service", appName)), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("failed to create service unit file: %v", err)
	}
	defer file.Close()

	if _, err = io.Copy(file, unit.Serialize(opts)); err != nil {
		return fmt.Errorf("failed to write service unit file: %v", err)
	}

	return nil
}
Example #12
0
func NewBuilder(podRoot string, podUUID *types.UUID) (*Builder, error) {
	pod, err := stage1commontypes.LoadPod(podRoot, podUUID)
	if err != nil {
		logs.WithError(err).Fatal("Failed to load pod")
	}
	if len(pod.Manifest.Apps) != 1 {
		logs.Fatal("dgr builder support only 1 application")
	}

	fields := data.WithField("aci", manifestApp(pod).Name)

	aciPath, ok := manifestApp(pod).App.Environment.Get(common.EnvAciPath)
	if !ok || aciPath == "" {
		return nil, errs.WithF(fields, "Builder image require "+common.EnvAciPath+" environment variable")
	}
	aciTarget, ok := manifestApp(pod).App.Environment.Get(common.EnvAciTarget)
	if !ok || aciPath == "" {
		return nil, errs.WithF(fields, "Builder image require "+common.EnvAciTarget+" environment variable")
	}

	return &Builder{
		fields:        fields,
		aciHomePath:   aciPath,
		aciTargetPath: aciTarget,
		pod:           pod,
		stage1Rootfs:  rktcommon.Stage1RootfsPath(pod.Root),
		stage2Rootfs:  filepath.Join(rktcommon.AppPath(pod.Root, manifestApp(pod).Name), "rootfs"),
	}, nil
}
Example #13
0
func StopPod(dir string, force bool, uuid *types.UUID) error {
	s1rootfs := common.Stage1RootfsPath(dir)

	if err := os.Chdir(dir); err != nil {
		return fmt.Errorf("failed changing to dir: %v", err)
	}

	ep, err := getStage1Entrypoint(dir, stopEntrypoint)
	if err != nil {
		return fmt.Errorf("rkt stop not implemented for pod's stage1: %v", err)
	}
	args := []string{filepath.Join(s1rootfs, ep)}
	debug("Execing %s", ep)

	if force {
		args = append(args, "--force")
	}

	args = append(args, uuid.String())

	c := exec.Cmd{
		Path:   args[0],
		Args:   args,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}

	return c.Run()
}
Example #14
0
func (e *podEnv) pluginPaths() []string {
	// try 3rd-party path first
	return []string{
		UserNetPluginsPath,
		filepath.Join(common.Stage1RootfsPath(e.podRoot), BuiltinNetPluginsPath),
	}
}
Example #15
0
File: pod.go Project: matomesc/rkt
// WriteDefaultTarget writes the default.target unit file
// which is responsible for bringing up the applications
func WriteDefaultTarget(p *stage1commontypes.Pod) error {
	opts := []*unit.UnitOption{
		unit.NewUnitOption("Unit", "Description", "rkt apps target"),
		unit.NewUnitOption("Unit", "DefaultDependencies", "false"),
	}

	for i := range p.Manifest.Apps {
		ra := &p.Manifest.Apps[i]
		serviceName := ServiceUnitName(ra.Name)
		opts = append(opts, unit.NewUnitOption("Unit", "After", serviceName))
		opts = append(opts, unit.NewUnitOption("Unit", "Wants", serviceName))
	}

	unitsPath := filepath.Join(common.Stage1RootfsPath(p.Root), UnitsDir)
	file, err := os.OpenFile(filepath.Join(unitsPath, "default.target"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer file.Close()

	if _, err = io.Copy(file, unit.Serialize(opts)); err != nil {
		return err
	}

	return nil
}
Example #16
0
File: podenv.go Project: nhlfr/rkt
func (e *podEnv) setupNets(nets []activeNet, noDNS bool) error {
	err := os.MkdirAll(e.netDir(), 0755)
	if err != nil {
		return err
	}

	i := 0
	defer func() {
		if err != nil {
			e.teardownNets(nets[:i])
		}
	}()

	n := activeNet{}

	// did stage0 already make /etc/rkt-resolv.conf (i.e. --dns passed)
	resolvPath := filepath.Join(common.Stage1RootfsPath(e.podRoot), "etc/rkt-resolv.conf")
	_, err = os.Stat(resolvPath)
	if err != nil && !os.IsNotExist(err) {
		return errwrap.Wrap(fmt.Errorf("error statting /etc/rkt-resolv.conf"), err)
	}
	podHasResolvConf := err == nil

	for i, n = range nets {
		if debuglog {
			stderr.Printf("loading network %v with type %v", n.conf.Name, n.conf.Type)
		}

		n.runtime.IfName = fmt.Sprintf(IfNamePattern, i)
		if n.runtime.ConfPath, err = copyFileToDir(n.runtime.ConfPath, e.netDir()); err != nil {
			return errwrap.Wrap(fmt.Errorf("error copying %q to %q", n.runtime.ConfPath, e.netDir()), err)
		}

		// Actually shell out to the plugin
		err = e.netPluginAdd(&n, e.podNS.Path())
		if err != nil {
			return errwrap.Wrap(fmt.Errorf("error adding network %q", n.conf.Name), err)
		}

		// Generate rkt-resolv.conf if it's not already there.
		// The first network plugin that supplies a non-empty
		// DNS response will win, unless noDNS is true (--dns passed to rkt run)
		if !common.IsDNSZero(&n.runtime.DNS) && !noDNS {
			if !podHasResolvConf {
				err := ioutil.WriteFile(
					resolvPath,
					[]byte(common.MakeResolvConf(n.runtime.DNS, "Generated by rkt from network "+n.conf.Name)),
					0644)
				if err != nil {
					return errwrap.Wrap(fmt.Errorf("error creating resolv.conf"), err)
				}
				podHasResolvConf = true
			} else {
				stderr.Printf("Warning: network %v plugin specified DNS configuration, but DNS already supplied", n.conf.Name)
			}
		}
	}
	return nil
}
Example #17
0
func ensureKeysExistInPod(workDir string) error {
	destRootfs := common.Stage1RootfsPath(workDir)
	keyDirPath := filepath.Join(destRootfs, u.HomeDir, ".ssh")
	if err := os.MkdirAll(keyDirPath, 0700); err != nil {
		return err
	}
	return ensureAuthorizedKeysExist(keyDirPath)
}
Example #18
0
File: pod.go Project: matomesc/rkt
// GetFlavor populates a flavor string based on the flavor itself and respectively the systemd version
func GetFlavor(p *stage1commontypes.Pod) (flavor string, systemdVersion string, err error) {
	flavor, err = os.Readlink(filepath.Join(common.Stage1RootfsPath(p.Root), "flavor"))
	if err != nil {
		return "", "", fmt.Errorf("unable to determine stage1 flavor: %v", err)
	}

	if flavor == "host" {
		// This flavor does not contain systemd, so don't return systemdVersion
		return flavor, "", nil
	}

	systemdVersionBytes, err := ioutil.ReadFile(filepath.Join(common.Stage1RootfsPath(p.Root), "systemd-version"))
	if err != nil {
		return "", "", fmt.Errorf("unable to determine stage1's systemd version: %v", err)
	}
	systemdVersion = strings.Trim(string(systemdVersionBytes), " \n")
	return flavor, systemdVersion, nil
}
Example #19
0
// GetFlavor populates a flavor string based on the flavor itself and respectively the systemd version
// If the systemd version couldn't be guessed, it will be set to 0.
func GetFlavor(p *stage1commontypes.Pod) (flavor string, systemdVersion int, err error) {
	flavor, err = os.Readlink(filepath.Join(common.Stage1RootfsPath(p.Root), "flavor"))
	if err != nil {
		return "", -1, errwrap.Wrap(errors.New("unable to determine stage1 flavor"), err)
	}

	if flavor == "host" {
		// This flavor does not contain systemd, parse "systemctl --version"
		systemctlBin, err := common.LookupPath("systemctl", os.Getenv("PATH"))
		if err != nil {
			return "", -1, err
		}

		systemdVersion, err := common.SystemdVersion(systemctlBin)
		if err != nil {
			return "", -1, errwrap.Wrap(errors.New("error finding systemctl version"), err)
		}

		return flavor, systemdVersion, nil
	}

	systemdVersionBytes, err := ioutil.ReadFile(filepath.Join(common.Stage1RootfsPath(p.Root), "systemd-version"))
	if err != nil {
		return "", -1, errwrap.Wrap(errors.New("unable to determine stage1's systemd version"), err)
	}
	systemdVersionString := strings.Trim(string(systemdVersionBytes), " \n")

	// systemdVersionString is either a tag name or a branch name. If it's a
	// tag name it's of the form "v229", remove the first character to get the
	// number.
	systemdVersion, err = strconv.Atoi(systemdVersionString[1:])
	if err != nil {
		// If we get a syntax error, it means the parsing of the version string
		// of the form "v229" failed, set it to 0 to indicate we couldn't guess
		// it.
		if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrSyntax {
			systemdVersion = 0
		} else {
			return "", -1, errwrap.Wrap(errors.New("error parsing stage1's systemd version"), err)
		}
	}
	return flavor, systemdVersion, nil
}
Example #20
0
File: kvm.go Project: nhlfr/rkt
// KvmNetworkingToSystemd generates systemd unit files for a pod according to network configuration
func KvmNetworkingToSystemd(p *stage1commontypes.Pod, n *networking.Networking) error {
	podRoot := common.Stage1RootfsPath(p.Root)

	// networking
	netDescriptions := kvm.GetNetworkDescriptions(n)
	if err := kvm.GenerateNetworkInterfaceUnits(filepath.Join(podRoot, stage1initcommon.UnitsDir), netDescriptions); err != nil {
		return errwrap.Wrap(errors.New("failed to transform networking to units"), err)
	}

	return nil
}
Example #21
0
// generateSysusers generates systemd sysusers files for a given app so that
// corresponding entries in /etc/passwd and /etc/group are created in stage1.
// This is needed to use the "User="******"Group=" options in the systemd
// service files of apps.
// If there're several apps defining the same UIDs/GIDs, systemd will take care
// of only generating one /etc/{passwd,group} entry
func generateSysusers(p *stage1commontypes.Pod, ra *schema.RuntimeApp, uid_ int, gid_ int, uidRange *user.UidRange) error {
	var toShift []string

	app := ra.App
	appName := ra.Name

	sysusersDir := path.Join(common.Stage1RootfsPath(p.Root), "usr/lib/sysusers.d")
	toShift = append(toShift, sysusersDir)
	if err := os.MkdirAll(sysusersDir, 0755); err != nil {
		return err
	}

	gids := append(app.SupplementaryGIDs, gid_)

	// Create the Unix user and group
	var sysusersConf []string

	for _, g := range gids {
		groupname := "gen" + strconv.Itoa(g)
		sysusersConf = append(sysusersConf, fmt.Sprintf("g %s %d\n", groupname, g))
	}

	username := "******" + strconv.Itoa(uid_)
	sysusersConf = append(sysusersConf, fmt.Sprintf("u %s %d \"%s\"\n", username, uid_, username))

	sysusersFile := path.Join(common.Stage1RootfsPath(p.Root), "usr/lib/sysusers.d", ServiceUnitName(appName)+".conf")
	toShift = append(toShift, sysusersFile)
	if err := ioutil.WriteFile(sysusersFile, []byte(strings.Join(sysusersConf, "\n")), 0640); err != nil {
		return err
	}

	if uidRange.Shift != 0 && uidRange.Count != 0 {
		for _, f := range toShift {
			if err := os.Chown(f, int(uidRange.Shift), int(uidRange.Shift)); err != nil {
				return err
			}
		}
	}

	return nil
}
Example #22
0
File: gc.go Project: 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)
	}
}
Example #23
0
// mountContainerV1Cgroups mounts the cgroup controllers hierarchy in the container's
// namespace read-only, leaving the needed knobs in the subcgroup for each-app
// read-write so systemd inside stage1 can apply isolators to them
func mountContainerV1Cgroups(m fs.Mounter, p *stage1commontypes.Pod, enabledCgroups map[int][]string, subcgroup string, serviceNames []string) error {
	mountContext := os.Getenv(common.EnvSELinuxMountContext)
	stage1Root := common.Stage1RootfsPath(p.Root)
	if err := v1.CreateCgroups(m, stage1Root, enabledCgroups, mountContext); err != nil {
		return errwrap.Wrap(errors.New("error creating container cgroups"), err)
	}

	if err := v1.RemountCgroups(m, stage1Root, enabledCgroups, subcgroup, serviceNames, p.InsecureOptions.DisablePaths); err != nil {
		return errwrap.Wrap(errors.New("error restricting container cgroups"), err)
	}

	return nil
}
Example #24
0
// Loads nets specified by user and default one from stage1
func (e *podEnv) loadNets() ([]activeNet, error) {
	nets, err := loadUserNets()
	if err != nil {
		return nil, err
	}

	if !netExists(nets, "default") {
		defPath := path.Join(common.Stage1RootfsPath(e.podRoot), DefaultNetPath)
		n, err := loadNet(defPath)
		if err != nil {
			return nil, err
		}
		nets = append(nets, *n)
	}

	return nets, nil
}
Example #25
0
File: pod.go Project: matomesc/rkt
// PodToNspawnArgs renders a prepared Pod as a systemd-nspawn
// argument list ready to be executed
func PodToNspawnArgs(p *stage1commontypes.Pod) ([]string, error) {
	args := []string{
		"--uuid=" + p.UUID.String(),
		"--machine=" + GetMachineID(p),
		"--directory=" + common.Stage1RootfsPath(p.Root),
	}

	for i := range p.Manifest.Apps {
		aa, err := appToNspawnArgs(p, &p.Manifest.Apps[i])
		if err != nil {
			return nil, err
		}
		args = append(args, aa...)
	}

	return args, nil
}
Example #26
0
File: gc.go Project: vincentvdk/rkt
func gcNetworking(podID *types.UUID) error {
	flavor, err := os.Readlink(filepath.Join(common.Stage1RootfsPath("."), "flavor"))
	if err != nil {
		return fmt.Errorf("Failed to get stage1 flavor: %v\n", err)
	}

	n, err := networking.Load(".", podID)
	switch {
	case err == nil:
		n.Teardown(flavor)
	case os.IsNotExist(err):
		// probably ran without --private-net
	default:
		return fmt.Errorf("Failed loading networking state: %v", err)
	}

	return nil
}
Example #27
0
func writeShutdownService(p *stage1commontypes.Pod) error {
	flavor, systemdVersion, err := GetFlavor(p)
	if err != nil {
		return err
	}

	opts := []*unit.UnitOption{
		unit.NewUnitOption("Unit", "Description", "Pod shutdown"),
		unit.NewUnitOption("Unit", "AllowIsolate", "true"),
		unit.NewUnitOption("Unit", "StopWhenUnneeded", "yes"),
		unit.NewUnitOption("Unit", "DefaultDependencies", "false"),
		unit.NewUnitOption("Service", "RemainAfterExit", "yes"),
	}

	shutdownVerb := "exit"
	// systemd <v227 doesn't allow the "exit" verb when running as PID 1, so
	// use "halt".
	// If systemdVersion is 0 it means it couldn't be guessed, assume it's new
	// enough for "systemctl exit".
	// This can happen, for example, when building rkt with:
	//
	// ./configure --with-stage1-flavors=src --with-stage1-systemd-version=master
	//
	// The patches for the "exit" verb are backported to the "coreos" flavor, so
	// don't rely on the systemd version on the "coreos" flavor.
	if flavor != "coreos" && systemdVersion != 0 && systemdVersion < 227 {
		shutdownVerb = "halt"
	}

	opts = append(opts, unit.NewUnitOption("Service", "ExecStop", fmt.Sprintf("/usr/bin/systemctl --force %s", shutdownVerb)))

	unitsPath := filepath.Join(common.Stage1RootfsPath(p.Root), UnitsDir)
	file, err := os.OpenFile(filepath.Join(unitsPath, "shutdown.service"), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return errwrap.Wrap(errors.New("failed to create unit file"), err)
	}
	defer file.Close()

	if _, err = io.Copy(file, unit.Serialize(opts)); err != nil {
		return errwrap.Wrap(errors.New("failed to write unit file"), err)
	}

	return nil
}
Example #28
0
File: app.go Project: nhlfr/rkt
func StopApp(cfg StopConfig) error {
	p, err := stage1types.LoadPod(cfg.Dir, cfg.UUID)
	if err != nil {
		return errwrap.Wrap(errors.New("error loading pod manifest"), err)
	}

	pm := p.Manifest

	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)
	}

	eep, err := getStage1Entrypoint(cfg.Dir, enterEntrypoint)
	if err != nil {
		return errwrap.Wrap(errors.New("error determining 'enter' entrypoint"), err)
	}

	args := []string{
		cfg.UUID.String(),
		cfg.AppName.String(),
		filepath.Join(common.Stage1RootfsPath(cfg.Dir), eep),
		strconv.Itoa(cfg.PodPID),
	}

	if err := callEntrypoint(cfg.Dir, appStopEntrypoint, args); err != nil {
		return err
	}

	return nil
}
Example #29
0
// PodToNspawnArgs renders a prepared Pod as a systemd-nspawn
// argument list ready to be executed
func (p *Pod) PodToNspawnArgs() ([]string, error) {
	args := []string{
		"--uuid=" + p.UUID.String(),
		"--machine=" + "rkt-" + p.UUID.String(),
		"--directory=" + common.Stage1RootfsPath(p.Root),
	}

	for _, am := range p.Apps {
		ra := p.Manifest.Apps.Get(am.Name)
		if ra == nil {
			panic("could not find app in pod manifest!")
		}
		aa, err := p.appToNspawnArgs(ra, am)
		if err != nil {
			return nil, fmt.Errorf("failed to construct args for app %q: %v", am.Name, err)
		}
		args = append(args, aa...)
	}

	return args, nil
}
Example #30
0
File: pod.go Project: joshix/rkt
// PodToNspawnArgs renders a prepared Pod as a systemd-nspawn
// argument list ready to be executed
func PodToNspawnArgs(p *stage1commontypes.Pod, insecureOptions Stage1InsecureOptions) ([]string, error) {
	args := []string{
		"--uuid=" + p.UUID.String(),
		"--machine=" + GetMachineID(p),
		"--directory=" + common.Stage1RootfsPath(p.Root),
	}

	for i := range p.Manifest.Apps {
		aa, err := appToNspawnArgs(p, &p.Manifest.Apps[i], insecureOptions)
		if err != nil {
			return nil, err
		}
		args = append(args, aa...)
	}

	if insecureOptions.DisableCapabilities {
		args = append(args, "--capability=all")
	}

	return args, nil
}