Пример #1
0
func (j roleBuildJob) Run() {
	select {
	case <-j.abort:
		j.resultsCh <- nil
		return
	default:
	}

	roleImageName := GetRoleDevImageName(j.repository, j.role, j.role.GetRoleDevVersion())
	if !j.force {
		if hasImage, err := j.dockerManager.HasImage(roleImageName); err != nil {
			j.resultsCh <- err
			return
		} else if hasImage {
			j.ui.Printf("Skipping build of role image %s because it exists\n", color.YellowString(j.role.Name))
			j.resultsCh <- nil
			return
		}
	}

	if j.builder.metricsPath != "" {
		seriesName := fmt.Sprintf("create-role-images::%s", roleImageName)

		stampy.Stamp(j.builder.metricsPath, "fissile", seriesName, "start")
		defer stampy.Stamp(j.builder.metricsPath, "fissile", seriesName, "done")
	}

	j.ui.Printf("Creating Dockerfile for role %s ...\n", color.YellowString(j.role.Name))
	dockerfileDir, err := j.builder.CreateDockerfileDir(j.role, j.baseImageName)
	if err != nil {
		j.resultsCh <- fmt.Errorf("Error creating Dockerfile and/or assets for role %s: %s", j.role.Name, err.Error())
		return
	}

	if j.noBuild {
		j.ui.Printf("Skipping build of role image %s because of flag\n", color.YellowString(j.role.Name))
		j.resultsCh <- nil
		return
	}

	if !strings.HasSuffix(dockerfileDir, string(os.PathSeparator)) {
		dockerfileDir = fmt.Sprintf("%s%c", dockerfileDir, os.PathSeparator)
	}

	j.ui.Printf("Building docker image of %s in %s ...\n", color.YellowString(j.role.Name), color.YellowString(dockerfileDir))

	log := new(bytes.Buffer)
	stdoutWriter := docker.NewFormattingWriter(
		log,
		docker.ColoredBuildStringFunc(roleImageName),
	)

	err = j.dockerManager.BuildImage(dockerfileDir, roleImageName, stdoutWriter)
	if err != nil {
		log.WriteTo(j.ui)
		j.resultsCh <- fmt.Errorf("Error building image: %s", err.Error())
		return
	}
	j.resultsCh <- nil
}
Пример #2
0
// GenerateBaseDockerImage generates a base docker image to be used as a FROM for role images
func (f *Fissile) GenerateBaseDockerImage(targetPath, baseImage, metricsPath string, noBuild bool, repository string) error {
	if metricsPath != "" {
		stampy.Stamp(metricsPath, "fissile", "create-role-base", "start")
		defer stampy.Stamp(metricsPath, "fissile", "create-role-base", "done")
	}

	dockerManager, err := docker.NewImageManager()
	if err != nil {
		return fmt.Errorf("Error connecting to docker: %s", err.Error())
	}

	baseImageName := builder.GetBaseImageName(repository, f.Version)

	image, err := dockerManager.FindImage(baseImageName)
	if err == docker.ErrImageNotFound {
		f.UI.Println("Image doesn't exist, it will be created ...")
	} else if err != nil {
		return fmt.Errorf("Error looking up image: %s", err.Error())
	} else {
		f.UI.Println(color.GreenString(
			"Base role image %s with ID %s already exists. Doing nothing.",
			color.YellowString(baseImageName),
			color.YellowString(image.ID),
		))
		return nil
	}

	if !strings.HasSuffix(targetPath, string(os.PathSeparator)) {
		targetPath = fmt.Sprintf("%s%c", targetPath, os.PathSeparator)
	}

	baseImageBuilder := builder.NewBaseImageBuilder(baseImage)

	if noBuild {
		f.UI.Println("Skipping image build because of flag.")
		return nil
	}

	f.UI.Println("Building base docker image ...")
	log := new(bytes.Buffer)
	stdoutWriter := docker.NewFormattingWriter(
		log,
		docker.ColoredBuildStringFunc(baseImageName),
	)

	tarPopulator := baseImageBuilder.NewDockerPopulator()
	err = dockerManager.BuildImageFromCallback(baseImageName, stdoutWriter, tarPopulator)
	if err != nil {
		log.WriteTo(f.UI)
		return fmt.Errorf("Error building base image: %s", err)
	}
	f.UI.Println(color.GreenString("Done."))

	return nil
}
Пример #3
0
// GeneratePackagesRoleImage builds the docker image for the packages layer
// where all packages are included
func (f *Fissile) GeneratePackagesRoleImage(repository string, roleManifest *model.RoleManifest, noBuild, force bool, packagesImageBuilder *builder.PackagesImageBuilder) error {
	if len(f.releases) == 0 {
		return fmt.Errorf("Releases not loaded")
	}

	dockerManager, err := docker.NewImageManager()
	if err != nil {
		return fmt.Errorf("Error connecting to docker: %s", err.Error())
	}

	packagesLayerImageName := packagesImageBuilder.GetRolePackageImageName(roleManifest)
	if !force {
		if hasImage, err := dockerManager.HasImage(packagesLayerImageName); err == nil && hasImage {
			f.UI.Printf("Packages layer %s already exists. Skipping ...\n", color.YellowString(packagesLayerImageName))
			return nil
		}
	}

	baseImageName := builder.GetBaseImageName(repository, f.Version)
	if hasImage, err := dockerManager.HasImage(baseImageName); err != nil {
		return fmt.Errorf("Error getting base image: %s", err)
	} else if !hasImage {
		return fmt.Errorf("Failed to find role base %s, did you build it first?", baseImageName)
	}

	if noBuild {
		f.UI.Println("Skipping packages layer docker image build because of --no-build flag.")
		return nil
	}

	f.UI.Printf("Building packages layer docker image %s ...\n",
		color.YellowString(packagesLayerImageName))
	log := new(bytes.Buffer)
	stdoutWriter := docker.NewFormattingWriter(
		log,
		docker.ColoredBuildStringFunc(packagesLayerImageName),
	)

	tarPopulator := packagesImageBuilder.NewDockerPopulator(roleManifest, force)
	err = dockerManager.BuildImageFromCallback(packagesLayerImageName, stdoutWriter, tarPopulator)
	if err != nil {
		log.WriteTo(f.UI)
		return fmt.Errorf("Error building packages layer docker image: %s", err.Error())
	}
	f.UI.Println(color.GreenString("Done."))

	return nil
}
Пример #4
0
func (c *Compilator) compilePackage(pkg *model.Package) (err error) {
	// Prepare input dir (package plus deps)
	if err := c.createCompilationDirStructure(pkg); err != nil {
		return err
	}

	if err := c.copyDependencies(pkg); err != nil {
		return err
	}

	// Generate a compilation script
	targetScriptName := "compile.sh"
	hostScriptPath := filepath.Join(pkg.GetTargetPackageSourcesDir(c.hostWorkDir), targetScriptName)
	containerScriptPath := filepath.Join(docker.ContainerInPath, targetScriptName)
	if err := compilation.SaveScript(c.baseType, compilation.CompilationScript, hostScriptPath); err != nil {
		return err
	}

	// Extract package
	extractDir := c.getSourcePackageDir(pkg)
	if _, err := pkg.Extract(extractDir); err != nil {
		return err
	}

	// Run compilation in container
	containerName := c.getPackageContainerName(pkg)

	// in-memory buffer of the log
	log := new(bytes.Buffer)

	stdoutWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-%s > %s", color.MagentaString("%s", pkg.Name), color.WhiteString("%s", line))
		},
	)
	stderrWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-%s > %s", color.MagentaString("%s", pkg.Name), color.RedString("%s", line))
		},
	)
	sourceMountName := fmt.Sprintf("source_mount-%s", uuid.New())
	mounts := map[string]string{
		pkg.GetTargetPackageSourcesDir(c.hostWorkDir): docker.ContainerInPath,
		pkg.GetPackageCompiledTempDir(c.hostWorkDir):  docker.ContainerOutPath,
		// Add the volume mount to work around AUFS issues.  We will clean
		// the volume up (as long as we're not trying to keep the container
		// around for debugging).  We don't give it an actual directory to mount
		// from, so it will be in some docker-maintained storage.
		sourceMountName: ContainerSourceDir,
	}
	exitCode, container, err := c.dockerManager.RunInContainer(docker.RunInContainerOpts{
		ContainerName: containerName,
		ImageName:     c.BaseImageName(),
		Cmd:           []string{"bash", containerScriptPath, pkg.Name, pkg.Version},
		Mounts:        mounts,
		Volumes:       map[string]map[string]string{sourceMountName: nil},
		KeepContainer: c.keepContainer,
		StdoutWriter:  stdoutWriter,
		StderrWriter:  stderrWriter,
	})

	if container != nil && (!c.keepContainer || err == nil || exitCode == 0) {
		// Attention. While the assignments to 'err' in the
		// deferal below take effect after the 'return'
		// statements coming later they are visible to the
		// caller, i.e.  override the 'return'ed value,
		// because 'err' is a __named__ return parameter.
		defer func() {
			// Remove container - dockerManager.RemoveContainer does a force-rm

			if removeErr := c.dockerManager.RemoveContainer(container.ID); removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf("Error compiling package: %s. Error removing package: %s", err.Error(), removeErr.Error())
				}
			}

			if removeErr := c.dockerManager.RemoveVolumes(container); removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf("%s: Error removing volumes for package %s: %s", err, pkg.Name, removeErr)
				}
			}
		}()
	}

	if err != nil {
		log.WriteTo(c.ui)
		return fmt.Errorf("Error compiling package %s: %s", pkg.Name, err.Error())
	}

	if exitCode != 0 {
		log.WriteTo(c.ui)
		return fmt.Errorf("Error - compilation for package %s exited with code %d", pkg.Name, exitCode)
	}

	return os.Rename(
		pkg.GetPackageCompiledTempDir(c.hostWorkDir),
		pkg.GetPackageCompiledDir(c.hostWorkDir))
}
Пример #5
0
// CreateCompilationBase will create the compiler container
func (c *Compilator) CreateCompilationBase(baseImageName string) (image *dockerClient.Image, err error) {
	imageTag := c.baseCompilationImageTag()
	imageName := c.BaseImageName()
	c.ui.Println(color.GreenString("Using %s as a compilation image name", color.YellowString(imageName)))

	containerName := c.baseCompilationContainerName()
	c.ui.Println(color.GreenString("Using %s as a compilation container name", color.YellowString(containerName)))

	image, err = c.dockerManager.FindImage(imageName)
	if err != nil {
		c.ui.Println("Image doesn't exist, it will be created ...")
	} else {
		c.ui.Println(color.GreenString(
			"Compilation image %s with ID %s already exists. Doing nothing.",
			color.YellowString(imageName),
			color.YellowString(image.ID),
		))
		return image, nil
	}

	tempScriptDir, err := util.TempDir("", "fissile-compilation")
	if err != nil {
		return nil, fmt.Errorf("Could not create temp dir %s: %s", tempScriptDir, err.Error())
	}
	defer os.RemoveAll(tempScriptDir)

	targetScriptName := "compilation-prerequisites.sh"
	containerScriptPath := filepath.Join(docker.ContainerInPath, targetScriptName)
	hostScriptPath := filepath.Join(tempScriptDir, targetScriptName)
	if err = compilation.SaveScript(c.baseType, compilation.PrerequisitesScript, hostScriptPath); err != nil {
		return nil, fmt.Errorf("Error saving script asset: %s", err.Error())
	}

	// in-memory buffer of the log
	log := new(bytes.Buffer)

	stdoutWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-container > %s", color.WhiteString("%s", line))
		},
	)
	stderrWriter := docker.NewFormattingWriter(
		log,
		func(line string) string {
			return color.GreenString("compilation-container > %s", color.RedString("%s", line))
		},
	)
	exitCode, container, err := c.dockerManager.RunInContainer(docker.RunInContainerOpts{
		ContainerName: containerName,
		ImageName:     baseImageName,
		Cmd:           []string{"bash", "-c", containerScriptPath},
		Mounts:        map[string]string{tempScriptDir: docker.ContainerInPath},
		KeepContainer: false, // There is never a need to keep this container on failure
		StdoutWriter:  stdoutWriter,
		StderrWriter:  stderrWriter,
	})
	if container != nil {
		defer func() {
			removeErr := c.dockerManager.RemoveContainer(container.ID)
			if removeErr != nil {
				if err == nil {
					err = removeErr
				} else {
					err = fmt.Errorf(
						"Image creation error: %s. Image removal error: %s",
						err,
						removeErr,
					)
				}
			}
		}()
	}

	if err != nil {
		log.WriteTo(c.ui)
		return nil, fmt.Errorf("Error running script: %s", err.Error())
	}

	if exitCode != 0 {
		log.WriteTo(c.ui)
		return nil, fmt.Errorf("Error - script script exited with code %d", exitCode)
	}

	image, err = c.dockerManager.CreateImage(
		container.ID,
		c.baseCompilationImageRepository(),
		imageTag,
		"",
		[]string{},
	)

	if err != nil {
		return nil, fmt.Errorf("Error creating image %s", err.Error())
	}

	c.ui.Println(color.GreenString(
		"Image %s with ID %s created successfully.",
		color.YellowString(c.BaseImageName()),
		color.YellowString(image.ID)))

	return image, nil
}