Esempio n. 1
0
// convert the servicebuilder yaml file into a runit service directory
func (s *ServiceBuilder) stage(templates map[string]ServiceTemplate) error {
	for serviceName, template := range templates {
		stageDir := filepath.Join(s.StagingRoot, serviceName)
		// create the default log directory
		err := os.MkdirAll(filepath.Join(stageDir, "log"), 0755)
		if err != nil {
			return err
		}

		runScript, err := template.RunScript()
		if err != nil {
			return err
		}
		if _, err := util.WriteIfChanged(filepath.Join(stageDir, "run"), runScript, 0755); err != nil {
			return err
		}

		logScript, err := template.LogScript()
		if err != nil {
			return err
		}
		if _, err := util.WriteIfChanged(filepath.Join(stageDir, "log", "run"), logScript, 0755); err != nil {
			return err
		}
	}
	return nil
}
Esempio n. 2
0
// set the memory limit on a cgroup, 0 to unrestrict
// https://www.kernel.org/doc/Documentation/cgroups/memory.txt
func (subsys Subsystems) SetMemory(name string, bytes int) error {
	if subsys.Memory == "" {
		return UnsupportedError("memory")
	}

	softLimit := bytes
	hardLimit := 2 * bytes
	if hardLimit < softLimit {
		// Deal with overflow
		hardLimit = softLimit
	}
	if bytes == 0 {
		softLimit = -1
		hardLimit = -1
	}

	err := os.Mkdir(filepath.Join(subsys.Memory, name), 0755)
	if err != nil && !os.IsExist(err) {
		return err
	}

	// the hard memory limit must be set BEFORE the mem+swap limit
	// so we must clear the swap limit at the start
	err = ioutil.WriteFile(filepath.Join(subsys.Memory, name, "memory.memsw.limit_in_bytes"), []byte("-1\n"), 0)
	if err != nil {
		return err
	}

	_, err = util.WriteIfChanged(filepath.Join(subsys.Memory, name, "memory.soft_limit_in_bytes"), []byte(strconv.Itoa(softLimit)+"\n"), 0)
	if err != nil {
		return err
	}

	_, err = util.WriteIfChanged(filepath.Join(subsys.Memory, name, "memory.limit_in_bytes"), []byte(strconv.Itoa(hardLimit)+"\n"), 0)
	if err != nil {
		return err
	}

	_, err = util.WriteIfChanged(filepath.Join(subsys.Memory, name, "memory.memsw.limit_in_bytes"), []byte(strconv.Itoa(hardLimit)+"\n"), 0)
	if err != nil {
		return err
	}

	return nil
}
Esempio n. 3
0
// set the number of logical CPUs in a given cgroup, 0 to unrestrict
// https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
func (subsys Subsystems) SetCPU(name string, cpus int) error {
	if subsys.CPU == "" {
		return UnsupportedError("cpu")
	}

	period := 1000000 // one million microseconds
	quota := cpus * period
	if cpus == 0 {
		// one hundred thousand microseconds is the default, -1 will return EINVAL
		period = 100000
		// setting -1 here will unrestrict the cgroup, so the period won't matter
		quota = -1
	}

	err := os.Mkdir(filepath.Join(subsys.CPU, name), 0755)
	if err != nil && !os.IsExist(err) {
		return err
	}

	_, err = util.WriteIfChanged(
		filepath.Join(subsys.CPU, name, "cpu.cfs_period_us"),
		[]byte(strconv.Itoa(period)+"\n"),
		0,
	)
	if err != nil {
		return err
	}

	_, err = util.WriteIfChanged(
		filepath.Join(subsys.CPU, name, "cpu.cfs_quota_us"),
		[]byte(strconv.Itoa(quota)+"\n"),
		0,
	)
	if err != nil {
		return err
	}

	return nil
}
Esempio n. 4
0
// convert the servicebuilder yaml file into a runit service directory
func (s *ServiceBuilder) stage(templates map[string]ServiceTemplate, restartPolicy RestartPolicy) error {
	nobody, err := user.Lookup("nobody")
	if err != nil {
		return err
	}
	nobodyUid, err := strconv.ParseInt(nobody.Uid, 10, 64)
	if err != nil {
		return err
	}
	nobodyGid, err := strconv.ParseInt(nobody.Gid, 10, 64)
	if err != nil {
		return err
	}

	for serviceName, template := range templates {
		stageDir := filepath.Join(s.StagingRoot, serviceName)
		// create the default log directory
		logDir := filepath.Join(stageDir, "log")
		err := os.MkdirAll(logDir, 0755)
		if err != nil {
			return err
		}

		// create a place for the logs to go
		logMainDir := filepath.Join(logDir, "main")
		err = os.Mkdir(logMainDir, 0755)
		if err == nil {
			if !s.testingNoChown {
				err = os.Chown(logMainDir, int(nobodyUid), int(nobodyGid))
				if err != nil {
					return err
				}
			}
		} else if !os.IsExist(err) {
			return err
		}

		runScript, err := template.runScript()
		if err != nil {
			return err
		}
		if _, err := util.WriteIfChanged(filepath.Join(stageDir, "run"), runScript, 0755); err != nil {
			return err
		}

		logScript, err := template.logScript()
		if err != nil {
			return err
		}
		if _, err := util.WriteIfChanged(filepath.Join(stageDir, "log", "run"), logScript, 0755); err != nil {
			return err
		}

		finishScript, err := template.finishScript()
		if err != nil {
			return err
		}
		if _, err := util.WriteIfChanged(filepath.Join(stageDir, "finish"), finishScript, 0755); err != nil {
			return err
		}

		// If a "down" file is not present, runit will restart the process
		// whenever it finishes. Prevent that if the requested restart policy
		// is not RestartAlways
		downPath := filepath.Join(stageDir, DOWN_FILE_NAME)
		if restartPolicy != RestartPolicyAlways {
			file, err := os.Create(downPath)
			if err != nil {
				return err
			}
			_ = file.Close()
		} else {
			// There could be a down file lying around from a
			// previous installation with a different restart
			// policy, check for it and remove it if present
			_, err := os.Stat(downPath)
			if err == nil {
				err := os.Remove(downPath)
				if err != nil {
					return util.Errorf("Unable to remove down file: %s", err)
				}
			} else if !os.IsNotExist(err) {
				return util.Errorf("Error checking for down file: %s", err)
			}
		}
	}
	return nil
}