Browse Source

Fixed: removed non-full paths

Added: First implementation of os specific implementation of pods
layerset
Till Wegmüller 6 years ago
parent
commit
5f6a4a78a6
  1. 2
      cmd/imageadm/build.go
  2. 2
      cmd/imageadm/config.go
  3. 2
      cmd/imageadm/create.go
  4. 2
      cmd/imageadm/resolve.go
  5. 2
      cmd/imageadm/root.go
  6. 2
      cmd/imageadm/set-config.go
  7. 15
      pod/app.go
  8. 16
      pod/app_dummy.go
  9. 15
      pod/app_freebsd.go
  10. 15
      pod/app_solaris.go
  11. 23
      pod/global.go
  12. 10
      pod/host.go
  13. 16
      pod/interface.go
  14. 51
      pod/pod.go
  15. 18
      pod/pod_dummy.go
  16. 192
      pod/pod_freebsd.go
  17. 18
      pod/pod_solaris.go

2
cmd/imageadm/build.go

@ -6,7 +6,7 @@ import (
"os"
"path/filepath"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"github.com/spf13/cobra"
)

2
cmd/imageadm/config.go

@ -3,7 +3,7 @@ package cmd
import (
"fmt"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"github.com/spf13/cobra"
)

2
cmd/imageadm/create.go

@ -5,7 +5,7 @@ import (
"path/filepath"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"github.com/spf13/cobra"
)

2
cmd/imageadm/resolve.go

@ -6,7 +6,7 @@ import (
"os"
"path/filepath"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"github.com/spf13/cobra"
)

2
cmd/imageadm/root.go

@ -4,7 +4,7 @@ import (
"fmt"
"os"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"git.wegmueller.it/toasterson/glog"
"github.com/spf13/cobra"
)

2
cmd/imageadm/set-config.go

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"../../image"
"git.wegmueller.it/opencloud/opencloud/image"
"github.com/spf13/cobra"
)

15
pod/app.go

@ -14,7 +14,6 @@ type App struct {
Name types.ACName
Pod *Pod
app *types.App
impl AppImplementation
killed bool
internalenv []string
@ -69,7 +68,7 @@ func (app *App) Run(stdin io.Reader, stdout, stderr io.Writer) (re error) {
switch eh.Name {
case "pre-start":
// TODO: log
if err := app.impl.Run(&cmd); err != nil {
if err := runApp(app, &cmd); err != nil {
return err
}
if app.killed {
@ -79,7 +78,7 @@ func (app *App) Run(stdin io.Reader, stdout, stderr io.Writer) (re error) {
defer func(exec []string) {
// TODO: log
if !app.killed {
if err := app.impl.Run(&cmd); err != nil {
if err := runApp(app, &cmd); err != nil {
if re != nil {
re = err
} // else? log?
@ -92,7 +91,7 @@ func (app *App) Run(stdin io.Reader, stdout, stderr io.Writer) (re error) {
}
cmd := exec.Cmd{Path: app.app.Exec[0], Args: app.app.Exec, Stdin: stdin, Stdout: stdout, Stderr: stderr}
return app.impl.Run(&cmd)
return runApp(app, &cmd)
}
func (app *App) Console(username string) error {
@ -100,17 +99,17 @@ func (app *App) Console(username string) error {
username = "root"
}
cmd := exec.Cmd{Path: "/usr/bin/login", Args: []string{"/usr/bin/login", "-p", "-f"}, Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr}
return app.impl.Run(&cmd)
return runApp(app, &cmd)
}
// IsRunning returns true if the app currently executes a stage2 command.
func (app *App) IsRunning() bool {
return app.impl.IsRunning()
return appIsRunning(app)
}
func (app *App) Kill() error {
if app.impl.IsRunning() {
err := app.impl.Kill()
if app.IsRunning() {
err := appKill(app)
app.killed = true
return err
}

16
pod/app_dummy.go

@ -0,0 +1,16 @@
//+build !solaris !freebsd
package pod
import "os/exec"
func runApp(app *App, cmd *exec.Cmd) error {
return nil
}
func appIsRunning(app *App) bool {
return false
}
func appKill(app *App) error {
return nil
}

15
pod/app_freebsd.go

@ -0,0 +1,15 @@
package pod
import "os/exec"
func runApp(app *App, cmd *exec.Cmd) error {
return nil
}
func appIsRunning(app *App) bool {
return false
}
func appKill(app *App) error {
return nil
}

15
pod/app_solaris.go

@ -0,0 +1,15 @@
package pod
import "os/exec"
func runApp(app *App, cmd *exec.Cmd) error {
return nil
}
func appIsRunning(app *App) bool {
return false
}
func appKill(app *App) error {
return nil
}

23
pod/global.go

@ -2,25 +2,26 @@ package pod
import "fmt"
type PodStatus uint
type Status uint
const (
PodStatusInvalid PodStatus = iota
PodStatusRunning
PodStatusDying
PodStatusStopped
StatusInvalid Status = iota
StatusRunning
StatusDying
StatusStopped
StatusNone
)
var podStatusNames = []string{
PodStatusInvalid: "invalid",
PodStatusRunning: "running",
PodStatusDying: "dying",
PodStatusStopped: "stopped",
StatusInvalid: "invalid",
StatusRunning: "running",
StatusDying: "dying",
StatusStopped: "stopped",
}
func (cs PodStatus) String() string {
func (cs Status) String() string {
if int(cs) < len(podStatusNames) {
return podStatusNames[cs]
}
return fmt.Sprintf("PodStatus[%d]", cs)
return fmt.Sprintf("Status[%d]", cs)
}

10
pod/host.go

@ -28,7 +28,7 @@ import (
type Host struct {
Dataset *zfs.Dataset
podStatusCache map[string]PodStatus
podStatusCache map[string]Status
cacheDate time.Time
mdsUid, mdsGid int
}
@ -408,7 +408,7 @@ func (h *Host) ImportImage(name types.ACIdentifier, aci, asc *os.File) (_ *Image
if err != nil {
return nil, err
}
aci.Seek(0, os.SEEK_SET)
aci.Seek(0, io.SeekStart)
if err = json.Unmarshal(manifestBytes, &img.Manifest); err != nil {
return nil, err
@ -532,15 +532,15 @@ func (h *Host) TrustKey(prefix types.ACIdentifier, location, fingerprint string)
defer kf.Close()
path, err := h.Keystore().StoreTrustedKey(prefix, kf, fingerprint)
keypath, err := h.Keystore().StoreTrustedKey(prefix, kf, fingerprint)
if err != nil {
return err
}
if path == "" {
if keypath == "" {
glog.Infoln("Key NOT accepted")
} else {
glog.Infof("Key accepted and saved as %v\n", path)
glog.Infof("Key accepted and saved as %v\n", keypath)
}
return nil

16
pod/interface.go

@ -3,7 +3,6 @@ package pod
import (
"net"
"os"
"os/exec"
"git.wegmueller.it/opencloud/opencloud/keystore"
"github.com/appc/spec/schema"
@ -11,21 +10,6 @@ import (
"github.com/satori/go.uuid"
)
type AppImplementation interface {
Run(cmd *exec.Cmd) (re error)
Kill() error
IsRunning() bool
}
type ImplementationInterface interface {
Create() error
Load() error
Status() PodStatus
Kill() error
Destroy() error
Run() error
}
type HostInterface interface {
Path(elem ...string) string
Initialize() error

51
pod/pod.go

@ -29,7 +29,6 @@ type Pod struct {
UUID uuid.UUID
Manifest schema.PodManifest
sealed bool
impl ImplementationInterface
}
func newPod(h *Host, id uuid.UUID) *Pod {
@ -152,12 +151,6 @@ func CreatePod(h *Host, pm *schema.PodManifest) (pod *Pod, rErr error) {
return nil, err
}
devfsRuleset, devfsRulesetFound := pod.Manifest.Annotations.Get("jetpack/devfs-ruleset")
if !devfsRulesetFound {
devfsRuleset = "4"
}
fstab = append(fstab, fmt.Sprintf(". %v devfs ruleset=%v 0 0\n", filepath.Join(appRootfs, "dev"), devfsRuleset))
if os_, _ := img.Manifest.GetLabel("os"); os_ == "linux" {
for _, dir := range []string{"sys", "proc"} {
if err := os.MkdirAll(filepath.Join(appRootfs, dir), 0755); err != nil && !os.IsExist(err) {
@ -169,21 +162,21 @@ func CreatePod(h *Host, pm *schema.PodManifest) (pod *Pod, rErr error) {
}
for _, mnt := range rtApp.Mounts {
path := mnt.Path
fspath := mnt.Path
readOnly := false
if path[0] != '/' {
if fspath[0] != '/' {
// Target path is a mount point name
if app == nil {
return nil, fmt.Errorf("invalid mount path %v:%#v: no app, no mount points", mnt.Volume, mnt.Path)
}
if name, err := types.NewACName(path); err != nil {
if name, err := types.NewACName(fspath); err != nil {
return nil, fmt.Errorf("invalid mount path %v:%#v: invalid ACName: %v", mnt.Volume, mnt.Path, err)
} else {
found := false
for _, mntpnt := range app.MountPoints {
if *name == mntpnt.Name {
path = mntpnt.Path
fspath = mntpnt.Path
readOnly = mntpnt.ReadOnly
found = true
break
@ -195,8 +188,8 @@ func CreatePod(h *Host, pm *schema.PodManifest) (pod *Pod, rErr error) {
}
} // TODO: (else?) { verify that target path exists }
path = filepath.Join(appRootfs, path)
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
fspath = filepath.Join(appRootfs, fspath)
if err := os.MkdirAll(fspath, 0755); err != nil && !os.IsExist(err) {
return nil, err
}
@ -205,7 +198,7 @@ func CreatePod(h *Host, pm *schema.PodManifest) (pod *Pod, rErr error) {
opts = "ro"
}
fstab = append(fstab, fmt.Sprintf("%v %v nullfs %v 1 0\n",
ds.VFSPath("rootfs", "vol", mnt.Volume.String()), path, opts))
ds.VFSPath("rootfs", "vol", mnt.Volume.String()), fspath, opts))
}
// TODO: verify app's unfulfilled mount points
@ -224,16 +217,8 @@ func CreatePod(h *Host, pm *schema.PodManifest) (pod *Pod, rErr error) {
pod.Manifest.Annotations.Set("ip-address", ip.String())
}
/*
TODO Tech specific Implementation
Zones
Jails
if err := ioutil.WriteFile(pod.Path("jail.conf"), []byte(pod.jailConf()), 0400); err != nil {
return nil, err
}
*/
if cerr := pod.impl.Create(); err != nil {
return nil, cerr
if err := createPod(h, pod); err != nil {
return nil, err
}
glog.Debugln("Saving manifest")
@ -319,24 +304,23 @@ func (pod *Pod) Load() error {
return nil
}
func (pod *Pod) Status() PodStatus {
//TODO Implement Tech specific function
return pod.impl.Status()
func (pod *Pod) Status() Status {
return podStatus(pod)
}
func (pod *Pod) Kill() error {
glog.Infoln("Shutting down")
retry:
switch status := pod.Status(); status {
case PodStatusStopped:
case StatusStopped:
// All's fine
return nil
case PodStatusRunning:
if err := pod.impl.Kill(); err != nil {
case StatusRunning:
if err := killPod(pod); err != nil {
return err
}
goto retry
case PodStatusDying:
case StatusDying:
time.Sleep(250 * time.Millisecond)
goto retry
default:
@ -355,11 +339,14 @@ func (pod *Pod) getDataset() *zfs.Dataset {
func (pod *Pod) Destroy() error {
glog.Infoln("Destroying")
if status := pod.impl.Status(); status == PodStatusRunning {
if status := pod.Status(); status == StatusRunning {
if err := pod.Kill(); err != nil {
// FIXME: plow through, ensure it's destroyed
return err
}
if err := destroyPod(pod); err != nil {
return err
}
}
if ds := pod.getDataset(); ds != nil {
if err := ds.Destroy(true); err != nil {

18
pod/pod_dummy.go

@ -0,0 +1,18 @@
//+build !freebsd !solaris
package pod
func createPod(host *Host, pod *Pod) error {
return nil
}
func podStatus(pod *Pod) Status {
return StatusStopped
}
func killPod(pod *Pod) error {
return nil
}
func destroyPod(pod *Pod) error {
return nil
}

192
pod/pod_freebsd.go

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

18
pod/pod_solaris.go

@ -0,0 +1,18 @@
//+build solaris
package pod
func createPod(host *Host, pod *Pod) error {
}
func podStatus(pod *Pod) Status {
}
func killPod(pod *Pod) error {
}
func destroyPod(pod *Pod) error {
}
Loading…
Cancel
Save