Beispiel #1
0
// appToNspawnArgs transforms the given app manifest, with the given associated
// app image id, into a subset of applicable systemd-nspawn argument
func (c *Container) appToNspawnArgs(am *schema.AppManifest, id types.Hash) ([]string, error) {
	args := []string{}
	name := am.Name.String()

	vols := make(map[types.ACName]types.Volume)
	for _, v := range c.Manifest.Volumes {
		for _, f := range v.Fulfills {
			vols[f] = v
		}
	}

	for _, mp := range am.MountPoints {
		key := mp.Name
		vol, ok := vols[key]
		if !ok {
			return nil, fmt.Errorf("no volume for mountpoint %q in app %q", key, name)
		}
		opt := make([]string, 4)

		if mp.ReadOnly {
			opt[0] = "--bind-ro="
		} else {
			opt[0] = "--bind="
		}

		opt[1] = vol.Source
		opt[2] = ":"
		opt[3] = filepath.Join(rktpath.RelAppRootfsPath(id), mp.Path)

		args = append(args, strings.Join(opt, ""))
	}

	return args, nil
}
Beispiel #2
0
// appToSystemd transforms the provided app manifest into systemd units
func (c *Container) appToSystemd(am *schema.AppManifest, id types.Hash) error {
	name := am.Name.String()
	execStart := strings.Join(am.Exec, " ")
	opts := []*unit.UnitOption{
		&unit.UnitOption{"Unit", "Description", name},
		&unit.UnitOption{"Unit", "DefaultDependencies", "false"},
		&unit.UnitOption{"Unit", "OnFailureJobMode", "isolate"},
		&unit.UnitOption{"Unit", "OnFailure", "reaper.service"},
		&unit.UnitOption{"Unit", "Wants", "exit-watcher.service"},
		&unit.UnitOption{"Service", "Restart", "no"},
		&unit.UnitOption{"Service", "RootDirectory", rktpath.RelAppRootfsPath(id)},
		&unit.UnitOption{"Service", "ExecStart", execStart},
		&unit.UnitOption{"Service", "User", am.User},
		&unit.UnitOption{"Service", "Group", am.Group},
	}

	for _, eh := range am.EventHandlers {
		var typ string
		switch eh.Name {
		case "pre-start":
			typ = "ExecStartPre"
		case "post-stop":
			typ = "ExecStopPost"
		default:
			return fmt.Errorf("unrecognized eventHandler: %v", eh.Name)
		}
		exec := strings.Join(eh.Exec, " ")
		opts = append(opts, &unit.UnitOption{"Service", typ, exec})
	}

	env := am.Environment
	env["AC_APP_NAME"] = name
	for ek, ev := range env {
		ee := fmt.Sprintf(`"%s=%s"`, ek, ev)
		opts = append(opts, &unit.UnitOption{"Service", "Environment", ee})
	}

	saPorts := []types.Port{}
	for _, p := range am.Ports {
		if p.SocketActivated {
			saPorts = append(saPorts, p)
		}
	}

	if len(saPorts) > 0 {
		sockopts := []*unit.UnitOption{
			&unit.UnitOption{"Unit", "Description", name + " socket-activated ports"},
			&unit.UnitOption{"Unit", "DefaultDependencies", "false"},
			&unit.UnitOption{"Socket", "BindIPv6Only", "both"},
			&unit.UnitOption{"Socket", "Service", ServiceUnitName(id)},
		}

		for _, sap := range saPorts {
			var proto string
			switch sap.Protocol {
			case "tcp":
				proto = "ListenStream"
			case "udp":
				proto = "ListenDatagram"
			default:
				return fmt.Errorf("unrecognized protocol: %v", sap.Protocol)
			}
			sockopts = append(sockopts, &unit.UnitOption{"Socket", proto, fmt.Sprintf("%v", sap.Port)})
		}

		file, err := os.OpenFile(SocketUnitPath(c.Root, id), os.O_WRONLY|os.O_CREATE, 0644)
		if err != nil {
			return fmt.Errorf("failed to create socket file: %v", err)
		}
		defer file.Close()

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

		if err = os.Symlink(path.Join("..", SocketUnitName(id)), SocketWantPath(c.Root, id)); err != nil {
			return fmt.Errorf("failed to link socket want: %v", err)
		}

		opts = append(opts, &unit.UnitOption{"Unit", "Requires", SocketUnitName(id)})
	}

	file, err := os.OpenFile(ServiceUnitPath(c.Root, id), 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)
	}

	if err = os.Symlink(path.Join("..", ServiceUnitName(id)), ServiceWantPath(c.Root, id)); err != nil {
		return fmt.Errorf("failed to link service want: %v", err)
	}

	return nil
}