|
|
|
@ -0,0 +1,192 @@
|
|
|
|
|
//+build freebsd
|
|
|
|
|
package pod |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"fmt" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"os" |
|
|
|
|
"path/filepath" |
|
|
|
|
"sort" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"git.wegmueller.it/opencloud/opencloud/run" |
|
|
|
|
"git.wegmueller.it/toasterson/glog" |
|
|
|
|
"github.com/spf13/viper" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type JailStatus struct { |
|
|
|
|
Jid int |
|
|
|
|
Dying bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var NoJailStatus = JailStatus{} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
jailStatusTimestamp time.Time |
|
|
|
|
jailStatusCache map[string]JailStatus |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func createPod(host *Host, pod *Pod) error { |
|
|
|
|
if err := ioutil.WriteFile(pod.Path("jail.conf"), []byte(pod.jailConf()), 0400); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func podStatus(pod *Pod) Status { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func killPod(pod *Pod) error { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func destroyPod(pod *Pod) error { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (h *Host) getJailStatus(name string, refresh bool) (JailStatus, error) { |
|
|
|
|
if refresh || jailStatusCache == nil || time.Now().Sub(jailStatusTimestamp) > (2*time.Second) { |
|
|
|
|
// FIXME: nicer cache/expiry implementation?
|
|
|
|
|
if lines, err := run.Command("/usr/sbin/jls", "-d", "jid", "dying", "name").OutputLines(); err != nil { |
|
|
|
|
return NoJailStatus, err |
|
|
|
|
} else { |
|
|
|
|
stat := make(map[string]JailStatus) |
|
|
|
|
for _, line := range lines { |
|
|
|
|
fields := strings.SplitN(line, " ", 3) |
|
|
|
|
status := NoJailStatus |
|
|
|
|
if len(fields) != 3 { |
|
|
|
|
return NoJailStatus, fmt.Errorf("cannot parse jls line %#v", line) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if jid, err := strconv.Atoi(fields[0]); err != nil { |
|
|
|
|
return NoJailStatus, fmt.Errorf("cannot parse jls line %#v: %s", line, err) |
|
|
|
|
} else { |
|
|
|
|
status.Jid = jid |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if dying, err := strconv.Atoi(fields[1]); err != nil { |
|
|
|
|
return NoJailStatus, fmt.Errorf("cannot parse jls line %#v: %s", line, err) |
|
|
|
|
} else { |
|
|
|
|
status.Dying = dying != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stat[fields[2]] = status |
|
|
|
|
} |
|
|
|
|
jailStatusCache = stat |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return jailStatusCache[name], nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) jailConf() string { |
|
|
|
|
parameters := map[string]string{ |
|
|
|
|
"exec.clean": "true", |
|
|
|
|
"host.hostuuid": pod.UUID.String(), |
|
|
|
|
"interface": viper.GetString("jail.interface"), |
|
|
|
|
"path": pod.Path("rootfs"), |
|
|
|
|
"persist": "true", |
|
|
|
|
"mount.fstab": pod.Path("fstab"), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for pk, pv := range viper.GetStringMapString("ace.jailConf") { |
|
|
|
|
parameters[pk] = pv |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if hostname, ok := pod.Manifest.Annotations.Get("hostname"); ok { |
|
|
|
|
parameters["host.hostname"] = hostname |
|
|
|
|
} else { |
|
|
|
|
parameters["host.hostname"] = parameters["host.hostuuid"] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ip, ok := pod.Manifest.Annotations.Get("ip-address"); ok { |
|
|
|
|
parameters["ip4.addr"] = ip |
|
|
|
|
} else { |
|
|
|
|
panic(fmt.Sprintf("No IP address for pod %v", pod.UUID)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, antn := range pod.Manifest.Annotations { |
|
|
|
|
if strings.HasPrefix(string(antn.Name), "jetpack/jail.conf/") { |
|
|
|
|
parameters[strings.Replace(string(antn.Name)[len("jetpack/jail.conf/"):], "-", "_", -1)] = antn.Value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
lines := make([]string, 0, len(parameters)) |
|
|
|
|
for k, v := range parameters { |
|
|
|
|
lines = append(lines, fmt.Sprintf(" %v=%#v;", k, v)) |
|
|
|
|
} |
|
|
|
|
sort.Strings(lines) |
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%#v {\n%v\n}\n", pod.jailName(), strings.Join(lines, "\n")) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) prepJail() error { |
|
|
|
|
for _, app := range pod.Manifest.Apps { |
|
|
|
|
etcPath := pod.Path("rootfs", "app", app.Name.String(), "rootfs", "etc") |
|
|
|
|
if fi, err := os.Stat(etcPath); err == nil && fi.IsDir() { |
|
|
|
|
// TODO: option (isolator?) to prevent creation of resolv.conf
|
|
|
|
|
if dnsServers := viper.GetString("ace.dns-servers"); dnsServers != "" { |
|
|
|
|
// By default, copy /etc/resolv.conf from host
|
|
|
|
|
if bb, err := ioutil.ReadFile("/etc/resolv.conf"); err != nil { |
|
|
|
|
return err |
|
|
|
|
} else { |
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(etcPath, "resolv.conf"), bb, 0644); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if resolvconf, err := os.Create(filepath.Join(etcPath, "resolv.conf")); err != nil { |
|
|
|
|
return err |
|
|
|
|
} else { |
|
|
|
|
for _, server := range strings.Fields(dnsServers) { |
|
|
|
|
fmt.Fprintln(resolvconf, "nameserver", server) |
|
|
|
|
} |
|
|
|
|
resolvconf.Close() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) runJail(op string) error { |
|
|
|
|
if err := pod.prepJail(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
verbosity := "-q" |
|
|
|
|
if viper.GetBool("debug") { |
|
|
|
|
verbosity = "-v" |
|
|
|
|
} |
|
|
|
|
glog.Debugf("Running: jail\n", op) |
|
|
|
|
return run.Command("jail", "-f", pod.Path("jail.conf"), verbosity, op, pod.jailName()).Run() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) jailName() string { |
|
|
|
|
return viper.GetString("jail.namePrefix") + pod.UUID.String() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) jailStatus(refresh bool) (JailStatus, error) { |
|
|
|
|
return pod.Host.getJailStatus(pod.jailName(), refresh) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pod *Pod) Jid() int { |
|
|
|
|
if status, err := pod.jailStatus(false); err != nil { |
|
|
|
|
panic(err) // FIXME: better error flow
|
|
|
|
|
} else { |
|
|
|
|
return status.Jid |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Return jail ID, start jail if necessary.
|
|
|
|
|
func (pod *Pod) ensureJid() int { |
|
|
|
|
jid := pod.Jid() |
|
|
|
|
if jid == 0 { |
|
|
|
|
if err := pod.runJail("-c"); err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
jid = pod.Jid() |
|
|
|
|
if jid == 0 { |
|
|
|
|
panic("Could not start jail") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return jid |
|
|
|
|
} |