github.com/ssube/gitlab-ci-multi-runner@v1.2.1-0.20160607142738-b8d1285632e6/common/config.go (about)

     1  package common
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io/ioutil"
     7  	"os"
     8  	"time"
     9  
    10  	"fmt"
    11  	"github.com/BurntSushi/toml"
    12  	log "github.com/Sirupsen/logrus"
    13  	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
    14  	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/docker"
    15  	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/ssh"
    16  	"path/filepath"
    17  )
    18  
    19  type DockerPullPolicy string
    20  
    21  const (
    22  	DockerPullPolicyAlways       DockerPullPolicy = "always"
    23  	DockerPullPolicyNever                         = "never"
    24  	DockerPullPolicyIfNotPresent                  = "if-not-present"
    25  )
    26  
    27  // Get returns one of the predefined values or returns an error if the value can't match the predefined
    28  func (p DockerPullPolicy) Get() (DockerPullPolicy, error) {
    29  	// Default policy is always
    30  	if p == "" {
    31  		return DockerPullPolicyAlways, nil
    32  	}
    33  
    34  	// Verify pull policy
    35  	if p != DockerPullPolicyNever &&
    36  		p != DockerPullPolicyIfNotPresent &&
    37  		p != DockerPullPolicyAlways {
    38  		return "", fmt.Errorf("unsupported docker-pull-policy: %v", p)
    39  	}
    40  	return p, nil
    41  }
    42  
    43  type DockerConfig struct {
    44  	docker_helpers.DockerCredentials
    45  	Hostname               string           `toml:"hostname,omitempty" json:"hostname" long:"hostname" env:"DOCKER_HOSTNAME" description:"Custom container hostname"`
    46  	Image                  string           `toml:"image" json:"image" long:"image" env:"DOCKER_IMAGE" description:"Docker image to be used"`
    47  	CPUSetCPUs             string           `toml:"cpuset_cpus,omitempty" json:"cpuset_cpus" long:"cpuset-cpus" env:"DOCKER_CPUSET_CPUS" description:"String value containing the cgroups CpusetCpus to use"`
    48  	DNS                    []string         `toml:"dns,omitempty" json:"dns" long:"dns" env:"DOCKER_DNS" description:"A list of DNS servers for the container to use"`
    49  	DNSSearch              []string         `toml:"dns_search,omitempty" json:"dns_search" long:"dns-search" env:"DOCKER_DNS_SEARCH" description:"A list of DNS search domains"`
    50  	Privileged             bool             `toml:"privileged,omitzero" json:"privileged" long:"privileged" env:"DOCKER_PRIVILEGED" description:"Give extended privileges to container"`
    51  	CapAdd                 []string         `toml:"cap_add" json:"cap_add" long:"cap-add" env:"DOCKER_CAP_ADD" description:"Add Linux capabilities"`
    52  	CapDrop                []string         `toml:"cap_drop" json:"cap_drop" long:"cap-drop" env:"DOCKER_CAP_DROP" description:"Drop Linux capabilities"`
    53  	Devices                []string         `toml:"devices" json:"devices" long:"devices" env:"DOCKER_DEVICES" description:"Add a host device to the container"`
    54  	DisableCache           bool             `toml:"disable_cache,omitzero" json:"disable_cache" long:"disable-cache" env:"DOCKER_DISABLE_CACHE" description:"Disable all container caching"`
    55  	Volumes                []string         `toml:"volumes,omitempty" json:"volumes" long:"volumes" env:"DOCKER_VOLUMES" description:"Bind mount a volumes"`
    56  	CacheDir               string           `toml:"cache_dir,omitempty" json:"cache_dir" long:"cache-dir" env:"DOCKER_CACHE_DIR" description:"Directory where to store caches"`
    57  	ExtraHosts             []string         `toml:"extra_hosts,omitempty" json:"extra_hosts" long:"extra-hosts" env:"DOCKER_EXTRA_HOSTS" description:"Add a custom host-to-IP mapping"`
    58  	NetworkMode            string           `toml:"network_mode,omitempty" json:"network_mode" long:"network-mode" env:"DOCKER_NETWORK_MODE" description:"Add container to a custom network"`
    59  	Links                  []string         `toml:"links,omitempty" json:"links" long:"links" env:"DOCKER_LINKS" description:"Add link to another container"`
    60  	Services               []string         `toml:"services,omitempty" json:"services" long:"services" env:"DOCKER_SERVICES" description:"Add service that is started with container"`
    61  	WaitForServicesTimeout int              `toml:"wait_for_services_timeout,omitzero" json:"wait_for_services_timeout" long:"wait-for-services-timeout" env:"DOCKER_WAIT_FOR_SERVICES_TIMEOUT" description:"How long to wait for service startup"`
    62  	AllowedImages          []string         `toml:"allowed_images,omitempty" json:"allowed_images" long:"allowed-images" env:"DOCKER_ALLOWED_IMAGES" description:"Whitelist allowed images"`
    63  	AllowedServices        []string         `toml:"allowed_services,omitempty" json:"allowed_services" long:"allowed-services" env:"DOCKER_ALLOWED_SERVICES" description:"Whitelist allowed services"`
    64  	PullPolicy             DockerPullPolicy `toml:"pull_policy,omitempty" json:"pull_policy" long:"pull-policy" env:"DOCKER_PULL_POLICY" description:"Image pull policy: never, if-not-present, always"`
    65  }
    66  
    67  type DockerMachine struct {
    68  	IdleCount      int      `long:"idle-nodes" env:"MACHINE_IDLE_COUNT" description:"Maximum idle machines"`
    69  	IdleTime       int      `toml:"IdleTime,omitzero" long:"idle-time" env:"MACHINE_IDLE_TIME" description:"Minimum time after node can be destroyed"`
    70  	MaxBuilds      int      `toml:"MaxBuilds,omitzero" long:"max-builds" env:"MACHINE_MAX_BUILDS" description:"Maximum number of builds processed by machine"`
    71  	MachineDriver  string   `long:"machine-driver" env:"MACHINE_DRIVER" description:"The driver to use when creating machine"`
    72  	MachineName    string   `long:"machine-name" env:"MACHINE_NAME" description:"The template for machine name (needs to include %s)"`
    73  	MachineOptions []string `long:"machine-options" env:"MACHINE_OPTIONS" description:"Additional machine creation options"`
    74  }
    75  
    76  type ParallelsConfig struct {
    77  	BaseName         string `toml:"base_name" json:"base_name" long:"base-name" env:"PARALLELS_BASE_NAME" description:"VM name to be used"`
    78  	TemplateName     string `toml:"template_name,omitempty" json:"template_name" long:"template-name" env:"PARALLELS_TEMPLATE_NAME" description:"VM template to be created"`
    79  	DisableSnapshots bool   `toml:"disable_snapshots,omitzero" json:"disable_snapshots" long:"disable-snapshots" env:"PARALLELS_DISABLE_SNAPSHOTS" description:"Disable snapshoting to speedup VM creation"`
    80  }
    81  
    82  type VirtualBoxConfig struct {
    83  	BaseName         string `toml:"base_name" json:"base_name" long:"base-name" env:"VIRTUALBOX_BASE_NAME" description:"VM name to be used"`
    84  	DisableSnapshots bool   `toml:"disable_snapshots,omitzero" json:"disable_snapshots" long:"disable-snapshots" env:"VIRTUALBOX_DISABLE_SNAPSHOTS" description:"Disable snapshoting to speedup VM creation"`
    85  }
    86  
    87  type RunnerCredentials struct {
    88  	URL       string `toml:"url" json:"url" short:"u" long:"url" env:"CI_SERVER_URL" required:"true" description:"Runner URL"`
    89  	Token     string `toml:"token" json:"token" short:"t" long:"token" env:"CI_SERVER_TOKEN" required:"true" description:"Runner token"`
    90  	TLSCAFile string `toml:"tls-ca-file,omitempty" json:"tls-ca-file" long:"tls-ca-file" env:"CI_SERVER_TLS_CA_FILE" description:"File containing the certificates to verify the peer when using HTTPS"`
    91  }
    92  
    93  type CacheConfig struct {
    94  	Type           string `toml:"Type,omitempty" long:"type" env:"CACHE_TYPE" description:"Select caching method: s3, to use S3 buckets"`
    95  	ServerAddress  string `toml:"ServerAddress,omitempty" long:"s3-server-address" env:"S3_SERVER_ADDRESS" description:"S3 Server Address"`
    96  	AccessKey      string `toml:"AccessKey,omitempty" long:"s3-access-key" env:"S3_ACCESS_KEY" description:"S3 Access Key"`
    97  	SecretKey      string `toml:"SecretKey,omitempty" long:"s3-secret-key" env:"S3_SECRET_KEY" description:"S3 Secret Key"`
    98  	BucketName     string `toml:"BucketName,omitempty" long:"s3-bucket-name" env:"S3_BUCKET_NAME" description:"S3 bucket name"`
    99  	BucketLocation string `toml:"BucketLocation,omitempty" long:"s3-bucket-location" env:"S3_BUCKET_LOCATION" description:"S3 location"`
   100  	Insecure       bool   `toml:"Insecure,omitempty" long:"s3-insecure" env:"S3_CACHE_INSECURE" description:"Use insecure mode (without https)"`
   101  }
   102  
   103  type RunnerSettings struct {
   104  	Executor  string `toml:"executor" json:"executor" long:"executor" env:"RUNNER_EXECUTOR" required:"true" description:"Select executor, eg. shell, docker, etc."`
   105  	BuildsDir string `toml:"builds_dir,omitempty" json:"builds_dir" long:"builds-dir" env:"RUNNER_BUILDS_DIR" description:"Directory where builds are stored"`
   106  	CacheDir  string `toml:"cache_dir,omitempty" json:"cache_dir" long:"cache-dir" env:"RUNNER_CACHE_DIR" description:"Directory where build cache is stored"`
   107  
   108  	Environment []string `toml:"environment,omitempty" json:"environment" long:"env" env:"RUNNER_ENV" description:"Custom environment variables injected to build environment"`
   109  
   110  	Shell string `toml:"shell,omitempty" json:"shell" long:"shell" env:"RUNNER_SHELL" description:"Select bash, cmd or powershell"`
   111  
   112  	SSH        *ssh.Config       `toml:"ssh" json:"ssh" group:"ssh executor" namespace:"ssh"`
   113  	Docker     *DockerConfig     `toml:"docker" json:"docker" group:"docker executor" namespace:"docker"`
   114  	Parallels  *ParallelsConfig  `toml:"parallels" json:"parallels" group:"parallels executor" namespace:"parallels"`
   115  	VirtualBox *VirtualBoxConfig `toml:"virtualbox" json:"virtualbox" group:"virtualbox executor" namespace:"virtualbox"`
   116  	Cache      *CacheConfig      `toml:"cache" json:"cache" group:"cache configuration" namespace:"cache"`
   117  	Machine    *DockerMachine    `toml:"machine" json:"machine" group:"docker machine provider" namespace:"machine"`
   118  }
   119  
   120  type RunnerConfig struct {
   121  	Name        string `toml:"name" json:"name" short:"name" long:"description" env:"RUNNER_NAME" description:"Runner name"`
   122  	Limit       int    `toml:"limit,omitzero" json:"limit" long:"limit" env:"RUNNER_LIMIT" description:"Maximum number of builds processed by this runner"`
   123  	OutputLimit int    `toml:"output_limit,omitzero" long:"output-limit" env:"RUNNER_OUTPUT_LIMIT" description:"Maximum build trace size"`
   124  
   125  	RunnerCredentials
   126  	RunnerSettings
   127  }
   128  
   129  type Config struct {
   130  	Concurrent int             `toml:"concurrent" json:"concurrent"`
   131  	User       string          `toml:"user,omitempty" json:"user"`
   132  	Runners    []*RunnerConfig `toml:"runners" json:"runners"`
   133  	ModTime    time.Time       `toml:"-"`
   134  	Loaded     bool            `toml:"-"`
   135  }
   136  
   137  func (c *RunnerCredentials) ShortDescription() string {
   138  	return helpers.ShortenToken(c.Token)
   139  }
   140  
   141  func (c *RunnerCredentials) UniqueID() string {
   142  	return c.URL + c.Token
   143  }
   144  
   145  func (c *RunnerCredentials) Log() *log.Entry {
   146  	if c.ShortDescription() != "" {
   147  		return log.WithField("runner", c.ShortDescription())
   148  	}
   149  	return log.WithFields(log.Fields{})
   150  }
   151  
   152  func (c *RunnerConfig) String() string {
   153  	return fmt.Sprintf("%v url=%v token=%v executor=%v", c.Name, c.URL, c.Token, c.Executor)
   154  }
   155  
   156  func (c *RunnerConfig) GetVariables() BuildVariables {
   157  	var variables BuildVariables
   158  
   159  	for _, environment := range c.Environment {
   160  		if variable, err := ParseVariable(environment); err == nil {
   161  			variable.Internal = true
   162  			variables = append(variables, variable)
   163  		}
   164  	}
   165  
   166  	return variables
   167  }
   168  
   169  func NewConfig() *Config {
   170  	return &Config{
   171  		Concurrent: 1,
   172  	}
   173  }
   174  
   175  func (c *Config) StatConfig(configFile string) error {
   176  	_, err := os.Stat(configFile)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	return nil
   181  }
   182  
   183  func (c *Config) LoadConfig(configFile string) error {
   184  	info, err := os.Stat(configFile)
   185  
   186  	// permission denied is soft error
   187  	if os.IsNotExist(err) {
   188  		return nil
   189  	} else if err != nil {
   190  		return err
   191  	}
   192  
   193  	if _, err = toml.DecodeFile(configFile, c); err != nil {
   194  		return err
   195  	}
   196  
   197  	c.ModTime = info.ModTime()
   198  	c.Loaded = true
   199  	return nil
   200  }
   201  
   202  func (c *Config) SaveConfig(configFile string) error {
   203  	var newConfig bytes.Buffer
   204  	newBuffer := bufio.NewWriter(&newConfig)
   205  
   206  	if err := toml.NewEncoder(newBuffer).Encode(c); err != nil {
   207  		log.Fatalf("Error encoding TOML: %s", err)
   208  		return err
   209  	}
   210  
   211  	if err := newBuffer.Flush(); err != nil {
   212  		return err
   213  	}
   214  
   215  	// create directory to store configuration
   216  	os.MkdirAll(filepath.Dir(configFile), 0700)
   217  
   218  	// write config file
   219  	if err := ioutil.WriteFile(configFile, newConfig.Bytes(), 0600); err != nil {
   220  		return err
   221  	}
   222  
   223  	c.Loaded = true
   224  	return nil
   225  }