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  }