podman
747 строк · 25.9 Кб
1package buildah
2
3import (
4"context"
5"encoding/json"
6"fmt"
7"os"
8"runtime"
9"strings"
10"time"
11
12"github.com/containers/buildah/define"
13"github.com/containers/buildah/docker"
14internalUtil "github.com/containers/buildah/internal/util"
15"github.com/containers/image/v5/manifest"
16"github.com/containers/image/v5/pkg/compression"
17"github.com/containers/image/v5/transports"
18"github.com/containers/image/v5/types"
19"github.com/containers/storage/pkg/stringid"
20ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
21"github.com/sirupsen/logrus"
22"golang.org/x/exp/slices"
23)
24
25// unmarshalConvertedConfig obtains the config blob of img valid for the wantedManifestMIMEType format
26// (either as it exists, or converting the image if necessary), and unmarshals it into dest.
27// NOTE: The MIME type is of the _manifest_, not of the _config_ that is returned.
28func unmarshalConvertedConfig(ctx context.Context, dest interface{}, img types.Image, wantedManifestMIMEType string) error {
29_, actualManifestMIMEType, err := img.Manifest(ctx)
30if err != nil {
31return fmt.Errorf("getting manifest MIME type for %q: %w", transports.ImageName(img.Reference()), err)
32}
33if wantedManifestMIMEType != actualManifestMIMEType {
34layerInfos := img.LayerInfos()
35for i := range layerInfos { // force the "compression" to gzip, which is supported by all of the formats we care about
36layerInfos[i].CompressionOperation = types.Compress
37layerInfos[i].CompressionAlgorithm = &compression.Gzip
38}
39updatedImg, err := img.UpdatedImage(ctx, types.ManifestUpdateOptions{
40LayerInfos: layerInfos,
41})
42if err != nil {
43return fmt.Errorf("resetting recorded compression for %q: %w", transports.ImageName(img.Reference()), err)
44}
45secondUpdatedImg, err := updatedImg.UpdatedImage(ctx, types.ManifestUpdateOptions{
46ManifestMIMEType: wantedManifestMIMEType,
47})
48if err != nil {
49return fmt.Errorf("converting image %q from %q to %q: %w", transports.ImageName(img.Reference()), actualManifestMIMEType, wantedManifestMIMEType, err)
50}
51img = secondUpdatedImg
52}
53config, err := img.ConfigBlob(ctx)
54if err != nil {
55return fmt.Errorf("reading %s config from %q: %w", wantedManifestMIMEType, transports.ImageName(img.Reference()), err)
56}
57if err := json.Unmarshal(config, dest); err != nil {
58return fmt.Errorf("parsing %s configuration %q from %q: %w", wantedManifestMIMEType, string(config), transports.ImageName(img.Reference()), err)
59}
60return nil
61}
62
63func (b *Builder) initConfig(ctx context.Context, img types.Image, sys *types.SystemContext) error {
64if img != nil { // A pre-existing image, as opposed to a "FROM scratch" new one.
65rawManifest, manifestMIMEType, err := img.Manifest(ctx)
66if err != nil {
67return fmt.Errorf("reading image manifest for %q: %w", transports.ImageName(img.Reference()), err)
68}
69rawConfig, err := img.ConfigBlob(ctx)
70if err != nil {
71return fmt.Errorf("reading image configuration for %q: %w", transports.ImageName(img.Reference()), err)
72}
73b.Manifest = rawManifest
74b.Config = rawConfig
75
76dimage := docker.V2Image{}
77if err := unmarshalConvertedConfig(ctx, &dimage, img, manifest.DockerV2Schema2MediaType); err != nil {
78return err
79}
80b.Docker = dimage
81
82oimage := ociv1.Image{}
83if err := unmarshalConvertedConfig(ctx, &oimage, img, ociv1.MediaTypeImageManifest); err != nil {
84return err
85}
86b.OCIv1 = oimage
87
88if manifestMIMEType == ociv1.MediaTypeImageManifest {
89// Attempt to recover format-specific data from the manifest.
90v1Manifest := ociv1.Manifest{}
91if err := json.Unmarshal(b.Manifest, &v1Manifest); err != nil {
92return fmt.Errorf("parsing OCI manifest %q: %w", string(b.Manifest), err)
93}
94for k, v := range v1Manifest.Annotations {
95b.ImageAnnotations[k] = v
96}
97}
98}
99
100b.setupLogger()
101b.fixupConfig(sys)
102return nil
103}
104
105func (b *Builder) fixupConfig(sys *types.SystemContext) {
106if b.Docker.Config != nil {
107// Prefer image-level settings over those from the container it was built from.
108b.Docker.ContainerConfig = *b.Docker.Config
109}
110b.Docker.Config = &b.Docker.ContainerConfig
111b.Docker.DockerVersion = ""
112now := time.Now().UTC()
113if b.Docker.Created.IsZero() {
114b.Docker.Created = now
115}
116if b.OCIv1.Created == nil || b.OCIv1.Created.IsZero() {
117b.OCIv1.Created = &now
118}
119if b.OS() == "" {
120if sys != nil && sys.OSChoice != "" {
121b.SetOS(sys.OSChoice)
122} else {
123b.SetOS(runtime.GOOS)
124}
125}
126if b.Architecture() == "" {
127if sys != nil && sys.ArchitectureChoice != "" {
128b.SetArchitecture(sys.ArchitectureChoice)
129} else {
130b.SetArchitecture(runtime.GOARCH)
131}
132// in case the arch string we started with was shorthand for a known arch+variant pair, normalize it
133ps := internalUtil.NormalizePlatform(ociv1.Platform{OS: b.OS(), Architecture: b.Architecture(), Variant: b.Variant()})
134b.SetArchitecture(ps.Architecture)
135b.SetVariant(ps.Variant)
136}
137if b.Variant() == "" {
138if sys != nil && sys.VariantChoice != "" {
139b.SetVariant(sys.VariantChoice)
140}
141// in case the arch string we started with was shorthand for a known arch+variant pair, normalize it
142ps := internalUtil.NormalizePlatform(ociv1.Platform{OS: b.OS(), Architecture: b.Architecture(), Variant: b.Variant()})
143b.SetArchitecture(ps.Architecture)
144b.SetVariant(ps.Variant)
145}
146if b.Format == define.Dockerv2ImageManifest && b.Hostname() == "" {
147b.SetHostname(stringid.TruncateID(stringid.GenerateRandomID()))
148}
149}
150
151func (b *Builder) setupLogger() {
152if b.Logger == nil {
153b.Logger = logrus.New()
154b.Logger.SetOutput(os.Stderr)
155b.Logger.SetLevel(logrus.GetLevel())
156}
157}
158
159// Annotations returns a set of key-value pairs from the image's manifest.
160func (b *Builder) Annotations() map[string]string {
161return copyStringStringMap(b.ImageAnnotations)
162}
163
164// SetAnnotation adds or overwrites a key's value from the image's manifest.
165// Note: this setting is not present in the Docker v2 image format, so it is
166// discarded when writing images using Docker v2 formats.
167func (b *Builder) SetAnnotation(key, value string) {
168if b.ImageAnnotations == nil {
169b.ImageAnnotations = map[string]string{}
170}
171b.ImageAnnotations[key] = value
172}
173
174// UnsetAnnotation removes a key and its value from the image's manifest, if
175// it's present.
176func (b *Builder) UnsetAnnotation(key string) {
177delete(b.ImageAnnotations, key)
178}
179
180// ClearAnnotations removes all keys and their values from the image's
181// manifest.
182func (b *Builder) ClearAnnotations() {
183b.ImageAnnotations = map[string]string{}
184}
185
186// CreatedBy returns a description of how this image was built.
187func (b *Builder) CreatedBy() string {
188return b.ImageCreatedBy
189}
190
191// SetCreatedBy sets the description of how this image was built.
192func (b *Builder) SetCreatedBy(how string) {
193b.ImageCreatedBy = how
194}
195
196// OS returns a name of the OS on which the container, or a container built
197// using an image built from this container, is intended to be run.
198func (b *Builder) OS() string {
199return b.OCIv1.OS
200}
201
202// SetOS sets the name of the OS on which the container, or a container built
203// using an image built from this container, is intended to be run.
204func (b *Builder) SetOS(os string) {
205b.OCIv1.OS = os
206b.Docker.OS = os
207}
208
209// OSVersion returns a version of the OS on which the container, or a container
210// built using an image built from this container, is intended to be run.
211func (b *Builder) OSVersion() string {
212return b.OCIv1.OSVersion
213}
214
215// SetOSVersion sets the version of the OS on which the container, or a
216// container built using an image built from this container, is intended to be
217// run.
218func (b *Builder) SetOSVersion(version string) {
219b.OCIv1.OSVersion = version
220b.Docker.OSVersion = version
221}
222
223// OSFeatures returns a list of OS features which the container, or a container
224// built using an image built from this container, depends on the OS supplying.
225func (b *Builder) OSFeatures() []string {
226return copyStringSlice(b.OCIv1.OSFeatures)
227}
228
229// SetOSFeature adds a feature of the OS which the container, or a container
230// built using an image built from this container, depends on the OS supplying.
231func (b *Builder) SetOSFeature(feature string) {
232if !slices.Contains(b.OCIv1.OSFeatures, feature) {
233b.OCIv1.OSFeatures = append(b.OCIv1.OSFeatures, feature)
234}
235if !slices.Contains(b.Docker.OSFeatures, feature) {
236b.Docker.OSFeatures = append(b.Docker.OSFeatures, feature)
237}
238}
239
240// UnsetOSFeature removes a feature of the OS which the container, or a
241// container built using an image built from this container, depends on the OS
242// supplying.
243func (b *Builder) UnsetOSFeature(feature string) {
244if slices.Contains(b.OCIv1.OSFeatures, feature) {
245features := make([]string, 0, len(b.OCIv1.OSFeatures))
246for _, f := range b.OCIv1.OSFeatures {
247if f != feature {
248features = append(features, f)
249}
250}
251b.OCIv1.OSFeatures = features
252}
253if slices.Contains(b.Docker.OSFeatures, feature) {
254features := make([]string, 0, len(b.Docker.OSFeatures))
255for _, f := range b.Docker.OSFeatures {
256if f != feature {
257features = append(features, f)
258}
259}
260b.Docker.OSFeatures = features
261}
262}
263
264// ClearOSFeatures clears the list of features of the OS which the container,
265// or a container built using an image built from this container, depends on
266// the OS supplying.
267func (b *Builder) ClearOSFeatures() {
268b.OCIv1.OSFeatures = []string{}
269b.Docker.OSFeatures = []string{}
270}
271
272// Architecture returns a name of the architecture on which the container, or a
273// container built using an image built from this container, is intended to be
274// run.
275func (b *Builder) Architecture() string {
276return b.OCIv1.Architecture
277}
278
279// SetArchitecture sets the name of the architecture on which the container, or
280// a container built using an image built from this container, is intended to
281// be run.
282func (b *Builder) SetArchitecture(arch string) {
283b.OCIv1.Architecture = arch
284b.Docker.Architecture = arch
285}
286
287// Variant returns a name of the architecture variant on which the container,
288// or a container built using an image built from this container, is intended
289// to be run.
290func (b *Builder) Variant() string {
291return b.OCIv1.Variant
292}
293
294// SetVariant sets the name of the architecture variant on which the container,
295// or a container built using an image built from this container, is intended
296// to be run.
297func (b *Builder) SetVariant(variant string) {
298b.Docker.Variant = variant
299b.OCIv1.Variant = variant
300}
301
302// Maintainer returns contact information for the person who built the image.
303func (b *Builder) Maintainer() string {
304return b.OCIv1.Author
305}
306
307// SetMaintainer sets contact information for the person who built the image.
308func (b *Builder) SetMaintainer(who string) {
309b.OCIv1.Author = who
310b.Docker.Author = who
311}
312
313// User returns information about the user as whom the container, or a
314// container built using an image built from this container, should be run.
315func (b *Builder) User() string {
316return b.OCIv1.Config.User
317}
318
319// SetUser sets information about the user as whom the container, or a
320// container built using an image built from this container, should be run.
321// Acceptable forms are a user name or ID, optionally followed by a colon and a
322// group name or ID.
323func (b *Builder) SetUser(spec string) {
324b.OCIv1.Config.User = spec
325b.Docker.Config.User = spec
326}
327
328// OnBuild returns the OnBuild value from the container.
329func (b *Builder) OnBuild() []string {
330return copyStringSlice(b.Docker.Config.OnBuild)
331}
332
333// ClearOnBuild removes all values from the OnBuild structure
334func (b *Builder) ClearOnBuild() {
335b.Docker.Config.OnBuild = []string{}
336}
337
338// SetOnBuild sets a trigger instruction to be executed when the image is used
339// as the base of another image.
340// Note: this setting is not present in the OCIv1 image format, so it is
341// discarded when writing images using OCIv1 formats.
342func (b *Builder) SetOnBuild(onBuild string) {
343if onBuild != "" && b.Format != define.Dockerv2ImageManifest {
344b.Logger.Warnf("ONBUILD is not supported for OCI image format, %s will be ignored. Must use `docker` format", onBuild)
345}
346b.Docker.Config.OnBuild = append(b.Docker.Config.OnBuild, onBuild)
347}
348
349// WorkDir returns the default working directory for running commands in the
350// container, or in a container built using an image built from this container.
351func (b *Builder) WorkDir() string {
352return b.OCIv1.Config.WorkingDir
353}
354
355// SetWorkDir sets the location of the default working directory for running
356// commands in the container, or in a container built using an image built from
357// this container.
358func (b *Builder) SetWorkDir(there string) {
359b.OCIv1.Config.WorkingDir = there
360b.Docker.Config.WorkingDir = there
361}
362
363// Shell returns the default shell for running commands in the
364// container, or in a container built using an image built from this container.
365func (b *Builder) Shell() []string {
366return copyStringSlice(b.Docker.Config.Shell)
367}
368
369// SetShell sets the default shell for running
370// commands in the container, or in a container built using an image built from
371// this container.
372// Note: this setting is not present in the OCIv1 image format, so it is
373// discarded when writing images using OCIv1 formats.
374func (b *Builder) SetShell(shell []string) {
375if len(shell) > 0 && b.Format != define.Dockerv2ImageManifest {
376b.Logger.Warnf("SHELL is not supported for OCI image format, %s will be ignored. Must use `docker` format", shell)
377}
378
379b.Docker.Config.Shell = copyStringSlice(shell)
380}
381
382// Env returns a list of key-value pairs to be set when running commands in the
383// container, or in a container built using an image built from this container.
384func (b *Builder) Env() []string {
385return copyStringSlice(b.OCIv1.Config.Env)
386}
387
388// SetEnv adds or overwrites a value to the set of environment strings which
389// should be set when running commands in the container, or in a container
390// built using an image built from this container.
391func (b *Builder) SetEnv(k string, v string) {
392reset := func(s *[]string) {
393n := []string{}
394for i := range *s {
395if !strings.HasPrefix((*s)[i], k+"=") {
396n = append(n, (*s)[i])
397}
398}
399n = append(n, k+"="+v)
400*s = n
401}
402reset(&b.OCIv1.Config.Env)
403reset(&b.Docker.Config.Env)
404}
405
406// UnsetEnv removes a value from the set of environment strings which should be
407// set when running commands in this container, or in a container built using
408// an image built from this container.
409func (b *Builder) UnsetEnv(k string) {
410unset := func(s *[]string) {
411n := []string{}
412for i := range *s {
413if !strings.HasPrefix((*s)[i], k+"=") {
414n = append(n, (*s)[i])
415}
416}
417*s = n
418}
419unset(&b.OCIv1.Config.Env)
420unset(&b.Docker.Config.Env)
421}
422
423// ClearEnv removes all values from the set of environment strings which should
424// be set when running commands in this container, or in a container built
425// using an image built from this container.
426func (b *Builder) ClearEnv() {
427b.OCIv1.Config.Env = []string{}
428b.Docker.Config.Env = []string{}
429}
430
431// Cmd returns the default command, or command parameters if an Entrypoint is
432// set, to use when running a container built from an image built from this
433// container.
434func (b *Builder) Cmd() []string {
435return copyStringSlice(b.OCIv1.Config.Cmd)
436}
437
438// SetCmd sets the default command, or command parameters if an Entrypoint is
439// set, to use when running a container built from an image built from this
440// container.
441func (b *Builder) SetCmd(cmd []string) {
442b.OCIv1.Config.Cmd = copyStringSlice(cmd)
443b.Docker.Config.Cmd = copyStringSlice(cmd)
444}
445
446// Entrypoint returns the command to be run for containers built from images
447// built from this container.
448func (b *Builder) Entrypoint() []string {
449if len(b.OCIv1.Config.Entrypoint) > 0 {
450return copyStringSlice(b.OCIv1.Config.Entrypoint)
451}
452return nil
453}
454
455// SetEntrypoint sets the command to be run for in containers built from images
456// built from this container.
457func (b *Builder) SetEntrypoint(ep []string) {
458b.OCIv1.Config.Entrypoint = copyStringSlice(ep)
459b.Docker.Config.Entrypoint = copyStringSlice(ep)
460}
461
462// Labels returns a set of key-value pairs from the image's runtime
463// configuration.
464func (b *Builder) Labels() map[string]string {
465return copyStringStringMap(b.OCIv1.Config.Labels)
466}
467
468// SetLabel adds or overwrites a key's value from the image's runtime
469// configuration.
470func (b *Builder) SetLabel(k string, v string) {
471if b.OCIv1.Config.Labels == nil {
472b.OCIv1.Config.Labels = map[string]string{}
473}
474b.OCIv1.Config.Labels[k] = v
475if b.Docker.Config.Labels == nil {
476b.Docker.Config.Labels = map[string]string{}
477}
478b.Docker.Config.Labels[k] = v
479}
480
481// UnsetLabel removes a key and its value from the image's runtime
482// configuration, if it's present.
483func (b *Builder) UnsetLabel(k string) {
484delete(b.OCIv1.Config.Labels, k)
485delete(b.Docker.Config.Labels, k)
486}
487
488// ClearLabels removes all keys and their values from the image's runtime
489// configuration.
490func (b *Builder) ClearLabels() {
491b.OCIv1.Config.Labels = map[string]string{}
492b.Docker.Config.Labels = map[string]string{}
493}
494
495// Ports returns the set of ports which should be exposed when a container
496// based on an image built from this container is run.
497func (b *Builder) Ports() []string {
498p := []string{}
499for k := range b.OCIv1.Config.ExposedPorts {
500p = append(p, k)
501}
502return p
503}
504
505// SetPort adds or overwrites an exported port in the set of ports which should
506// be exposed when a container based on an image built from this container is
507// run.
508func (b *Builder) SetPort(p string) {
509if b.OCIv1.Config.ExposedPorts == nil {
510b.OCIv1.Config.ExposedPorts = map[string]struct{}{}
511}
512b.OCIv1.Config.ExposedPorts[p] = struct{}{}
513if b.Docker.Config.ExposedPorts == nil {
514b.Docker.Config.ExposedPorts = make(docker.PortSet)
515}
516b.Docker.Config.ExposedPorts[docker.Port(p)] = struct{}{}
517}
518
519// UnsetPort removes an exposed port from the set of ports which should be
520// exposed when a container based on an image built from this container is run.
521func (b *Builder) UnsetPort(p string) {
522delete(b.OCIv1.Config.ExposedPorts, p)
523delete(b.Docker.Config.ExposedPorts, docker.Port(p))
524}
525
526// ClearPorts empties the set of ports which should be exposed when a container
527// based on an image built from this container is run.
528func (b *Builder) ClearPorts() {
529b.OCIv1.Config.ExposedPorts = map[string]struct{}{}
530b.Docker.Config.ExposedPorts = docker.PortSet{}
531}
532
533// Volumes returns a list of filesystem locations which should be mounted from
534// outside of the container when a container built from an image built from
535// this container is run.
536func (b *Builder) Volumes() []string {
537v := []string{}
538for k := range b.OCIv1.Config.Volumes {
539v = append(v, k)
540}
541if len(v) > 0 {
542return v
543}
544return nil
545}
546
547// CheckVolume returns True if the location exists in the image's list of locations
548// which should be mounted from outside of the container when a container
549// based on an image built from this container is run
550
551func (b *Builder) CheckVolume(v string) bool {
552_, OCIv1Volume := b.OCIv1.Config.Volumes[v]
553_, DockerVolume := b.Docker.Config.Volumes[v]
554return OCIv1Volume || DockerVolume
555}
556
557// AddVolume adds a location to the image's list of locations which should be
558// mounted from outside of the container when a container based on an image
559// built from this container is run.
560func (b *Builder) AddVolume(v string) {
561if b.OCIv1.Config.Volumes == nil {
562b.OCIv1.Config.Volumes = map[string]struct{}{}
563}
564b.OCIv1.Config.Volumes[v] = struct{}{}
565if b.Docker.Config.Volumes == nil {
566b.Docker.Config.Volumes = map[string]struct{}{}
567}
568b.Docker.Config.Volumes[v] = struct{}{}
569}
570
571// RemoveVolume removes a location from the list of locations which should be
572// mounted from outside of the container when a container based on an image
573// built from this container is run.
574func (b *Builder) RemoveVolume(v string) {
575delete(b.OCIv1.Config.Volumes, v)
576delete(b.Docker.Config.Volumes, v)
577}
578
579// ClearVolumes removes all locations from the image's list of locations which
580// should be mounted from outside of the container when a container based on an
581// image built from this container is run.
582func (b *Builder) ClearVolumes() {
583b.OCIv1.Config.Volumes = map[string]struct{}{}
584b.Docker.Config.Volumes = map[string]struct{}{}
585}
586
587// Hostname returns the hostname which will be set in the container and in
588// containers built using images built from the container.
589func (b *Builder) Hostname() string {
590return b.Docker.Config.Hostname
591}
592
593// SetHostname sets the hostname which will be set in the container and in
594// containers built using images built from the container.
595// Note: this setting is not present in the OCIv1 image format, so it is
596// discarded when writing images using OCIv1 formats.
597func (b *Builder) SetHostname(name string) {
598b.Docker.Config.Hostname = name
599}
600
601// Domainname returns the domainname which will be set in the container and in
602// containers built using images built from the container.
603func (b *Builder) Domainname() string {
604return b.Docker.Config.Domainname
605}
606
607// SetDomainname sets the domainname which will be set in the container and in
608// containers built using images built from the container.
609// Note: this setting is not present in the OCIv1 image format, so it is
610// discarded when writing images using OCIv1 formats.
611func (b *Builder) SetDomainname(name string) {
612if name != "" && b.Format != define.Dockerv2ImageManifest {
613b.Logger.Warnf("DOMAINNAME is not supported for OCI image format, domainname %s will be ignored. Must use `docker` format", name)
614}
615b.Docker.Config.Domainname = name
616}
617
618// SetDefaultMountsFilePath sets the mounts file path for testing purposes
619func (b *Builder) SetDefaultMountsFilePath(path string) {
620b.DefaultMountsFilePath = path
621}
622
623// Comment returns the comment which will be set in the container and in
624// containers built using images built from the container
625func (b *Builder) Comment() string {
626return b.Docker.Comment
627}
628
629// SetComment sets the comment which will be set in the container and in
630// containers built using images built from the container.
631// Note: this setting is not present in the OCIv1 image format, so it is
632// discarded when writing images using OCIv1 formats.
633func (b *Builder) SetComment(comment string) {
634if comment != "" && b.Format != define.Dockerv2ImageManifest {
635logrus.Warnf("COMMENT is not supported for OCI image format, comment %s will be ignored. Must use `docker` format", comment)
636}
637b.Docker.Comment = comment
638}
639
640// HistoryComment returns the comment which will be used in the history item
641// which will describe the latest layer when we commit an image.
642func (b *Builder) HistoryComment() string {
643return b.ImageHistoryComment
644}
645
646// SetHistoryComment sets the comment which will be used in the history item
647// which will describe the latest layer when we commit an image.
648func (b *Builder) SetHistoryComment(comment string) {
649b.ImageHistoryComment = comment
650}
651
652// StopSignal returns the signal which will be set in the container and in
653// containers built using images built from the container
654func (b *Builder) StopSignal() string {
655return b.Docker.Config.StopSignal
656}
657
658// SetStopSignal sets the signal which will be set in the container and in
659// containers built using images built from the container.
660func (b *Builder) SetStopSignal(stopSignal string) {
661b.OCIv1.Config.StopSignal = stopSignal
662b.Docker.Config.StopSignal = stopSignal
663}
664
665// Healthcheck returns information that recommends how a container engine
666// should check if a running container is "healthy".
667func (b *Builder) Healthcheck() *docker.HealthConfig {
668if b.Docker.Config.Healthcheck == nil {
669return nil
670}
671return &docker.HealthConfig{
672Test: copyStringSlice(b.Docker.Config.Healthcheck.Test),
673Interval: b.Docker.Config.Healthcheck.Interval,
674Timeout: b.Docker.Config.Healthcheck.Timeout,
675StartPeriod: b.Docker.Config.Healthcheck.StartPeriod,
676Retries: b.Docker.Config.Healthcheck.Retries,
677}
678}
679
680// SetHealthcheck sets recommended commands to run in order to verify that a
681// running container based on this image is "healthy", along with information
682// specifying how often that test should be run, and how many times the test
683// should fail before the container should be considered unhealthy.
684// Note: this setting is not present in the OCIv1 image format, so it is
685// discarded when writing images using OCIv1 formats.
686func (b *Builder) SetHealthcheck(config *docker.HealthConfig) {
687b.Docker.Config.Healthcheck = nil
688if config != nil {
689if b.Format != define.Dockerv2ImageManifest {
690b.Logger.Warnf("HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format")
691}
692b.Docker.Config.Healthcheck = &docker.HealthConfig{
693Test: copyStringSlice(config.Test),
694Interval: config.Interval,
695Timeout: config.Timeout,
696StartPeriod: config.StartPeriod,
697Retries: config.Retries,
698}
699}
700}
701
702// AddPrependedEmptyLayer adds an item to the history that we'll create when
703// committing the image, after any history we inherit from the base image, but
704// before the history item that we'll use to describe the new layer that we're
705// adding.
706func (b *Builder) AddPrependedEmptyLayer(created *time.Time, createdBy, author, comment string) {
707if created != nil {
708copiedTimestamp := *created
709created = &copiedTimestamp
710}
711b.PrependedEmptyLayers = append(b.PrependedEmptyLayers, ociv1.History{
712Created: created,
713CreatedBy: createdBy,
714Author: author,
715Comment: comment,
716EmptyLayer: true,
717})
718}
719
720// ClearPrependedEmptyLayers clears the list of history entries that we'll add
721// to the committed image before the entry for the layer that we're adding.
722func (b *Builder) ClearPrependedEmptyLayers() {
723b.PrependedEmptyLayers = nil
724}
725
726// AddAppendedEmptyLayer adds an item to the history that we'll create when
727// committing the image, after the history item that we'll use to describe the
728// new layer that we're adding.
729func (b *Builder) AddAppendedEmptyLayer(created *time.Time, createdBy, author, comment string) {
730if created != nil {
731copiedTimestamp := *created
732created = &copiedTimestamp
733}
734b.AppendedEmptyLayers = append(b.AppendedEmptyLayers, ociv1.History{
735Created: created,
736CreatedBy: createdBy,
737Author: author,
738Comment: comment,
739EmptyLayer: true,
740})
741}
742
743// ClearAppendedEmptyLayers clears the list of history entries that we'll add
744// to the committed image after the entry for the layer that we're adding.
745func (b *Builder) ClearAppendedEmptyLayers() {
746b.AppendedEmptyLayers = nil
747}
748