Commit 92b01edc authored by Kamil Trzciński's avatar Kamil Trzciński 🔴

Make most of the config options optional

parent 775b150a
......@@ -3,6 +3,7 @@ v 0.3.0
- Build path includes repository hostname
- Support TLS connection with Docker
- Default concurrent limit is set to number of CPUs
- Make most of the config options optional
v 0.2.0
- Added delete and verify commands
......
......@@ -15,6 +15,8 @@ import (
"errors"
"fmt"
"github.com/ayufan/gitlab-ci-multi-runner/common"
"github.com/ayufan/gitlab-ci-multi-runner/helpers"
"math"
)
type RunnerHealth struct {
......@@ -151,7 +153,8 @@ func (mr *MultiRunner) requestBuild(runner *common.RunnerConfig) *common.Build {
}
count := mr.buildsForRunner(runner)
if runner.Limit > 0 && count >= runner.Limit {
limit := helpers.NonZeroOrDefault(runner.Limit, math.MaxInt32)
if count >= limit {
return nil
}
......
......@@ -115,11 +115,19 @@ func (s *SetupContext) askParallels(runnerConfig *common.RunnerConfig) {
func (s *SetupContext) askSSH(runnerConfig *common.RunnerConfig, serverless bool) {
runnerConfig.SSH = &ssh.Config{}
if !serverless {
runnerConfig.SSH.Host = s.ask("ssh-host", "Please enter the SSH server address (eg. my.server.com):")
runnerConfig.SSH.Port = s.ask("ssh-port", "Please enter the SSH server port (eg. 22):", true)
if host := s.ask("ssh-host", "Please enter the SSH server address (eg. my.server.com):"); host != "" {
runnerConfig.SSH.Host = &host
}
if port := s.ask("ssh-port", "Please enter the SSH server port (eg. 22):", true); port != "" {
runnerConfig.SSH.Port = &port
}
}
if user := s.ask("ssh-user", "Please enter the SSH user (eg. root):"); user != "" {
runnerConfig.SSH.User = &user
}
if password := s.ask("ssh-password", "Please enter the SSH password (eg. docker.io):"); password != "" {
runnerConfig.SSH.Password = &password
}
runnerConfig.SSH.User = s.ask("ssh-user", "Please enter the SSH user (eg. root):")
runnerConfig.SSH.Password = s.ask("ssh-password", "Please enter the SSH password (eg. docker.io):")
}
func (s *SetupContext) touchConfig() {
......@@ -204,7 +212,6 @@ func runSetup(c *cli.Context) {
}
runnerConfig.Executor = s.askExecutor()
runnerConfig.DisableVerbose = s.Bool("disable-verbose-output")
switch runnerConfig.Executor {
case "docker", "docker-ssh":
......@@ -288,11 +295,6 @@ func init() {
Usage: "Select executor, eg. shell, docker, etc.",
EnvVar: "RUNNER_EXECUTOR",
},
cli.BoolFlag{
Name: "disable-verbose-output",
Usage: "Disables printing of shell commands to build log",
EnvVar: "RUNNER_DISABLE_VERBOSE_OUTPUT",
},
// Docker specific configuration
cli.StringFlag{
......
......@@ -51,12 +51,14 @@ func runHerokuURL(addr string) error {
}
func runSingle(c *cli.Context) {
buildsDir := c.String("builds-dir")
shell := c.String("shell")
runner := common.RunnerConfig{
URL: c.String("url"),
Token: c.String("token"),
Executor: c.String("executor"),
BuildsDir: c.String("builds-dir"),
Shell: c.String("shell"),
BuildsDir: &buildsDir,
Shell: &shell,
}
if len(runner.URL) == 0 {
......
......@@ -15,16 +15,15 @@ import (
)
type DockerConfig struct {
Host string `toml:"host" json:"host"`
Host *string `toml:"host" json:"host"`
CertPath *string `toml:"tls_cert_path" json:"tls_cert_path"`
Hostname string `toml:"hostname" json:"hostname"`
Hostname *string `toml:"hostname" json:"hostname"`
Image string `toml:"image" json:"image"`
Privileged bool `toml:"privileged" json:"privileged"`
DisableCache bool `toml:"disable_cache" json:"disable_cache"`
DisablePull bool `toml:"disable_pull" json:"disable_pull"`
DisableCache *bool `toml:"disable_cache" json:"disable_cache"`
Volumes []string `toml:"volumes" json:"volumes"`
CacheDir string `toml:"cache_dir" json:"cache_dir"`
Registry string `toml:"registry" json:"registry"`
CacheDir *string `toml:"cache_dir" json:"cache_dir"`
Registry *string `toml:"registry" json:"registry"`
ExtraHosts []string `toml:"extra_hosts" json:"extra_hosts"`
Links []string `toml:"links" json:"links"`
Services []string `toml:"services" json:"services"`
......@@ -32,24 +31,24 @@ type DockerConfig struct {
}
type ParallelsConfig struct {
BaseName string `toml:"base_name" json:"base_name"`
TemplateName string `toml:"template_name" json:"template_name"`
DisableSnapshots bool `toml:"disable_snapshots" json:"disable_snapshots"`
BaseName string `toml:"base_name" json:"base_name"`
TemplateName *string `toml:"template_name" json:"template_name"`
DisableSnapshots *bool `toml:"disable_snapshots" json:"disable_snapshots"`
}
type RunnerConfig struct {
Name string `toml:"name" json:"name"`
URL string `toml:"url" json:"url"`
Token string `toml:"token" json:"token"`
Limit int `toml:"limit" json:"limit"`
Executor string `toml:"executor" json:"executor"`
BuildsDir string `toml:"builds_dir" json:"builds_dir"`
CleanEnvironment bool `toml:"clean_environment" json:"clean_environment"`
Name string `toml:"name" json:"name"`
URL string `toml:"url" json:"url"`
Token string `toml:"token" json:"token"`
Limit *int `toml:"limit" json:"limit"`
Executor string `toml:"executor" json:"executor"`
BuildsDir *string `toml:"builds_dir" json:"builds_dir"`
CleanEnvironment *bool `toml:"clean_environment" json:"clean_environment"`
Environment []string `toml:"environment" json:"environment"`
Shell string `toml:"shell" json:"shell"`
DisableVerbose bool `toml:"disable_verbose" json:"disable_verbose"`
Shell *string `toml:"shell" json:"shell"`
DisableVerbose *bool `toml:"disable_verbose" json:"disable_verbose"`
SSH *ssh.Config `toml:"ssh" json:"ssh"`
Docker *DockerConfig `toml:"docker" json:"docker"`
......
......@@ -15,6 +15,7 @@ import (
"github.com/ayufan/gitlab-ci-multi-runner/common"
"github.com/ayufan/gitlab-ci-multi-runner/executors"
"github.com/ayufan/gitlab-ci-multi-runner/helpers"
)
type DockerExecutor struct {
......@@ -25,21 +26,17 @@ type DockerExecutor struct {
services []*docker.Container
}
func (s *DockerExecutor) getImage(imageName string, pullImage bool) (*docker.Image, error) {
func (s *DockerExecutor) getImage(imageName string) (*docker.Image, error) {
s.Debugln("Looking for image", imageName, "...")
image, err := s.client.InspectImage(imageName)
if err == nil {
return image, nil
}
if !pullImage {
return nil, err
}
s.Println("Pulling docker image", imageName, "...")
pullImageOptions := docker.PullImageOptions{
Repository: imageName,
Registry: s.Config.Docker.Registry,
Registry: helpers.StringOrDefault(s.Config.Docker.Registry, ""),
}
err = s.client.PullImage(pullImageOptions, docker.AuthConfiguration{})
......@@ -69,7 +66,7 @@ func (s *DockerExecutor) addCacheVolume(binds, volumesFrom *[]string, containerP
containerPath = s.getAbsoluteContainerPath(containerPath)
// disable cache for automatic container cache, but leave it for host volumes (they are shared on purpose)
if s.Config.Docker.DisableCache {
if helpers.BoolOrDefault(s.Config.Docker.DisableCache, false) {
s.Debugln("Container cache for", containerPath, " is disabled.")
return nil
}
......@@ -77,7 +74,7 @@ func (s *DockerExecutor) addCacheVolume(binds, volumesFrom *[]string, containerP
hash := md5.Sum([]byte(containerPath))
// use host-based cache
if s.Config.Docker.CacheDir != "" {
if cacheDir := helpers.StringOrDefault(s.Config.Docker.CacheDir, ""); cacheDir != "" {
hostPath := fmt.Sprintf("%s/%s/%x", s.Config.Docker.CacheDir, s.Build.ProjectUniqueName(), hash)
hostPath, err := filepath.Abs(hostPath)
if err != nil {
......@@ -101,7 +98,7 @@ func (s *DockerExecutor) addCacheVolume(binds, volumesFrom *[]string, containerP
// create new cache container for that project
if container == nil {
// get busybox image
cacheImage, err := s.getImage("busybox:latest", true)
cacheImage, err := s.getImage("busybox:latest")
if err != nil {
return err
}
......@@ -193,7 +190,7 @@ func (s *DockerExecutor) createService(service, version string) (*docker.Contain
return nil, errors.New("Invalid service name")
}
serviceImage, err := s.getImage(service+":"+version, !s.Config.Docker.DisablePull)
serviceImage, err := s.getImage(service + ":" + version)
if err != nil {
return nil, err
}
......@@ -273,9 +270,9 @@ func (s *DockerExecutor) connect() (*docker.Client, error) {
tlsVerify := false
tlsCertPath := ""
if s.Config.Docker.Host != "" {
if host := helpers.StringOrDefault(s.Config.Docker.Host, ""); host != "" {
// read docker config from config
endpoint = s.Config.Docker.Host
endpoint = host
if s.Config.Docker.CertPath != nil {
tlsVerify = true
tlsCertPath = *s.Config.Docker.CertPath
......@@ -310,11 +307,7 @@ func (s *DockerExecutor) connect() (*docker.Client, error) {
}
func (s *DockerExecutor) createContainer(image *docker.Image, cmd []string) (*docker.Container, error) {
hostname := s.Config.Docker.Hostname
if hostname == "" {
hostname = s.Build.ProjectUniqueName()
}
hostname := helpers.StringOrDefault(s.Config.Docker.Hostname, s.Build.ProjectUniqueName())
containerName := s.Build.ProjectUniqueName()
// this will fail potentially some builds if there's name collision
......@@ -410,7 +403,7 @@ func (s *DockerExecutor) Prepare(config *common.RunnerConfig, build *common.Buil
s.client = client
// Get image
image, err := s.getImage(s.Config.Docker.Image, !s.Config.Docker.DisablePull)
image, err := s.getImage(s.Config.Docker.Image)
if err != nil {
return err
}
......@@ -432,7 +425,7 @@ func (s *DockerExecutor) Cleanup() {
}
func (s *DockerExecutor) waitForServiceContainer(container *docker.Container, timeout time.Duration) error {
waitImage, err := s.getImage("aanand/wait", !s.Config.Docker.DisablePull)
waitImage, err := s.getImage("aanand/wait")
if err != nil {
return err
}
......
......@@ -41,7 +41,7 @@ func (s *DockerSSHExecutor) Start() error {
Stdout: s.BuildLog,
Stderr: s.BuildLog,
}
s.sshCommand.Host = containerData.NetworkSettings.IPAddress
s.sshCommand.Host = &containerData.NetworkSettings.IPAddress
s.Debugln("Connecting to SSH server...")
err = s.sshCommand.Connect()
......
......@@ -8,6 +8,7 @@ import (
"bufio"
log "github.com/Sirupsen/logrus"
"github.com/ayufan/gitlab-ci-multi-runner/common"
"github.com/ayufan/gitlab-ci-multi-runner/helpers"
"io"
"path/filepath"
)
......@@ -121,11 +122,7 @@ func (e *AbstractExecutor) Errorln(args ...interface{}) {
}
func (e *AbstractExecutor) generateShellScript() error {
shell := e.DefaultShell
if e.Config.Shell != "" {
shell = e.Config.Shell
}
shell := helpers.StringOrDefault(e.Config.Shell, e.DefaultShell)
shellScript, err := common.GenerateShellScript(shell, e.Build)
if err != nil {
return err
......@@ -147,10 +144,8 @@ func (e *AbstractExecutor) startBuild() error {
}
// Deduce build directory
buildsDir := e.DefaultBuildsDir
if e.Config.BuildsDir != "" {
buildsDir = e.Config.BuildsDir
}
buildsDir := helpers.StringOrDefault(e.Config.BuildsDir, e.DefaultBuildsDir)
if e.SharedBuildsDir {
buildsDir = filepath.Join(buildsDir, e.Build.ProjectUniqueName())
}
......
......@@ -10,6 +10,7 @@ import (
prl "github.com/ayufan/gitlab-ci-multi-runner/parallels"
"github.com/ayufan/gitlab-ci-multi-runner/helpers"
"time"
)
......@@ -68,7 +69,7 @@ func (s *ParallelsExecutor) verifyMachine(vmName string) error {
Stderr: s.BuildLog,
ConnectRetries: 30,
}
sshCommand.Host = ipAddr
sshCommand.Host = &ipAddr
s.Debugln("Connecting to SSH...")
err = sshCommand.Connect()
......@@ -106,10 +107,7 @@ func (s *ParallelsExecutor) createVM() error {
return errors.New("Missing Image setting from Parallels config")
}
templateName := s.Config.Parallels.TemplateName
if templateName == "" {
templateName = baseImage + "-template"
}
templateName := helpers.StringOrDefault(s.Config.Parallels.TemplateName, baseImage+"-template")
// remove invalid template (removed?)
templateStatus, _ := prl.Status(templateName)
......@@ -186,7 +184,7 @@ func (s *ParallelsExecutor) Prepare(config *common.RunnerConfig, build *common.B
prl.Unregister(s.vmName)
}
if s.Config.Parallels.DisableSnapshots {
if helpers.BoolOrDefault(s.Config.Parallels.DisableSnapshots, false) {
s.vmName = s.Config.Parallels.BaseName + "-" + s.Build.ProjectRunnerName
if prl.Exist(s.vmName) {
s.Debugln("Deleting old VM...")
......@@ -216,7 +214,7 @@ func (s *ParallelsExecutor) Prepare(config *common.RunnerConfig, build *common.B
return err
}
if !s.Config.Parallels.DisableSnapshots {
if !helpers.BoolOrDefault(s.Config.Parallels.DisableSnapshots, false) {
s.Println("Creating default snapshot...")
err = prl.CreateSnapshot(s.vmName, "Started")
if err != nil {
......@@ -279,7 +277,7 @@ func (s *ParallelsExecutor) Start() error {
Stdout: s.BuildLog,
Stderr: s.BuildLog,
}
s.sshCommand.Host = ipAddr
s.sshCommand.Host = &ipAddr
s.Debugln("Connecting to SSH server...")
err = s.sshCommand.Connect()
......@@ -303,7 +301,7 @@ func (s *ParallelsExecutor) Cleanup() {
if s.vmName != "" {
prl.Kill(s.vmName)
if s.Config.Parallels.DisableSnapshots || !s.provisioned {
if helpers.BoolOrDefault(s.Config.Parallels.DisableSnapshots, false) || !s.provisioned {
prl.Delete(s.vmName)
}
}
......
......@@ -41,7 +41,7 @@ func (s *ShellExecutor) Start() error {
helpers.SetProcessGroup(s.cmd)
// Inherit environment from current process
if !s.Config.CleanEnvironment {
if !helpers.BoolOrDefault(s.Config.CleanEnvironment, false) {
s.cmd.Env = os.Environ()
}
......
......@@ -19,3 +19,11 @@ func NonZeroOrDefault(data *int, def int) int {
return *data
}
}
func BoolOrDefault(data *bool, def bool) bool {
if data == nil {
return def
} else {
return *data
}
}
......@@ -68,7 +68,7 @@ func (b *BashShell) GenerateScript(build *common.Build) (*common.ShellScript, er
b.writeCheckoutCmd(w, build)
io.WriteString(w, "\n")
if !build.Runner.DisableVerbose {
if !helpers.BoolOrDefault(build.Runner.DisableVerbose, false) {
io.WriteString(w, "set -v\n")
io.WriteString(w, "\n")
}
......
......@@ -85,7 +85,7 @@ func (b *CmdShell) GenerateScript(build *common.Build) (*common.ShellScript, err
continue
}
if !build.Runner.DisableVerbose {
if !helpers.BoolOrDefault(build.Runner.DisableVerbose, false) {
b.writeCommand(w, "echo %s", command)
}
b.writeCommandChecked(w, "%s", command)
......
......@@ -83,7 +83,7 @@ func (b *PowerShell) GenerateScript(build *common.Build) (*common.ShellScript, e
continue
}
if !build.Runner.DisableVerbose {
if !helpers.BoolOrDefault(build.Runner.DisableVerbose, false) {
b.writeCommand(w, "echo \"%s\"", command)
}
b.writeCommandChecked(w, "%s", command)
......
......@@ -28,23 +28,20 @@ type Command struct {
func (s *Command) getSSHAuthMethods() []ssh.AuthMethod {
var methods []ssh.AuthMethod
if len(s.Password) != 0 {
methods = append(methods, ssh.Password(s.Password))
if s.Password != nil {
methods = append(methods, ssh.Password(*s.Password))
}
return methods
}
func (s *Command) Connect() error {
if len(s.User) == 0 {
s.User = "root"
}
if len(s.Port) == 0 {
s.Port = "22"
}
host := helpers.StringOrDefault(s.Host, "localhost")
user := helpers.StringOrDefault(s.User, "root")
port := helpers.StringOrDefault(s.Port, "22")
config := &ssh.ClientConfig{
User: s.User,
User: user,
Auth: s.getSSHAuthMethods(),
}
......@@ -56,7 +53,7 @@ func (s *Command) Connect() error {
var finalError error
for i := 0; i < connectRetries; i++ {
client, err := ssh.Dial("tcp", s.Host+":"+s.Port, config)
client, err := ssh.Dial("tcp", host+":"+port, config)
if err == nil {
s.client = client
return nil
......
package ssh
type Config struct {
User string `toml:"user" json:"user"`
Password string `toml:"password" json:"password"`
Host string `toml:"host" json:"host"`
Port string `toml:"port" json:"port"`
User *string `toml:"user" json:"user"`
Password *string `toml:"password" json:"password"`
Host *string `toml:"host" json:"host"`
Port *string `toml:"port" json:"port"`
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment