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  }