Skip to content

Commit 3cb2a6e

Browse files
committed
dockerui: separate docker frontend params to reusable package
Signed-off-by: Tonis Tiigi <[email protected]>
1 parent 30df092 commit 3cb2a6e

File tree

6 files changed

+1245
-0
lines changed

6 files changed

+1245
-0
lines changed

frontend/dockerui/attr.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package dockerui
2+
3+
import (
4+
"encoding/csv"
5+
"net"
6+
"strconv"
7+
"strings"
8+
"time"
9+
10+
"github.com/containerd/containerd/platforms"
11+
"github.com/docker/go-units"
12+
"github.com/moby/buildkit/client/llb"
13+
"github.com/moby/buildkit/solver/pb"
14+
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
15+
"github.com/pkg/errors"
16+
)
17+
18+
func parsePlatforms(v string) ([]ocispecs.Platform, error) {
19+
var pp []ocispecs.Platform
20+
for _, v := range strings.Split(v, ",") {
21+
p, err := platforms.Parse(v)
22+
if err != nil {
23+
return nil, errors.Wrapf(err, "failed to parse target platform %s", v)
24+
}
25+
pp = append(pp, platforms.Normalize(p))
26+
}
27+
return pp, nil
28+
}
29+
30+
func parseResolveMode(v string) (llb.ResolveMode, error) {
31+
switch v {
32+
case pb.AttrImageResolveModeDefault, "":
33+
return llb.ResolveModeDefault, nil
34+
case pb.AttrImageResolveModeForcePull:
35+
return llb.ResolveModeForcePull, nil
36+
case pb.AttrImageResolveModePreferLocal:
37+
return llb.ResolveModePreferLocal, nil
38+
default:
39+
return 0, errors.Errorf("invalid image-resolve-mode: %s", v)
40+
}
41+
}
42+
43+
func parseExtraHosts(v string) ([]llb.HostIP, error) {
44+
if v == "" {
45+
return nil, nil
46+
}
47+
out := make([]llb.HostIP, 0)
48+
csvReader := csv.NewReader(strings.NewReader(v))
49+
fields, err := csvReader.Read()
50+
if err != nil {
51+
return nil, err
52+
}
53+
for _, field := range fields {
54+
key, val, ok := strings.Cut(strings.ToLower(field), "=")
55+
if !ok {
56+
return nil, errors.Errorf("invalid key-value pair %s", field)
57+
}
58+
ip := net.ParseIP(val)
59+
if ip == nil {
60+
return nil, errors.Errorf("failed to parse IP %s", val)
61+
}
62+
out = append(out, llb.HostIP{Host: key, IP: ip})
63+
}
64+
return out, nil
65+
}
66+
67+
func parseShmSize(v string) (int64, error) {
68+
if len(v) == 0 {
69+
return 0, nil
70+
}
71+
kb, err := strconv.ParseInt(v, 10, 64)
72+
if err != nil {
73+
return 0, err
74+
}
75+
return kb, nil
76+
}
77+
78+
func parseUlimits(v string) ([]pb.Ulimit, error) {
79+
if v == "" {
80+
return nil, nil
81+
}
82+
out := make([]pb.Ulimit, 0)
83+
csvReader := csv.NewReader(strings.NewReader(v))
84+
fields, err := csvReader.Read()
85+
if err != nil {
86+
return nil, err
87+
}
88+
for _, field := range fields {
89+
ulimit, err := units.ParseUlimit(field)
90+
if err != nil {
91+
return nil, err
92+
}
93+
out = append(out, pb.Ulimit{
94+
Name: ulimit.Name,
95+
Soft: ulimit.Soft,
96+
Hard: ulimit.Hard,
97+
})
98+
}
99+
return out, nil
100+
}
101+
102+
func parseNetMode(v string) (pb.NetMode, error) {
103+
if v == "" {
104+
return llb.NetModeSandbox, nil
105+
}
106+
switch v {
107+
case "none":
108+
return llb.NetModeNone, nil
109+
case "host":
110+
return llb.NetModeHost, nil
111+
case "sandbox":
112+
return llb.NetModeSandbox, nil
113+
default:
114+
return 0, errors.Errorf("invalid netmode %s", v)
115+
}
116+
}
117+
118+
func parseSourceDateEpoch(v string) (*time.Time, error) {
119+
if v == "" {
120+
return nil, nil
121+
}
122+
sde, err := strconv.ParseInt(v, 10, 64)
123+
if err != nil {
124+
return nil, errors.Wrapf(err, "invalid SOURCE_DATE_EPOCH: %s", v)
125+
}
126+
tm := time.Unix(sde, 0).UTC()
127+
return &tm, nil
128+
}
129+
130+
func filter(opt map[string]string, key string) map[string]string {
131+
m := map[string]string{}
132+
for k, v := range opt {
133+
if strings.HasPrefix(k, key) {
134+
m[strings.TrimPrefix(k, key)] = v
135+
}
136+
}
137+
return m
138+
}

frontend/dockerui/build.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package dockerui
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
8+
"github.com/containerd/containerd/platforms"
9+
"github.com/moby/buildkit/exporter/containerimage/exptypes"
10+
"github.com/moby/buildkit/exporter/containerimage/image"
11+
"github.com/moby/buildkit/frontend/gateway/client"
12+
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
13+
"github.com/pkg/errors"
14+
"golang.org/x/sync/errgroup"
15+
)
16+
17+
type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *image.Image, error)
18+
19+
func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, error) {
20+
res := client.NewResult()
21+
22+
targets := make([]*ocispecs.Platform, 0, len(bc.TargetPlatforms))
23+
for _, p := range bc.TargetPlatforms {
24+
p := p
25+
targets = append(targets, &p)
26+
}
27+
if len(targets) == 0 {
28+
targets = append(targets, nil)
29+
}
30+
expPlatforms := &exptypes.Platforms{
31+
Platforms: make([]exptypes.Platform, len(targets)),
32+
}
33+
34+
eg, ctx := errgroup.WithContext(ctx)
35+
36+
for i, tp := range targets {
37+
i, tp := i, tp
38+
eg.Go(func() error {
39+
ref, img, err := fn(ctx, tp, i)
40+
if err != nil {
41+
return err
42+
}
43+
44+
config, err := json.Marshal(img)
45+
if err != nil {
46+
return errors.Wrapf(err, "failed to marshal image config")
47+
}
48+
49+
p := platforms.DefaultSpec()
50+
if tp != nil {
51+
p = *tp
52+
}
53+
p = platforms.Normalize(p)
54+
k := platforms.Format(p)
55+
56+
if bc.MultiPlatformRequested {
57+
res.AddRef(k, ref)
58+
res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k), config)
59+
} else {
60+
res.SetRef(ref)
61+
res.AddMeta(exptypes.ExporterImageConfigKey, config)
62+
}
63+
expPlatforms.Platforms[i] = exptypes.Platform{
64+
ID: k,
65+
Platform: p,
66+
}
67+
return nil
68+
})
69+
}
70+
if err := eg.Wait(); err != nil {
71+
return nil, err
72+
}
73+
return &ResultBuilder{
74+
Result: res,
75+
expPlatforms: expPlatforms,
76+
}, nil
77+
}
78+
79+
type ResultBuilder struct {
80+
*client.Result
81+
expPlatforms *exptypes.Platforms
82+
}
83+
84+
func (rb *ResultBuilder) Finalize() (*client.Result, error) {
85+
dt, err := json.Marshal(rb.expPlatforms)
86+
if err != nil {
87+
return nil, err
88+
}
89+
rb.AddMeta(exptypes.ExporterPlatformsKey, dt)
90+
91+
return rb.Result, nil
92+
}
93+
94+
func (rb *ResultBuilder) EachPlatform(ctx context.Context, fn func(ctx context.Context, id string, p ocispecs.Platform) error) error {
95+
eg, ctx := errgroup.WithContext(ctx)
96+
for _, p := range rb.expPlatforms.Platforms {
97+
p := p
98+
eg.Go(func() error {
99+
return fn(ctx, p.ID, p.Platform)
100+
})
101+
}
102+
return eg.Wait()
103+
}

0 commit comments

Comments
 (0)