github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/driver/lxc_executor.go (about) 1 package driver 2 3 import ( 4 "fmt" 5 cstructs "github.com/hashicorp/nomad/client/driver/structs" 6 "github.com/hashicorp/nomad/nomad/structs" 7 lxc "gopkg.in/lxc/go-lxc.v2" 8 "log" 9 "strconv" 10 "time" 11 ) 12 13 type LXCExecutorConfig struct { 14 LXCPath string `mapstructure:"lxc_path"` 15 Name string `mapstructure:"name"` 16 CloneFrom string `mapstructure:"clone_from"` 17 Template string `mapstructure:"template"` 18 Distro string `mapstructure:"distro"` 19 Release string `mapstructure:"release"` 20 Arch string `mapstructure:"arch"` 21 CgroupItems map[string]string `mapstructure:"cgroup_items"` 22 ConfigItems map[string]string `mapstructure:"config_items"` 23 } 24 25 type LXCExecutor struct { 26 logger *log.Logger 27 container *lxc.Container 28 config *LXCExecutorConfig 29 } 30 31 func (e *LXCExecutor) Container() *lxc.Container { 32 return e.container 33 } 34 35 func NewLXCExecutor(config *LXCExecutorConfig, logger *log.Logger) (*LXCExecutor, error) { 36 container, err := CreateLXCContainer(config) 37 if err != nil { 38 logger.Printf("[ERROR] failed to create container: %s", err) 39 return nil, err 40 } 41 executor := LXCExecutor{ 42 config: config, 43 container: container, 44 logger: logger, 45 } 46 return &executor, nil 47 } 48 49 func createFromTemplate(config *LXCExecutorConfig) (*lxc.Container, error) { 50 if config.Template == "" { 51 return nil, fmt.Errorf("Missing template name for lxc driver") 52 } 53 if config.Distro == "" { 54 return nil, fmt.Errorf("Missing distro name for lxc driver") 55 } 56 if config.Release == "" { 57 return nil, fmt.Errorf("Missing release name for lxc driver") 58 } 59 if config.Arch == "" { 60 return nil, fmt.Errorf("Missing arch name for lxc driver") 61 } 62 options := lxc.TemplateOptions{ 63 Template: config.Template, 64 Distro: config.Distro, 65 Release: config.Release, 66 Arch: config.Arch, 67 FlushCache: false, 68 DisableGPGValidation: false, 69 } 70 c, err := lxc.NewContainer(config.Name, config.LXCPath) 71 if err != nil { 72 return nil, err 73 } 74 if err := c.Create(options); err != nil { 75 return nil, err 76 } 77 return c, nil 78 } 79 80 func createByCloning(config *LXCExecutorConfig) (*lxc.Container, error) { 81 c, err := lxc.NewContainer(config.CloneFrom, config.LXCPath) 82 if err != nil { 83 return nil, err 84 } 85 if err := c.Clone(config.Name, lxc.DefaultCloneOptions); err != nil { 86 return nil, err 87 } 88 c1, err1 := lxc.NewContainer(config.Name, config.LXCPath) 89 if err1 != nil { 90 return nil, err1 91 } 92 return c1, nil 93 } 94 95 func CreateLXCContainer(config *LXCExecutorConfig) (*lxc.Container, error) { 96 if config.LXCPath == "" { 97 config.LXCPath = lxc.DefaultConfigPath() 98 } 99 if config.Name == "" { 100 return nil, fmt.Errorf("Missing container name for lxc driver") 101 } 102 var container *lxc.Container 103 if config.CloneFrom == "" { 104 c, err := createFromTemplate(config) 105 if err != nil { 106 return nil, err 107 } 108 container = c 109 } else { 110 c, err := createByCloning(config) 111 if err != nil { 112 return nil, err 113 } 114 container = c 115 } 116 for k, v := range config.CgroupItems { 117 if err := container.SetCgroupItem(k, v); err != nil { 118 return nil, err 119 } 120 } 121 for k, v := range config.ConfigItems { 122 if err := container.SetConfigItem(k, v); err != nil { 123 return nil, err 124 } 125 } 126 return container, nil 127 } 128 129 func (e *LXCExecutor) Wait() *cstructs.WaitResult { 130 for { 131 if e.container.Running() { 132 time.Sleep(5 * time.Second) 133 } else { 134 return cstructs.NewWaitResult(0, 0, nil) 135 } 136 } 137 return nil 138 } 139 140 func (e *LXCExecutor) Limit(resources *structs.Resources) error { 141 if resources.MemoryMB > 0 { 142 limit := strconv.Itoa(resources.MemoryMB) + "M" 143 if err := e.container.SetConfigItem("lxc.cgroup.memory.limit_in_bytes", limit); err != nil { 144 e.logger.Printf("[ERROR] failed to set memory limit to %s. Error: %v", limit, err) 145 return err 146 } 147 } 148 if resources.CPU > 2 { 149 limit := strconv.Itoa(resources.CPU) 150 if err := e.container.SetConfigItem("lxc.cgroup.cpu.shares", limit); err != nil { 151 e.logger.Printf("[ERROR] failed to set cpu limit to %s. Error: %v", limit, err) 152 return err 153 } 154 } 155 if resources.IOPS > 0 { 156 limit := strconv.Itoa(resources.IOPS) 157 if err := e.container.SetConfigItem("lxc.cgroup.blkio.weight", limit); err != nil { 158 e.logger.Printf("[ERROR] failed to set iops limit to %s. Error: %v", limit, err) 159 return err 160 } 161 } 162 return nil 163 } 164 165 func (e *LXCExecutor) Start() error { 166 return e.container.Start() 167 } 168 169 func (e *LXCExecutor) Shutdown() error { 170 if e.container.Defined() { 171 if e.container.State() == lxc.RUNNING { 172 if err := e.container.Stop(); err != nil { 173 return err 174 } 175 } 176 return e.container.Destroy() 177 } 178 return nil 179 }