func (s *Command) Connect() error { host := helpers.StringOrDefault(s.Host, "localhost") user := helpers.StringOrDefault(s.User, "root") port := helpers.StringOrDefault(s.Port, "22") methods, err := s.getSSHAuthMethods() if err != nil { return err } config := &ssh.ClientConfig{ User: user, Auth: methods, } connectRetries := s.ConnectRetries if connectRetries == 0 { connectRetries = 3 } var finalError error for i := 0; i < connectRetries; i++ { client, err := ssh.Dial("tcp", host+":"+port, config) if err == nil { s.client = client return nil } time.Sleep(sshRetryInterval * time.Second) finalError = err } return finalError }
func (s *DockerExecutor) createContainer(containerType, imageName string, cmd []string, options docker.CreateContainerOptions) (container *docker.Container, err error) { hostname := helpers.StringOrDefault(s.Config.Docker.Hostname, s.Build.ProjectUniqueName()) containerName := s.Build.ProjectUniqueName() + "-" + containerType // Fetch image image, err := s.getDockerImage(imageName) if err != nil { return nil, err } // Fill container options options.Name = containerName options.Config.Image = image.ID options.Config.Hostname = hostname options.Config.Cmd = cmd options.Config.Labels = s.getLabels(containerType) // this will fail potentially some builds if there's name collision s.removeContainer(containerName) s.Debugln("Creating container", options.Name, "...") container, err = s.client.CreateContainer(options) if err != nil { if container != nil { go s.removeContainer(container.ID) } return nil, err } s.builds = append(s.builds, container) return }
func (e *AbstractExecutor) generateShellScript() error { script := &e.Shell script.Build = e.Build script.Shell = helpers.StringOrDefault(e.Config.Shell, script.Shell) // Add config variables for _, environment := range e.Config.Environment { keyValue := strings.SplitN(environment, "=", 2) if len(keyValue) != 2 { continue } variable := common.BuildVariable{ Key: keyValue[0], Value: keyValue[1], } script.Environment = append(script.Environment, variable) } // Add secure variables script.Environment = append(script.Environment, e.Build.Variables...) // Generate shell script shellScript, err := common.GenerateShellScript(*script) if err != nil { return err } e.ShellScript = shellScript e.Debugln("Shell script:", shellScript) return nil }
func (e *AbstractExecutor) startBuild() error { // Craete pipe where data are read reader, writer := io.Pipe() go e.ReadTrace(reader) e.BuildLog = writer // Save hostname if e.ShowHostname { e.Build.Hostname, _ = os.Hostname() } // Deduce build directory buildsDir := helpers.StringOrDefault(e.Config.BuildsDir, e.DefaultBuildsDir) if e.SharedBuildsDir { buildsDir = filepath.Join(buildsDir, e.Build.ProjectUniqueDir()) } if slug, err := e.Build.ProjectSlug(); err == nil { buildsDir = filepath.Join(buildsDir, slug) } // Start actual build e.Build.StartBuild(buildsDir) return nil }
func (e *AbstractExecutor) startBuild() error { // Create pipe where data are read reader, writer := io.Pipe() e.BuildLog = writer go e.readTrace(reader) go e.updateTrace(e.Config, e.buildCanceled, e.finishUpdateTrace) // Save hostname if e.ShowHostname { e.Build.Hostname, _ = os.Hostname() } // Start actual build rootDir := helpers.StringOrDefault(e.Config.BuildsDir, e.DefaultBuildsDir) cacheDir := helpers.StringOrDefault(e.Config.CacheDir, e.DefaultCacheDir) e.Build.StartBuild(rootDir, cacheDir, e.SharedBuildsDir) return nil }
func (e *AbstractExecutor) generateShellScript() error { shell := helpers.StringOrDefault(e.Config.Shell, e.DefaultShell) shellScript, err := common.GenerateShellScript(shell, e.Build, e.ShellType) if err != nil { return err } e.ShellScript = shellScript e.Debugln("Shell script:", shellScript) return nil }
func (e *AbstractExecutor) startBuild() error { // Create pipe where data are read reader, writer := io.Pipe() go e.ReadTrace(reader) e.BuildLog = writer // Save hostname if e.ShowHostname { e.Build.Hostname, _ = os.Hostname() } // Start actual build rootDir := helpers.StringOrDefault(e.Config.BuildsDir, e.DefaultBuildsDir) e.Build.StartBuild(rootDir, e.SharedBuildsDir) return nil }
func (s *ParallelsExecutor) createVM() error { baseImage := s.Config.Parallels.BaseName if baseImage == "" { return errors.New("Missing Image setting from Parallels config") } templateName := helpers.StringOrDefault(s.Config.Parallels.TemplateName, baseImage+"-template") // remove invalid template (removed?) templateStatus, _ := prl.Status(templateName) if templateStatus == prl.Invalid { prl.Unregister(templateName) } if !prl.Exist(templateName) { s.Debugln("Creating template from VM", baseImage, "...") err := prl.CreateTemplate(baseImage, templateName) if err != nil { return err } } s.Debugln("Creating runner from VM template...") err := prl.CreateOsVM(s.vmName, templateName) if err != nil { return err } s.Debugln("Bootstraping VM...") err = prl.Start(s.vmName) if err != nil { return err } s.Debugln("Waiting for VM to start...") err = prl.TryExec(s.vmName, 120, "exit", "0") if err != nil { return err } s.Debugln("Waiting for VM to become responsive...") err = s.verifyMachine(s.vmName) if err != nil { return err } return nil }
func (s *DockerExecutor) addCacheVolume(binds, volumesFrom *[]string, containerPath string) error { var err error containerPath = s.getAbsoluteContainerPath(containerPath) // disable cache for automatic container cache, but leave it for host volumes (they are shared on purpose) if helpers.BoolOrDefault(s.Config.Docker.DisableCache, false) { s.Debugln("Container cache for", containerPath, " is disabled.") return nil } hash := md5.Sum([]byte(containerPath)) // use host-based cache if cacheDir := helpers.StringOrDefault(s.Config.Docker.CacheDir, ""); cacheDir != "" { hostPath := fmt.Sprintf("%s/%s/%x", cacheDir, s.Build.ProjectUniqueName(), hash) hostPath, err := filepath.Abs(hostPath) if err != nil { return err } s.Debugln("Using path", hostPath, "as cache for", containerPath, "...") *binds = append(*binds, fmt.Sprintf("%v:%v", hostPath, containerPath)) return nil } // get existing cache container containerName := fmt.Sprintf("%s-cache-%x", s.Build.ProjectUniqueName(), hash) container, _ := s.client.InspectContainer(containerName) // check if we have valid cache, if not remove the broken container if container != nil && container.Volumes[containerPath] == "" { s.removeContainer(container.ID) container = nil } // create new cache container for that project if container == nil { container, err = s.createCacheVolume(containerName, containerPath) if err != nil { return err } } s.Debugln("Using container", container.ID, "as cache", containerPath, "...") *volumesFrom = append(*volumesFrom, container.ID) return nil }
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 } s.Println("Pulling docker image", imageName, "...") pullImageOptions := docker.PullImageOptions{ Repository: imageName, Registry: helpers.StringOrDefault(s.Config.Docker.Registry, ""), } err = s.client.PullImage(pullImageOptions, docker.AuthConfiguration{}) if err != nil { return nil, err } return s.client.InspectImage(imageName) }
func Connect(c DockerCredentials, apiVersion string) (*docker.Client, error) { endpoint := "unix:///var/run/docker.sock" tlsVerify := false tlsCertPath := "" if host := helpers.StringOrDefault(c.Host, ""); host != "" { // read docker config from config endpoint = host if c.CertPath != nil { tlsVerify = true tlsCertPath = *c.CertPath } } else if host := os.Getenv("DOCKER_HOST"); host != "" { // read docker config from environment endpoint = host tlsVerify, _ = strconv.ParseBool(os.Getenv("DOCKER_TLS_VERIFY")) tlsCertPath = os.Getenv("DOCKER_CERT_PATH") } if tlsVerify { client, err := docker.NewVersionnedTLSClient( endpoint, filepath.Join(tlsCertPath, "cert.pem"), filepath.Join(tlsCertPath, "key.pem"), filepath.Join(tlsCertPath, "ca.pem"), apiVersion, ) if err != nil { return nil, err } return client, nil } else { client, err := docker.NewVersionedClient(endpoint, apiVersion) if err != nil { return nil, err } return client, nil } }
func (e *AbstractExecutor) updateShell() error { script := &e.Shell script.Build = e.Build script.Shell = helpers.StringOrDefault(e.Config.Shell, script.Shell) // Add config variables for _, environment := range e.Config.Environment { keyValue := strings.SplitN(environment, "=", 2) if len(keyValue) != 2 { continue } variable := common.BuildVariable{ Key: keyValue[0], Value: keyValue[1], } script.Environment = append(script.Environment, variable) } // Add secure variables script.Environment = append(script.Environment, e.Build.Variables...) return nil }
func (s *DockerExecutor) createContainer(image *docker.Image, cmd []string) (*docker.Container, error) { 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 s.removeContainer(containerName) createContainerOptions := docker.CreateContainerOptions{ Name: containerName, Config: &docker.Config{ Hostname: hostname, Image: image.ID, Tty: false, AttachStdin: true, AttachStdout: true, AttachStderr: true, OpenStdin: true, StdinOnce: true, Env: s.ShellScript.Environment, Cmd: cmd, }, HostConfig: &docker.HostConfig{ Privileged: s.Config.Docker.Privileged, RestartPolicy: docker.NeverRestart(), ExtraHosts: s.Config.Docker.ExtraHosts, Links: s.Config.Docker.Links, }, } s.Debugln("Creating services...") links, err := s.createServices() if err != nil { return nil, err } createContainerOptions.HostConfig.Links = append(createContainerOptions.HostConfig.Links, links...) s.Debugln("Creating cache directories...") binds, volumesFrom, err := s.createVolumes(image) if err != nil { return nil, err } createContainerOptions.HostConfig.Binds = binds createContainerOptions.HostConfig.VolumesFrom = volumesFrom s.Debugln("Creating container", createContainerOptions.Name, "...") container, err := s.client.CreateContainer(createContainerOptions) if err != nil { if container != nil { go s.removeContainer(container.ID) } return nil, err } s.Debugln("Starting container", container.ID, "...") err = s.client.StartContainer(container.ID, createContainerOptions.HostConfig) if err != nil { go s.removeContainer(container.ID) return nil, err } return container, nil }
func (e *AbstractExecutor) updateShell() error { script := &e.Shell script.Build = e.Build script.Shell = helpers.StringOrDefault(e.Config.Shell, script.Shell) return nil }