github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/driver/executor/systemd.go (about) 1 package executor 2 3 import ( 4 "fmt" 5 systemd "github.com/coreos/go-systemd/dbus" 6 "github.com/godbus/dbus" 7 cstructs "github.com/hashicorp/nomad/client/driver/structs" 8 "github.com/hashicorp/nomad/nomad/structs" 9 "log" 10 "strings" 11 "time" 12 ) 13 14 type SystemdExecutor struct { 15 Target string 16 Properties []systemd.Property 17 logger *log.Logger 18 } 19 20 func NewSystemdExecutor(id, command string, logger *log.Logger) *SystemdExecutor { 21 props := []systemd.Property{systemd.PropExecStart(strings.Fields(command), false)} 22 props = append(props, systemd.Property{Name: "DefaultDependencies", Value: dbus.MakeVariant(false)}) 23 return &SystemdExecutor{ 24 Target: "nomad-" + id + ".service", 25 Properties: props, 26 logger: logger, 27 } 28 } 29 30 func (e *SystemdExecutor) Start() error { 31 conn, err := systemd.New() 32 if err != nil { 33 e.logger.Printf("[ERROR]Failed to connect to dbus. Error: %s\n", err) 34 return err 35 } 36 defer conn.Close() 37 statusCh := make(chan string, 1) 38 _, dbusErr := conn.StartTransientUnit(e.Target, "replace", e.Properties, statusCh) 39 if dbusErr != nil { 40 e.logger.Printf("Failed to start transient unit %s. Error:\n", e.Target, dbusErr) 41 return dbusErr 42 } 43 done := <-statusCh 44 if done != "done" { 45 e.logger.Printf("[ERROR] Job failed : %s\n", done) 46 return fmt.Errorf("Failed to enqueue transiet unit. Status: %s\n", done) 47 } 48 return nil 49 } 50 51 func (e *SystemdExecutor) Limit(resources *structs.Resources) error { 52 if resources.MemoryMB > 0 { 53 memoryLimit := systemd.Property{ 54 Name: "MemoryLimit", 55 Value: dbus.MakeVariant(uint64(resources.MemoryMB * 1024 * 1024)), 56 } 57 e.Properties = append(e.Properties, memoryLimit) 58 } 59 if resources.CPU > 2 { 60 cpuLimit := systemd.Property{ 61 Name: "CPUShares", 62 Value: dbus.MakeVariant(uint64(resources.CPU)), 63 } 64 e.Properties = append(e.Properties, cpuLimit) 65 } 66 if resources.IOPS > 0 { 67 iopsLimit := systemd.Property{ 68 Name: "BlkioWeight", 69 Value: dbus.MakeVariant(uint64(resources.IOPS)), 70 } 71 e.Properties = append(e.Properties, iopsLimit) 72 } 73 return nil 74 } 75 func (e *SystemdExecutor) Wait() *cstructs.WaitResult { 76 conn, err := systemd.New() 77 if err != nil { 78 e.logger.Printf("[ERROR]Failed to connect to dbus. Error: %s\n", err) 79 return cstructs.NewWaitResult(-1, 0, err) 80 } 81 defer conn.Close() 82 statusCh, errCh := conn.SubscribeUnits(5 * time.Second) 83 for { 84 select { 85 case units := <-statusCh: 86 for k, u := range units { 87 if k == e.Target { 88 e.logger.Printf("[DEBUG]Unit changed: %s\n", k) 89 if u == nil { 90 return cstructs.NewWaitResult(0, 0, nil) 91 } else { 92 e.logger.Printf("State changed for triggered unit: %#v\n", u) 93 } 94 } 95 } 96 case err := <-errCh: 97 return cstructs.NewWaitResult(-1, 0, err) 98 } 99 } 100 return nil 101 } 102 func (e *SystemdExecutor) Shutdown() error { 103 conn, err := systemd.New() 104 if err != nil { 105 e.logger.Printf("[ERROR]Failed to connect to dbus. Error: %s\n", err) 106 return err 107 } 108 defer conn.Close() 109 reschan := make(chan string) 110 _, err1 := conn.StopUnit(e.Target, "replace", reschan) 111 if err1 != nil { 112 e.logger.Printf("[ERROR]Failed to to make stop unit request. Error: %s\n", err1) 113 return err1 114 } 115 done := <-reschan 116 if done != "done" { 117 e.logger.Printf("Failed to stip unit %s. Status: %s\n", e.Target, done) 118 return fmt.Errorf("Failed to stip unit %s. Status: %s\n", e.Target, done) 119 } 120 return nil 121 }