// NewDockerPopulator returns a function that will populate the docker tar archive func (b *BaseImageBuilder) NewDockerPopulator() func(*tar.Writer) error { return func(tarWriter *tar.Writer) error { // Generate dockerfile dockerfileContents, err := b.generateDockerfile() if err != nil { return err } err = util.WriteToTarStream(tarWriter, dockerfileContents, tar.Header{ Name: "Dockerfile", }) if err != nil { return err } // Add rsyslog_conf, monitrc.erb, and the post-start handler. for _, assetName := range dockerfiles.AssetNames() { switch { case strings.HasPrefix(assetName, "rsyslog_conf/"): case assetName == "monitrc.erb": case assetName == "post-start.sh": default: continue } assetContents, err := dockerfiles.Asset(assetName) if err != nil { return err } err = util.WriteToTarStream(tarWriter, assetContents, tar.Header{ Name: assetName, }) if err != nil { return err } } // Add configgin configginGzip, err := configgin.Asset("configgin.tgz") if err != nil { return err } err = util.TargzIterate( "configgin.tgz", bytes.NewReader(configginGzip), func(reader *tar.Reader, header *tar.Header) error { header.Name = filepath.Join("configgin", header.Name) if err = tarWriter.WriteHeader(header); err != nil { return err } if _, err = io.Copy(tarWriter, reader); err != nil { return err } return nil }) if err != nil { return err } return nil } }
func TestBuildImageFromCallbackCallbackFailure(t *testing.T) { assert := assert.New(t) doTestBuildImageFromCallback(t, func(tarStream *tar.Writer) error { err := util.WriteToTarStream(tarStream, []byte("FROM scratch\nENV hello=world"), tar.Header{ Name: "Dockerfile", }) assert.NoError(err) return fmt.Errorf("Dummy error") }, func(err error, dockerManager *ImageManager, imageName string) { if assert.Error(err) { assert.EqualError(err, "Dummy error", "Error message should be from callback") } // The image _could_ have been built, since nothing in it is missing hasImage, err := dockerManager.HasImage(imageName) if assert.NoError(err) && hasImage { assert.NoError(dockerManager.RemoveImage(imageName)) } }) }
// NewDockerPopulator returns a function which can populate a tar stream with the docker context to build the packages layer image with func (p *PackagesImageBuilder) NewDockerPopulator(roleManifest *model.RoleManifest, forceBuildAll bool) func(*tar.Writer) error { return func(tarWriter *tar.Writer) error { var err error if len(roleManifest.Roles) == 0 { return fmt.Errorf("No roles to build") } // Collect compiled packages foundFingerprints := make(map[string]struct{}) var packages model.Packages for _, role := range roleManifest.Roles { for _, job := range role.Jobs { for _, pkg := range job.Packages { if _, ok := foundFingerprints[pkg.Fingerprint]; ok { // Package has already been found (possibly due to a different role) continue } packages = append(packages, pkg) foundFingerprints[pkg.Fingerprint] = struct{}{} } } } // Generate dockerfile dockerfile := bytes.Buffer{} baseImageName := GetBaseImageName(p.repository, p.fissileVersion) if !forceBuildAll { baseImageName, packages, err = p.determinePackagesLayerBaseImage(packages) if err != nil { return err } } if err = p.generateDockerfile(baseImageName, packages, &dockerfile); err != nil { return err } err = util.WriteToTarStream(tarWriter, dockerfile.Bytes(), tar.Header{ Name: "Dockerfile", }) if err != nil { return err } // Make sure we have the directory, even if we have no packages to add err = util.WriteToTarStream(tarWriter, []byte{}, tar.Header{ Name: "packages-src", Mode: 0755, Typeflag: tar.TypeDir, }) if err != nil { return err } // Actually insert the packages into the tar stream for _, pkg := range packages { walker := &tarWalker{ stream: tarWriter, root: pkg.GetPackageCompiledDir(p.compiledPackagesPath), prefix: filepath.Join("packages-src", pkg.Fingerprint), } if err = filepath.Walk(walker.root, walker.walk); err != nil { return err } } return nil } }