diff --git a/.github/workflows/buildkit.yml b/.github/workflows/buildkit.yml index f1d1971406849..b1841c1900e3e 100644 --- a/.github/workflows/buildkit.yml +++ b/.github/workflows/buildkit.yml @@ -50,6 +50,9 @@ jobs: timeout-minutes: 120 needs: - build + env: + TEST_IMAGE_BUILD: "0" + TEST_IMAGE_ID: "buildkit-tests" strategy: fail-fast: false matrix: @@ -115,6 +118,14 @@ jobs: sudo service docker restart docker version docker info + - + name: Build test image + uses: docker/bake-action@v4 + with: + workdir: ./buildkit + targets: integration-tests + set: | + *.output=type=docker,name=${{ env.TEST_IMAGE_ID }} - name: Test run: | diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go index 6a8be68762fef..b33f03480e831 100644 --- a/builder/builder-next/adapters/containerimage/pull.go +++ b/builder/builder-next/adapters/containerimage/pull.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "path" + "strconv" "strings" "sync" "time" @@ -34,14 +35,15 @@ import ( pkgprogress "github.com/docker/docker/pkg/progress" "github.com/docker/docker/reference" "github.com/moby/buildkit/cache" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/session" "github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/source" + "github.com/moby/buildkit/source/containerimage" srctypes "github.com/moby/buildkit/source/types" "github.com/moby/buildkit/sourcepolicy" - policy "github.com/moby/buildkit/sourcepolicy/pb" spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/imageutil" @@ -80,9 +82,77 @@ func NewSource(opt SourceOpt) (*Source, error) { return &Source{SourceOpt: opt}, nil } -// ID returns image scheme identifier -func (is *Source) ID() string { - return srctypes.DockerImageScheme +// Schemes returns a list of SourceOp identifier schemes that this source +// should match. +func (is *Source) Schemes() []string { + return []string{srctypes.DockerImageScheme} +} + +// Identifier constructs an Identifier from the given scheme, ref, and attrs, +// all of which come from a SourceOp. +func (is *Source) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + return is.registryIdentifier(ref, attrs, platform) +} + +// Copied from github.com/moby/buildkit/source/containerimage/source.go +func (is *Source) registryIdentifier(ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := containerimage.NewImageIdentifier(ref) + if err != nil { + return nil, err + } + + if platform != nil { + id.Platform = &ocispec.Platform{ + OS: platform.OS, + Architecture: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + } + if platform.OSFeatures != nil { + id.Platform.OSFeatures = append([]string{}, platform.OSFeatures...) + } + } + + for k, v := range attrs { + switch k { + case pb.AttrImageResolveMode: + rm, err := resolver.ParseImageResolveMode(v) + if err != nil { + return nil, err + } + id.ResolveMode = rm + case pb.AttrImageRecordType: + rt, err := parseImageRecordType(v) + if err != nil { + return nil, err + } + id.RecordType = rt + case pb.AttrImageLayerLimit: + l, err := strconv.Atoi(v) + if err != nil { + return nil, errors.Wrapf(err, "invalid layer limit %s", v) + } + if l <= 0 { + return nil, errors.Errorf("invalid layer limit %s", v) + } + id.LayerLimit = &l + } + } + + return id, nil +} + +func parseImageRecordType(v string) (client.UsageRecordType, error) { + switch client.UsageRecordType(v) { + case "", client.UsageRecordTypeRegular: + return client.UsageRecordTypeRegular, nil + case client.UsageRecordTypeInternal: + return client.UsageRecordTypeInternal, nil + case client.UsageRecordTypeFrontend: + return client.UsageRecordTypeFrontend, nil + default: + return "", errors.Errorf("invalid record type %s", v) + } } func (is *Source) resolveLocal(refStr string) (*image.Image, error) { @@ -107,7 +177,7 @@ type resolveRemoteResult struct { dt []byte } -func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) { +func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) { p := platforms.DefaultSpec() if platform != nil { p = *platform @@ -116,34 +186,36 @@ func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocisp key := "getconfig::" + ref + "::" + platforms.Format(p) res, err := is.g.Do(ctx, key, func(ctx context.Context) (*resolveRemoteResult, error) { res := resolver.DefaultPool.GetResolver(is.RegistryHosts, ref, "pull", sm, g) - ref, dgst, dt, err := imageutil.Config(ctx, ref, res, is.ContentStore, is.LeaseManager, platform, []*policy.Policy{}) + dgst, dt, err := imageutil.Config(ctx, ref, res, is.ContentStore, is.LeaseManager, platform) if err != nil { return nil, err } return &resolveRemoteResult{ref: ref, dgst: dgst, dt: dt}, nil }) if err != nil { - return ref, "", nil, err + return "", nil, err } - return res.ref, res.dgst, res.dt, nil + return res.dgst, res.dt, nil } // ResolveImageConfig returns image config for an image -func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) { +func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) { + if opt.ImageOpt == nil { + return "", nil, fmt.Errorf("can only resolve an image: %v, opt: %v", ref, opt) + } ref, err := applySourcePolicies(ctx, ref, opt.SourcePolicies) if err != nil { - return "", "", nil, err + return "", nil, err } - resolveMode, err := source.ParseImageResolveMode(opt.ResolveMode) + resolveMode, err := resolver.ParseImageResolveMode(opt.ImageOpt.ResolveMode) if err != nil { - return ref, "", nil, err + return "", nil, err } switch resolveMode { - case source.ResolveModeForcePull: - ref, dgst, dt, err := is.resolveRemote(ctx, ref, opt.Platform, sm, g) + case resolver.ResolveModeForcePull: + return is.resolveRemote(ctx, ref, opt.Platform, sm, g) // TODO: pull should fallback to local in case of failure to allow offline behavior // the fallback doesn't work currently - return ref, dgst, dt, err /* if err == nil { return dgst, dt, err @@ -153,10 +225,10 @@ func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.Re return "", dt, err */ - case source.ResolveModeDefault: + case resolver.ResolveModeDefault: // default == prefer local, but in the future could be smarter fallthrough - case source.ResolveModePreferLocal: + case resolver.ResolveModePreferLocal: img, err := is.resolveLocal(ref) if err == nil { if opt.Platform != nil && !platformMatches(img, opt.Platform) { @@ -165,19 +237,19 @@ func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.Re path.Join(img.OS, img.Architecture, img.Variant), ) } else { - return ref, "", img.RawJSON(), err + return "", img.RawJSON(), err } } // fallback to remote return is.resolveRemote(ctx, ref, opt.Platform, sm, g) } // should never happen - return ref, "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ResolveMode) + return "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ImageOpt.ResolveMode) } // Resolve returns access to pulling for an identifier func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, vtx solver.Vertex) (source.SourceInstance, error) { - imageIdentifier, ok := id.(*source.ImageIdentifier) + imageIdentifier, ok := id.(*containerimage.ImageIdentifier) if !ok { return nil, errors.Errorf("invalid image identifier %v", id) } @@ -201,7 +273,7 @@ type puller struct { is *Source resolveLocalOnce sync.Once g flightcontrol.Group[struct{}] - src *source.ImageIdentifier + src *containerimage.ImageIdentifier desc ocispec.Descriptor ref string config []byte @@ -253,7 +325,7 @@ func (p *puller) resolveLocal() { } } - if p.src.ResolveMode == source.ResolveModeDefault || p.src.ResolveMode == source.ResolveModePreferLocal { + if p.src.ResolveMode == resolver.ResolveModeDefault || p.src.ResolveMode == resolver.ResolveModePreferLocal { ref := p.src.Reference.String() img, err := p.is.resolveLocal(ref) if err == nil { @@ -302,12 +374,17 @@ func (p *puller) resolve(ctx context.Context, g session.Group) error { if err != nil { return struct{}{}, err } - newRef, _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), llb.ResolveImageConfigOpt{Platform: &p.platform, ResolveMode: p.src.ResolveMode.String()}, p.sm, g) + _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), sourceresolver.Opt{ + Platform: &p.platform, + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: p.src.ResolveMode.String(), + }, + }, p.sm, g) if err != nil { return struct{}{}, err } - p.ref = newRef + p.ref = ref.String() p.config = dt } return struct{}{}, nil @@ -866,12 +943,8 @@ func applySourcePolicies(ctx context.Context, str string, spls []*spb.Policy) (s if err != nil { return "", errors.WithStack(err) } - op := &pb.Op{ - Op: &pb.Op_Source{ - Source: &pb.SourceOp{ - Identifier: srctypes.DockerImageScheme + "://" + ref.String(), - }, - }, + op := &pb.SourceOp{ + Identifier: srctypes.DockerImageScheme + "://" + ref.String(), } mut, err := sourcepolicy.NewEngine(spls).Evaluate(ctx, op) @@ -884,9 +957,9 @@ func applySourcePolicies(ctx context.Context, str string, spls []*spb.Policy) (s t string ok bool ) - t, newRef, ok := strings.Cut(op.GetSource().GetIdentifier(), "://") + t, newRef, ok := strings.Cut(op.GetIdentifier(), "://") if !ok { - return "", errors.Errorf("could not parse ref: %s", op.GetSource().GetIdentifier()) + return "", errors.Errorf("could not parse ref: %s", op.GetIdentifier()) } if ok && t != srctypes.DockerImageScheme { return "", &imageutil.ResolveToNonImageError{Ref: str, Updated: newRef} diff --git a/builder/builder-next/builder.go b/builder/builder-next/builder.go index e4b11164153c7..439a1aac3d15d 100644 --- a/builder/builder-next/builder.go +++ b/builder/builder-next/builder.go @@ -389,9 +389,10 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder. } req := &controlapi.SolveRequest{ - Ref: id, - Exporter: exporterName, - ExporterAttrs: exporterAttrs, + Ref: id, + Exporters: []*controlapi.Exporter{ + &controlapi.Exporter{Type: exporterName, Attrs: exporterAttrs}, + }, Frontend: "dockerfile.v0", FrontendAttrs: frontendAttrs, Session: opt.Options.SessionID, diff --git a/builder/builder-next/controller.go b/builder/builder-next/controller.go index cefb39476ec62..457466d2f463a 100644 --- a/builder/builder-next/controller.go +++ b/builder/builder-next/controller.go @@ -67,11 +67,11 @@ func newController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control } func getTraceExporter(ctx context.Context) trace.SpanExporter { - exp, err := detect.Exporter() + span, _, err := detect.Exporter() if err != nil { log.G(ctx).WithError(err).Error("Failed to detect trace exporter for buildkit controller") } - return exp + return span } func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) { @@ -105,7 +105,8 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt wo, err := containerd.NewWorkerOpt(opt.Root, opt.ContainerdAddress, opt.Snapshotter, opt.ContainerdNamespace, opt.Rootless, map[string]string{ label.Snapshotter: opt.Snapshotter, - }, dns, nc, opt.ApparmorProfile, false, nil, "", ctd.WithTimeout(60*time.Second)) + }, dns, nc, opt.ApparmorProfile, false, nil, "", nil, ctd.WithTimeout(60*time.Second), + ) if err != nil { return nil, err } @@ -302,9 +303,11 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt } exp, err := mobyexporter.New(mobyexporter.Opt{ - ImageStore: dist.ImageStore, - Differ: differ, - ImageTagger: opt.ImageTagger, + ImageStore: dist.ImageStore, + ContentStore: store, + Differ: differ, + ImageTagger: opt.ImageTagger, + LeaseManager: lm, }) if err != nil { return nil, err diff --git a/builder/builder-next/exporter/mobyexporter/export.go b/builder/builder-next/exporter/mobyexporter/export.go index f692af4339a6d..d6c5776099e18 100644 --- a/builder/builder-next/exporter/mobyexporter/export.go +++ b/builder/builder-next/exporter/mobyexporter/export.go @@ -1,24 +1,25 @@ package mobyexporter import ( + "bytes" "context" - "encoding/json" "fmt" "strings" + "time" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/leases" distref "github.com/distribution/reference" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/moby/buildkit/exporter" + "github.com/moby/buildkit/exporter/containerimage" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) -const ( - keyImageName = "name" -) - // Differ can make a moby layer from a snapshot type Differ interface { EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error) @@ -30,9 +31,11 @@ type ImageTagger interface { // Opt defines a struct for creating new exporter type Opt struct { - ImageStore image.Store - Differ Differ - ImageTagger ImageTagger + ImageStore image.Store + Differ Differ + ImageTagger ImageTagger + ContentStore content.Store + LeaseManager leases.Manager } type imageExporter struct { @@ -45,13 +48,14 @@ func New(opt Opt) (exporter.Exporter, error) { return im, nil } -func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { +func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) { i := &imageExporterInstance{ imageExporter: e, + id: id, } for k, v := range opt { - switch k { - case keyImageName: + switch exptypes.ImageExporterOptKey(k) { + case exptypes.OptKeyName: for _, v := range strings.Split(v, ",") { ref, err := distref.ParseNormalizedNamed(v) if err != nil { @@ -71,10 +75,15 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp type imageExporterInstance struct { *imageExporter + id int targetNames []distref.Named meta map[string][]byte } +func (e *imageExporterInstance) ID() int { + return e.id +} + func (e *imageExporterInstance) Name() string { return "exporting to image" } @@ -83,7 +92,7 @@ func (e *imageExporterInstance) Config() *exporter.Config { return exporter.NewConfig() } -func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, exporter.DescriptorReference, error) { +func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) { if len(inp.Refs) > 1 { return nil, nil, fmt.Errorf("exporting multiple references to image store is currently unsupported") } @@ -103,18 +112,14 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source case 0: config = inp.Metadata[exptypes.ExporterImageConfigKey] case 1: - platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey] - if !ok { - return nil, nil, fmt.Errorf("cannot export image, missing platforms mapping") - } - var p exptypes.Platforms - if err := json.Unmarshal(platformsBytes, &p); err != nil { - return nil, nil, errors.Wrapf(err, "failed to parse platforms passed to exporter") + ps, err := exptypes.ParsePlatforms(inp.Metadata) + if err != nil { + return nil, nil, fmt.Errorf("cannot export image, failed to parse platforms: %w", err) } - if len(p.Platforms) != len(inp.Refs) { - return nil, nil, errors.Errorf("number of platforms does not match references %d %d", len(p.Platforms), len(inp.Refs)) + if len(ps.Platforms) != len(inp.Refs) { + return nil, nil, errors.Errorf("number of platforms does not match references %d %d", len(ps.Platforms), len(inp.Refs)) } - config = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, p.Platforms[0].ID)] + config = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, ps.Platforms[0].ID)] } var diffs []digest.Digest @@ -157,7 +162,21 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source diffs, history = normalizeLayersAndHistory(diffs, history, ref) - config, err = patchImageConfig(config, diffs, history, inp.Metadata[exptypes.ExporterInlineCache]) + var inlineCacheEntry *exptypes.InlineCacheEntry + if inlineCache != nil { + inlineCacheResult, err := inlineCache(ctx) + if err != nil { + return nil, nil, err + } + if inlineCacheResult != nil { + if ref != nil { + inlineCacheEntry, _ = inlineCacheResult.FindRef(ref.ID()) + } else { + inlineCacheEntry = inlineCacheResult.Ref + } + } + } + config, err = patchImageConfig(config, diffs, history, inlineCacheEntry) if err != nil { return nil, nil, err } @@ -171,8 +190,10 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source } _ = configDone(nil) - if e.opt.ImageTagger != nil { - for _, targetName := range e.targetNames { + var names []string + for _, targetName := range e.targetNames { + names = append(names, targetName.String()) + if e.opt.ImageTagger != nil { tagDone := oneOffProgress(ctx, "naming to "+targetName.String()) if err := e.opt.ImageTagger.TagImage(ctx, image.ID(digest.Digest(id)), targetName); err != nil { return nil, nil, tagDone(err) @@ -181,8 +202,42 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source } } - return map[string]string{ + resp := map[string]string{ exptypes.ExporterImageConfigDigestKey: configDigest.String(), exptypes.ExporterImageDigestKey: id.String(), - }, nil, nil + } + if len(names) > 0 { + resp["image.name"] = strings.Join(names, ",") + } + + descRef, err := e.newTempReference(ctx, config) + if err != nil { + return nil, nil, fmt.Errorf("failed to create a temporary descriptor reference: %w", err) + } + + return resp, descRef, nil +} + +func (e *imageExporterInstance) newTempReference(ctx context.Context, config []byte) (exporter.DescriptorReference, error) { + lm := e.opt.LeaseManager + + dgst := digest.FromBytes(config) + lease, err := lm.Create(ctx, leases.WithRandomID(), leases.WithExpiration(time.Hour)) + if err != nil { + return nil, err + } + + desc := ocispec.Descriptor{ + Digest: dgst, + MediaType: "application/vnd.docker.container.image.v1+json", + Size: int64(len(config)), + } + + if err := content.WriteBlob(ctx, e.opt.ContentStore, desc.Digest.String(), bytes.NewReader(config), desc); err != nil { + return nil, fmt.Errorf("failed to save temporary image config: %w", err) + } + + return containerimage.NewDescriptorReference(desc, func(ctx context.Context) error { + return lm.Delete(ctx, lease) + }), nil } diff --git a/builder/builder-next/exporter/mobyexporter/writer.go b/builder/builder-next/exporter/mobyexporter/writer.go index 2ee7e01a1ad27..6ecdc3bf6aabf 100644 --- a/builder/builder-next/exporter/mobyexporter/writer.go +++ b/builder/builder-next/exporter/mobyexporter/writer.go @@ -8,6 +8,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/containerd/log" "github.com/moby/buildkit/cache" + "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/system" "github.com/opencontainers/go-digest" @@ -38,7 +39,7 @@ func parseHistoryFromConfig(dt []byte) ([]ocispec.History, error) { return config.History, nil } -func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache []byte) ([]byte, error) { +func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache *exptypes.InlineCacheEntry) ([]byte, error) { m := map[string]json.RawMessage{} if err := json.Unmarshal(dt, &m); err != nil { return nil, errors.Wrap(err, "failed to parse image config for patch") @@ -75,7 +76,7 @@ func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, } if cache != nil { - dt, err := json.Marshal(cache) + dt, err := json.Marshal(cache.Data) if err != nil { return nil, err } diff --git a/builder/builder-next/exporter/overrides/wrapper.go b/builder/builder-next/exporter/overrides/wrapper.go index 220a042df10f5..abbf8b6174521 100644 --- a/builder/builder-next/exporter/overrides/wrapper.go +++ b/builder/builder-next/exporter/overrides/wrapper.go @@ -19,7 +19,7 @@ func NewExporterWrapper(exp exporter.Exporter) (exporter.Exporter, error) { } // Resolve applies moby specific attributes to the request. -func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, exporterAttrs map[string]string) (exporter.ExporterInstance, error) { +func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, id int, exporterAttrs map[string]string) (exporter.ExporterInstance, error) { if exporterAttrs == nil { exporterAttrs = make(map[string]string) } @@ -33,5 +33,5 @@ func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, exporterAttrs ma exporterAttrs[string(exptypes.OptKeyDanglingPrefix)] = "moby-dangling" } - return e.exp.Resolve(ctx, exporterAttrs) + return e.exp.Resolve(ctx, id, exporterAttrs) } diff --git a/builder/builder-next/worker/worker.go b/builder/builder-next/worker/worker.go index b74c793df42db..ba4fac6e636eb 100644 --- a/builder/builder-next/worker/worker.go +++ b/builder/builder-next/worker/worker.go @@ -12,7 +12,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/rootfs" "github.com/containerd/log" - "github.com/docker/docker/builder/builder-next/adapters/containerimage" + imageadapter "github.com/docker/docker/builder/builder-next/adapters/containerimage" mobyexporter "github.com/docker/docker/builder/builder-next/exporter" distmetadata "github.com/docker/docker/distribution/metadata" "github.com/docker/docker/distribution/xfer" @@ -23,7 +23,7 @@ import ( "github.com/moby/buildkit/cache" cacheconfig "github.com/moby/buildkit/cache/config" "github.com/moby/buildkit/client" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/exporter" localexporter "github.com/moby/buildkit/exporter/local" @@ -37,6 +37,7 @@ import ( "github.com/moby/buildkit/solver/llbsolver/ops" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/source" + "github.com/moby/buildkit/source/containerimage" "github.com/moby/buildkit/source/git" "github.com/moby/buildkit/source/http" "github.com/moby/buildkit/source/local" @@ -75,7 +76,7 @@ type Opt struct { ContentStore *containerdsnapshot.Store CacheManager cache.Manager LeaseManager *leaseutil.Manager - ImageSource *containerimage.Source + ImageSource *imageadapter.Source DownloadManager *xfer.LayerDownloadManager V2MetadataService distmetadata.V2MetadataService Transport nethttp.RoundTripper @@ -212,6 +213,49 @@ func (w *Worker) LoadRef(ctx context.Context, id string, hidden bool) (cache.Imm return w.CacheManager().Get(ctx, id, nil, opts...) } +func (w *Worker) ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (*sourceresolver.MetaResponse, error) { + if opt.SourcePolicies != nil { + return nil, errors.New("source policies can not be set for worker") + } + + var platform *pb.Platform + if p := opt.Platform; p != nil { + platform = &pb.Platform{ + Architecture: p.Architecture, + OS: p.OS, + Variant: p.Variant, + OSVersion: p.OSVersion, + } + } + + id, err := w.SourceManager.Identifier(&pb.Op_Source{Source: op}, platform) + if err != nil { + return nil, err + } + + switch idt := id.(type) { + case *containerimage.ImageIdentifier: + if opt.ImageOpt == nil { + opt.ImageOpt = &sourceresolver.ResolveImageOpt{} + } + dgst, config, err := w.ImageSource.ResolveImageConfig(ctx, idt.Reference.String(), opt, sm, g) + if err != nil { + return nil, err + } + return &sourceresolver.MetaResponse{ + Op: op, + Image: &sourceresolver.ResolveImageResponse{ + Digest: dgst, + Config: config, + }, + }, nil + } + + return &sourceresolver.MetaResponse{ + Op: op, + }, nil +} + // ResolveOp converts a LLB vertex into a LLB operation func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *session.Manager) (solver.Op, error) { if baseOp, ok := v.Sys().(*pb.Op); ok { @@ -236,7 +280,7 @@ func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *se } // ResolveImageConfig returns image config for an image -func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) { +func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) { return w.ImageSource.ResolveImageConfig(ctx, ref, opt, sm, g) } diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index 99c5aabbf860a..b81c4bc9b71d1 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -242,7 +242,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) { // Override BuildKit's default Resource so that it matches the semconv // version that is used in our code. - detect.Resource = resource.Default() + detect.OverrideResource(resource.Default()) detect.Recorder = detect.NewTraceRecorder() tp, err := detect.TracerProvider() @@ -380,12 +380,20 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) { // TODO: This can be removed after buildkit is updated to use http/protobuf as the default. func setOTLPProtoDefault() { const ( - tracesEnv = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL" - protoEnv = "OTEL_EXPORTER_OTLP_PROTOCOL" + tracesEnv = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL" + metricsEnv = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL" + protoEnv = "OTEL_EXPORTER_OTLP_PROTOCOL" + + defaultProto = "http/protobuf" ) - if os.Getenv(tracesEnv) == "" && os.Getenv(protoEnv) == "" { - os.Setenv(tracesEnv, "http/protobuf") + if os.Getenv(protoEnv) == "" { + if os.Getenv(tracesEnv) == "" { + os.Setenv(tracesEnv, defaultProto) + } + if os.Getenv(metricsEnv) == "" { + os.Setenv(metricsEnv, defaultProto) + } } } diff --git a/hack/with-go-mod.sh b/hack/with-go-mod.sh index 0abc352faa86b..384d1bde9bf8a 100755 --- a/hack/with-go-mod.sh +++ b/hack/with-go-mod.sh @@ -25,9 +25,9 @@ else tee "${ROOTDIR}/go.mod" >&2 <<- EOF module github.com/docker/docker - go 1.20 + go 1.21 EOF trap 'rm -f "${ROOTDIR}/go.mod"' EXIT fi -GO111MODULE=on "$@" +GO111MODULE=on GOTOOLCHAIN=local "$@" diff --git a/integration/build/build_session_test.go b/integration/build/build_session_test.go index 8f49689990d34..6c655c46a36fc 100644 --- a/integration/build/build_session_test.go +++ b/integration/build/build_session_test.go @@ -15,6 +15,7 @@ import ( "github.com/docker/docker/testutil/request" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/filesync" + "github.com/tonistiigi/fsutil" "golang.org/x/sync/errgroup" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -95,8 +96,11 @@ func testBuildWithSession(ctx context.Context, t *testing.T, client dclient.APIC sess, err := session.NewSession(ctx, "foo1", "foo") assert.Check(t, err) + fs, err := fsutil.NewFS(dir) + assert.NilError(t, err) + fsProvider := filesync.NewFSSyncProvider(filesync.StaticDirSource{ - "": {Dir: dir}, + "": fs, }) sess.Allow(fsProvider) diff --git a/integration/build/build_traces_test.go b/integration/build/build_traces_test.go index 1cbc02f98799d..8cc0301417d72 100644 --- a/integration/build/build_traces_test.go +++ b/integration/build/build_traces_test.go @@ -56,8 +56,11 @@ func TestBuildkitHistoryTracePropagation(t *testing.T) { <-sub.Context().Done() }() + d, err := progressui.NewDisplay(&testWriter{t}, progressui.AutoMode, progressui.WithPhase("test")) + assert.NilError(t, err) + eg.Go(func() error { - _, err := progressui.DisplaySolveStatus(ctxGo, nil, &testWriter{t}, ch, progressui.WithPhase("test")) + _, err := d.UpdateFrom(ctxGo, ch) return err }) diff --git a/vendor.mod b/vendor.mod index 081dfede321e4..ea73aa6af6a2f 100644 --- a/vendor.mod +++ b/vendor.mod @@ -4,7 +4,7 @@ module github.com/docker/docker -go 1.20 +go 1.21 require ( cloud.google.com/go/compute/metadata v0.2.3 @@ -60,7 +60,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mistifyio/go-zfs/v3 v3.0.1 github.com/mitchellh/copystructure v1.2.0 - github.com/moby/buildkit v0.12.5 + github.com/moby/buildkit v0.13.0-rc2 github.com/moby/docker-image-spec v1.3.1 github.com/moby/ipvs v1.1.0 github.com/moby/locker v1.0.1 @@ -87,6 +87,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 + github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6 github.com/tonistiigi/go-archvariant v1.0.0 github.com/vbatts/tar-split v0.11.5 github.com/vishvananda/netlink v1.2.1-beta.2 @@ -136,13 +137,14 @@ require ( github.com/cilium/ebpf v0.11.0 // indirect github.com/container-storage-interface/spec v1.5.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect - github.com/containerd/console v1.0.3 // indirect + github.com/containerd/console v1.0.4 // indirect github.com/containerd/go-cni v1.1.9 // indirect github.com/containerd/go-runc v1.1.0 // indirect github.com/containerd/nydus-snapshotter v0.13.7 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/ttrpc v1.2.2 // indirect github.com/containernetworking/cni v1.1.2 // indirect + github.com/containernetworking/plugins v1.4.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect @@ -185,7 +187,6 @@ require ( github.com/spdx/tools-golang v0.5.1 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/tinylib/msgp v1.1.8 // indirect - github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect @@ -198,9 +199,14 @@ require ( go.etcd.io/etcd/server/v3 v3.5.6 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect diff --git a/vendor.sum b/vendor.sum index c64ec5ef4ebe1..c4568b046b7c4 100644 --- a/vendor.sum +++ b/vendor.sum @@ -34,6 +34,7 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc= +cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= cloud.google.com/go/logging v1.8.1 h1:26skQWPeYhvIasWKm48+Eq7oUqdcdbwsCVwz5Ys0FvU= cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= cloud.google.com/go/longrunning v0.5.2 h1:u+oFqfEwwU7F9dIELigxbe0XVnBAo9wqMuQLA50CZ5k= @@ -119,6 +120,7 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -147,7 +149,9 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/akutz/gosync v0.1.0 h1:naxPT/aDYDh79PMwM3XmencmNQeYmpNFSZy4ZE9zIW0= +github.com/akutz/gosync v0.1.0/go.mod h1:I8I4aiqJI1nqaeYOOB1WS+CgRJVVPqhct9Y4njywM84= github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -276,6 +280,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= @@ -285,6 +290,7 @@ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOi github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/container-storage-interface/spec v1.5.0 h1:lvKxe3uLgqQeVQcrnL2CPQKISoKjTJxojEs9cBk+HXo= github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= @@ -298,8 +304,8 @@ github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= +github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -328,8 +334,8 @@ github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3 github.com/containerd/nydus-snapshotter v0.13.7 h1:x7DHvGnzJOu1ZPwPYkeOPk5MjZZYbdddygEjaSDoFTk= github.com/containerd/nydus-snapshotter v0.13.7/go.mod h1:VPVKQ3jmHFIcUIV2yiQ1kImZuBFS3GXDohKs9mRABVE= github.com/containerd/stargz-snapshotter v0.0.0-20201027054423-3a04e4c2c116/go.mod h1:o59b3PCKVAf9jjiKtCc/9hLAd+5p/rfhBfm6aBcTEr4= -github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= +github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs= @@ -341,6 +347,8 @@ github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3H github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic= +github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ= @@ -443,6 +451,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -457,6 +466,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -506,6 +516,7 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= @@ -549,6 +560,7 @@ github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2 h1:xisWqjiKEff2B0KfFYG github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -644,8 +656,9 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk= +github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= @@ -826,6 +839,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -899,8 +913,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlKZIaiQ= -github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0= -github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso= +github.com/moby/buildkit v0.13.0-rc2 h1:LWAIkaBIoRTne57NJCnFMdFV30auPia3j9UUZeUc24A= +github.com/moby/buildkit v0.13.0-rc2/go.mod h1:RWPZ1bRcehlF1bjPzj7+wOPZ5cLViAEtx5ZNQWma5/s= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ= @@ -971,8 +985,10 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= +github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -982,7 +998,8 @@ github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1031,6 +1048,7 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee h1:P6U24L02WMfj9ymZTxl7CxS73JC99x3ukk+DBkgQGQs= +github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -1097,12 +1115,14 @@ github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rexray/gocsi v1.2.2 h1:h9F/eSizORihN+XT+mxhq7ClZ3cYo1L9RvasN6dKz8U= +github.com/rexray/gocsi v1.2.2/go.mod h1:X9oJHHpIVGmfKdK8e+JuCXafggk7HxL9mWQOgrsoHpo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rootless-containers/rootlesskit/v2 v2.0.1 h1:yMUDTn9dMWtTkccosPDJpMVxjhmEjSD6jYyaePCXshg= github.com/rootless-containers/rootlesskit/v2 v2.0.1/go.mod h1:ZwETpgA/DPizAF7Zdui4ZHOfYK5rZ4Z4SUO6omyZVfY= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -1200,6 +1220,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1224,8 +1245,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1 github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85/go.mod h1:a7cilN64dG941IOXfhJhlH0qB92hxJ9A1ewrdUmJ6xo= -github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb h1:uUe8rNyVXM8moActoBol6Xf6xX2GMr7SosR2EywMvGg= -github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb/go.mod h1:SxX/oNQ/ag6Vaoli547ipFK9J7BZn5JqJG0JE8lf8bA= +github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6 h1:v9u6pmdUkarXL/1S/6LGcG9wsiBLd9N/WyJq/Y9WPcg= +github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 h1:8eY6m1mjgyB8XySUR7WvebTM8D/Vs86jLJzD/Tw7zkc= github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7/go.mod h1:qqvyZqkfwkoJuPU/bw61bItaoO0SJ8YSW0vSVRRvsRg= github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= @@ -1272,6 +1293,7 @@ github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfD github.com/xanzy/go-gitlab v0.32.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= @@ -1334,6 +1356,12 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= @@ -1342,11 +1370,15 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqhe go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= +go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA= +go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA= go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= +go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= @@ -1361,6 +1393,7 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= @@ -1621,6 +1654,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1854,6 +1888,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1931,7 +1966,9 @@ k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuB k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= kernel.org/pub/linux/libs/security/libcap/cap v1.2.67 h1:sPQ9qlSNR26fToTKbxe/HDWJlXvBLqGmt84LGCQkOy0= +kernel.org/pub/linux/libs/security/libcap/cap v1.2.67/go.mod h1:GkntoBuwffz19qtdFVB+k2NtWNN+yCKnC/Ykv/hMiTU= kernel.org/pub/linux/libs/security/libcap/psx v1.2.67 h1:NxbXJ7pDVq0FKBsqjieT92QDXI2XaqH2HAi4QcCOHt8= +kernel.org/pub/linux/libs/security/libcap/psx v1.2.67/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/vendor/github.com/containerd/console/.golangci.yml b/vendor/github.com/containerd/console/.golangci.yml index fcba5e885f0a0..abe3d84bb1648 100644 --- a/vendor/github.com/containerd/console/.golangci.yml +++ b/vendor/github.com/containerd/console/.golangci.yml @@ -1,16 +1,16 @@ linters: enable: - - structcheck - - varcheck - - staticcheck - - unconvert - gofmt - goimports - - golint - ineffassign - - vet - - unused - misspell + - revive + - staticcheck + - structcheck + - unconvert + - unused + - varcheck + - vet disable: - errcheck diff --git a/vendor/github.com/containerd/console/README.md b/vendor/github.com/containerd/console/README.md index 580b461a73dbb..a849a728f1e59 100644 --- a/vendor/github.com/containerd/console/README.md +++ b/vendor/github.com/containerd/console/README.md @@ -22,8 +22,8 @@ current.Resize(ws) console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). As a containerd sub-project, you will find the: - * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), - * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), - * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md) information in our [`containerd/project`](https://github.com/containerd/project) repository. diff --git a/vendor/github.com/containerd/console/console.go b/vendor/github.com/containerd/console/console.go index f989d28a41cd4..dd587d88e0728 100644 --- a/vendor/github.com/containerd/console/console.go +++ b/vendor/github.com/containerd/console/console.go @@ -22,7 +22,10 @@ import ( "os" ) -var ErrNotAConsole = errors.New("provided file is not a console") +var ( + ErrNotAConsole = errors.New("provided file is not a console") + ErrNotImplemented = errors.New("not implemented") +) type File interface { io.ReadWriteCloser @@ -45,7 +48,7 @@ type Console interface { SetRaw() error // DisableEcho disables echo on the console DisableEcho() error - // Reset restores the console to its orignal state + // Reset restores the console to its original state Reset() error // Size returns the window size of the console Size() (WinSize, error) @@ -78,7 +81,7 @@ func Current() (c Console) { } // ConsoleFromFile returns a console using the provided file -// nolint:golint +// nolint:revive func ConsoleFromFile(f File) (Console, error) { if err := checkConsole(f); err != nil { return nil, err diff --git a/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/containerd/console/console_linux.go index c1c839ee3ae02..28b77b7a38918 100644 --- a/vendor/github.com/containerd/console/console_linux.go +++ b/vendor/github.com/containerd/console/console_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux /* diff --git a/vendor/github.com/containerd/console/console_other.go b/vendor/github.com/containerd/console/console_other.go new file mode 100644 index 0000000000000..933dfadddae6a --- /dev/null +++ b/vendor/github.com/containerd/console/console_other.go @@ -0,0 +1,36 @@ +//go:build !darwin && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos +// +build !darwin,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows,!zos + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +// NewPty creates a new pty pair +// The master is returned as the first console and a string +// with the path to the pty slave is returned as the second +func NewPty() (Console, string, error) { + return nil, "", ErrNotImplemented +} + +// checkConsole checks if the provided file is a console +func checkConsole(f File) error { + return ErrNotAConsole +} + +func newMaster(f File) (Console, error) { + return nil, ErrNotImplemented +} diff --git a/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/containerd/console/console_unix.go index a08117695e320..161f5d126cbad 100644 --- a/vendor/github.com/containerd/console/console_unix.go +++ b/vendor/github.com/containerd/console/console_unix.go @@ -1,4 +1,5 @@ -// +build darwin freebsd linux netbsd openbsd solaris +//go:build darwin || freebsd || linux || netbsd || openbsd || zos +// +build darwin freebsd linux netbsd openbsd zos /* Copyright The containerd Authors. diff --git a/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/containerd/console/console_windows.go index 787c11fe56fd9..6896db1825fef 100644 --- a/vendor/github.com/containerd/console/console_windows.go +++ b/vendor/github.com/containerd/console/console_windows.go @@ -24,12 +24,13 @@ import ( "golang.org/x/sys/windows" ) -var ( - vtInputSupported bool - ErrNotImplemented = errors.New("not implemented") -) +var vtInputSupported bool func (m *master) initStdios() { + // Note: We discard console mode warnings, because in/out can be redirected. + // + // TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly + m.in = windows.Handle(os.Stdin.Fd()) if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil { // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it. @@ -39,8 +40,6 @@ func (m *master) initStdios() { // Unconditionally set the console mode back even on failure because SetConsoleMode // remembers invalid bits on input handles. windows.SetConsoleMode(m.in, m.inMode) - } else { - fmt.Printf("failed to get console mode for stdin: %v\n", err) } m.out = windows.Handle(os.Stdout.Fd()) @@ -50,8 +49,6 @@ func (m *master) initStdios() { } else { windows.SetConsoleMode(m.out, m.outMode) } - } else { - fmt.Printf("failed to get console mode for stdout: %v\n", err) } m.err = windows.Handle(os.Stderr.Fd()) @@ -61,8 +58,6 @@ func (m *master) initStdios() { } else { windows.SetConsoleMode(m.err, m.errMode) } - } else { - fmt.Printf("failed to get console mode for stderr: %v\n", err) } } @@ -94,6 +89,8 @@ func (m *master) SetRaw() error { } func (m *master) Reset() error { + var errs []error + for _, s := range []struct { fd windows.Handle mode uint32 @@ -103,10 +100,16 @@ func (m *master) Reset() error { {m.err, m.errMode}, } { if err := windows.SetConsoleMode(s.fd, s.mode); err != nil { - return fmt.Errorf("unable to restore console mode: %w", err) + // we can't just abort on the first error, otherwise we might leave + // the console in an unexpected state. + errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err)) } } + if len(errs) > 0 { + return errs[0] + } + return nil } diff --git a/vendor/github.com/containerd/console/console_zos.go b/vendor/github.com/containerd/console/console_zos.go deleted file mode 100644 index b348a839a03b8..0000000000000 --- a/vendor/github.com/containerd/console/console_zos.go +++ /dev/null @@ -1,163 +0,0 @@ -// +build zos - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -// NewPty creates a new pty pair -// The master is returned as the first console and a string -// with the path to the pty slave is returned as the second -func NewPty() (Console, string, error) { - var f File - var err error - var slave string - for i := 0;; i++ { - ptyp := fmt.Sprintf("/dev/ptyp%04d", i) - f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) - if err == nil { - slave = fmt.Sprintf("/dev/ttyp%04d", i) - break - } - if os.IsNotExist(err) { - return nil, "", err - } - // else probably Resource Busy - } - m, err := newMaster(f) - if err != nil { - return nil, "", err - } - return m, slave, nil -} - -type master struct { - f File - original *unix.Termios -} - -func (m *master) Read(b []byte) (int, error) { - return m.f.Read(b) -} - -func (m *master) Write(b []byte) (int, error) { - return m.f.Write(b) -} - -func (m *master) Close() error { - return m.f.Close() -} - -func (m *master) Resize(ws WinSize) error { - return tcswinsz(m.f.Fd(), ws) -} - -func (m *master) ResizeFrom(c Console) error { - ws, err := c.Size() - if err != nil { - return err - } - return m.Resize(ws) -} - -func (m *master) Reset() error { - if m.original == nil { - return nil - } - return tcset(m.f.Fd(), m.original) -} - -func (m *master) getCurrent() (unix.Termios, error) { - var termios unix.Termios - if err := tcget(m.f.Fd(), &termios); err != nil { - return unix.Termios{}, err - } - return termios, nil -} - -func (m *master) SetRaw() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState = cfmakeraw(rawState) - rawState.Oflag = rawState.Oflag | unix.OPOST - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) DisableEcho() error { - rawState, err := m.getCurrent() - if err != nil { - return err - } - rawState.Lflag = rawState.Lflag &^ unix.ECHO - return tcset(m.f.Fd(), &rawState) -} - -func (m *master) Size() (WinSize, error) { - return tcgwinsz(m.f.Fd()) -} - -func (m *master) Fd() uintptr { - return m.f.Fd() -} - -func (m *master) Name() string { - return m.f.Name() -} - -// checkConsole checks if the provided file is a console -func checkConsole(f File) error { - var termios unix.Termios - if tcget(f.Fd(), &termios) != nil { - return ErrNotAConsole - } - return nil -} - -func newMaster(f File) (Console, error) { - m := &master{ - f: f, - } - t, err := m.getCurrent() - if err != nil { - return nil, err - } - m.original = &t - return m, nil -} - -// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts normally. In particular, a not-very-well-known default of -// Linux unix98 ptys is that they have +onlcr by default. While this isn't a -// problem for terminal emulators, because we relay data from the terminal we -// also relay that funky line discipline. -func ClearONLCR(fd uintptr) error { - return setONLCR(fd, false) -} - -// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair -// created by us acts as intended for a terminal emulator. -func SetONLCR(fd uintptr) error { - return setONLCR(fd, true) -} diff --git a/vendor/github.com/containerd/console/pty_freebsd_cgo.go b/vendor/github.com/containerd/console/pty_freebsd_cgo.go index cbd3cd7ea43d8..22368623aab23 100644 --- a/vendor/github.com/containerd/console/pty_freebsd_cgo.go +++ b/vendor/github.com/containerd/console/pty_freebsd_cgo.go @@ -1,3 +1,4 @@ +//go:build freebsd && cgo // +build freebsd,cgo /* diff --git a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go index b5e43181d4f36..ceb90a47b8189 100644 --- a/vendor/github.com/containerd/console/pty_freebsd_nocgo.go +++ b/vendor/github.com/containerd/console/pty_freebsd_nocgo.go @@ -1,3 +1,4 @@ +//go:build freebsd && !cgo // +build freebsd,!cgo /* diff --git a/vendor/github.com/containerd/console/pty_unix.go b/vendor/github.com/containerd/console/pty_unix.go index d5a6bd8ca2e80..f5a5b8058c650 100644 --- a/vendor/github.com/containerd/console/pty_unix.go +++ b/vendor/github.com/containerd/console/pty_unix.go @@ -1,4 +1,5 @@ -// +build darwin linux netbsd openbsd solaris +//go:build darwin || linux || netbsd || openbsd +// +build darwin linux netbsd openbsd /* Copyright The containerd Authors. diff --git a/vendor/github.com/containerd/console/pty_zos.go b/vendor/github.com/containerd/console/pty_zos.go new file mode 100644 index 0000000000000..58f59aba58c98 --- /dev/null +++ b/vendor/github.com/containerd/console/pty_zos.go @@ -0,0 +1,43 @@ +//go:build zos +// +build zos + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" +) + +// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device +func openpt() (*os.File, error) { + var f *os.File + var err error + for i := 0; ; i++ { + ptyp := fmt.Sprintf("/dev/ptyp%04d", i) + f, err = os.OpenFile(ptyp, os.O_RDWR, 0600) + if err == nil { + break + } + if os.IsNotExist(err) { + return nil, err + } + // else probably Resource Busy + } + return f, nil +} diff --git a/vendor/github.com/containerd/console/tc_freebsd_cgo.go b/vendor/github.com/containerd/console/tc_freebsd_cgo.go index 0f3d27273094c..33282579411ee 100644 --- a/vendor/github.com/containerd/console/tc_freebsd_cgo.go +++ b/vendor/github.com/containerd/console/tc_freebsd_cgo.go @@ -1,3 +1,4 @@ +//go:build freebsd && cgo // +build freebsd,cgo /* diff --git a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go index 087fc158a1696..18a9b9cbea97a 100644 --- a/vendor/github.com/containerd/console/tc_freebsd_nocgo.go +++ b/vendor/github.com/containerd/console/tc_freebsd_nocgo.go @@ -1,3 +1,4 @@ +//go:build freebsd && !cgo // +build freebsd,!cgo /* diff --git a/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/containerd/console/tc_openbsd_cgo.go index f0cec06a72dc8..0e76f6cc3e0af 100644 --- a/vendor/github.com/containerd/console/tc_openbsd_cgo.go +++ b/vendor/github.com/containerd/console/tc_openbsd_cgo.go @@ -1,3 +1,4 @@ +//go:build openbsd && cgo // +build openbsd,cgo /* diff --git a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go index daccce20585a7..dca92418b0e53 100644 --- a/vendor/github.com/containerd/console/tc_openbsd_nocgo.go +++ b/vendor/github.com/containerd/console/tc_openbsd_nocgo.go @@ -1,3 +1,4 @@ +//go:build openbsd && !cgo // +build openbsd,!cgo /* diff --git a/vendor/github.com/containerd/console/tc_solaris_cgo.go b/vendor/github.com/containerd/console/tc_solaris_cgo.go deleted file mode 100644 index e36a68edd1ed7..0000000000000 --- a/vendor/github.com/containerd/console/tc_solaris_cgo.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build solaris,cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "os" - - "golang.org/x/sys/unix" -) - -//#include -import "C" - -const ( - cmdTcGet = unix.TCGETS - cmdTcSet = unix.TCSETS -) - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - ptspath, err := C.ptsname(C.int(f.Fd())) - if err != nil { - return "", err - } - return C.GoString(ptspath), nil -} - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -func unlockpt(f *os.File) error { - if _, err := C.grantpt(C.int(f.Fd())); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/containerd/console/tc_solaris_nocgo.go b/vendor/github.com/containerd/console/tc_solaris_nocgo.go deleted file mode 100644 index eb0bd2c36b830..0000000000000 --- a/vendor/github.com/containerd/console/tc_solaris_nocgo.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build solaris,!cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// -// Implementing the functions below requires cgo support. Non-cgo stubs -// versions are defined below to enable cross-compilation of source code -// that depends on these functions, but the resultant cross-compiled -// binaries cannot actually be used. If the stub function(s) below are -// actually invoked they will display an error message and cause the -// calling process to exit. -// - -package console - -import ( - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TCGETS - cmdTcSet = unix.TCSETS -) - -func ptsname(f *os.File) (string, error) { - panic("ptsname() support requires cgo.") -} - -func unlockpt(f *os.File) error { - panic("unlockpt() support requires cgo.") -} diff --git a/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/containerd/console/tc_unix.go index a6bf01e8d1a2b..2ecf188fca330 100644 --- a/vendor/github.com/containerd/console/tc_unix.go +++ b/vendor/github.com/containerd/console/tc_unix.go @@ -1,4 +1,5 @@ -// +build darwin freebsd linux netbsd openbsd solaris zos +//go:build darwin || freebsd || linux || netbsd || openbsd || zos +// +build darwin freebsd linux netbsd openbsd zos /* Copyright The containerd Authors. @@ -83,7 +84,7 @@ func cfmakeraw(t unix.Termios) unix.Termios { t.Oflag &^= unix.OPOST t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN) t.Cflag &^= (unix.CSIZE | unix.PARENB) - t.Cflag &^= unix.CS8 + t.Cflag |= unix.CS8 t.Cc[unix.VMIN] = 1 t.Cc[unix.VTIME] = 0 diff --git a/vendor/github.com/containerd/console/tc_zos.go b/vendor/github.com/containerd/console/tc_zos.go index 4262eaf4cc076..fc90ba5fb86e3 100644 --- a/vendor/github.com/containerd/console/tc_zos.go +++ b/vendor/github.com/containerd/console/tc_zos.go @@ -17,6 +17,9 @@ package console import ( + "os" + "strings" + "golang.org/x/sys/unix" ) @@ -24,3 +27,13 @@ const ( cmdTcGet = unix.TCGETS cmdTcSet = unix.TCSETS ) + +// unlockpt is a no-op on zos. +func unlockpt(_ *os.File) error { + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil +} diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go index b071cea51dde9..6aba0ef1f6928 100644 --- a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go +++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go @@ -436,9 +436,8 @@ func importTar(in io.ReaderAt) (*tarFile, error) { if err != nil { if err == io.EOF { break - } else { - return nil, fmt.Errorf("failed to parse tar file, %w", err) } + return nil, fmt.Errorf("failed to parse tar file, %w", err) } switch cleanEntryName(h.Name) { case PrefetchLandmark, NoPrefetchLandmark: diff --git a/vendor/github.com/containernetworking/plugins/LICENSE b/vendor/github.com/containernetworking/plugins/LICENSE new file mode 100644 index 0000000000000..8dada3edaf50d --- /dev/null +++ b/vendor/github.com/containernetworking/plugins/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/containernetworking/plugins/pkg/ns/README.md b/vendor/github.com/containernetworking/plugins/pkg/ns/README.md new file mode 100644 index 0000000000000..1e265c7a011fe --- /dev/null +++ b/vendor/github.com/containernetworking/plugins/pkg/ns/README.md @@ -0,0 +1,41 @@ +### Namespaces, Threads, and Go +On Linux each OS thread can have a different network namespace. Go's thread scheduling model switches goroutines between OS threads based on OS thread load and whether the goroutine would block other goroutines. This can result in a goroutine switching network namespaces without notice and lead to errors in your code. + +### Namespace Switching +Switching namespaces with the `ns.Set()` method is not recommended without additional strategies to prevent unexpected namespace changes when your goroutines switch OS threads. + +Go provides the `runtime.LockOSThread()` function to ensure a specific goroutine executes on its current OS thread and prevents any other goroutine from running in that thread until the locked one exits. Careful usage of `LockOSThread()` and goroutines can provide good control over which network namespace a given goroutine executes in. + +For example, you cannot rely on the `ns.Set()` namespace being the current namespace after the `Set()` call unless you do two things. First, the goroutine calling `Set()` must have previously called `LockOSThread()`. Second, you must ensure `runtime.UnlockOSThread()` is not called somewhere in-between. You also cannot rely on the initial network namespace remaining the current network namespace if any other code in your program switches namespaces, unless you have already called `LockOSThread()` in that goroutine. Note that `LockOSThread()` prevents the Go scheduler from optimally scheduling goroutines for best performance, so `LockOSThread()` should only be used in small, isolated goroutines that release the lock quickly. + +### Do() The Recommended Thing +The `ns.Do()` method provides **partial** control over network namespaces for you by implementing these strategies. All code dependent on a particular network namespace (including the root namespace) should be wrapped in the `ns.Do()` method to ensure the correct namespace is selected for the duration of your code. For example: + +```go +err = targetNs.Do(func(hostNs ns.NetNS) error { + dummy := &netlink.Dummy{ + LinkAttrs: netlink.LinkAttrs{ + Name: "dummy0", + }, + } + return netlink.LinkAdd(dummy) +}) +``` + +Note this requirement to wrap every network call is very onerous - any libraries you call might call out to network services such as DNS, and all such calls need to be protected after you call `ns.Do()`. All goroutines spawned from within the `ns.Do` will not inherit the new namespace. The CNI plugins all exit very soon after calling `ns.Do()` which helps to minimize the problem. + +When a new thread is spawned in Linux, it inherits the namespace of its parent. In versions of go **prior to 1.10**, if the runtime spawns a new OS thread, it picks the parent randomly. If the chosen parent thread has been moved to a new namespace (even temporarily), the new OS thread will be permanently "stuck in the wrong namespace", and goroutines will non-deterministically switch namespaces as they are rescheduled. + +In short, **there was no safe way to change network namespaces, even temporarily, from within a long-lived, multithreaded Go process**. If you wish to do this, you must use go 1.10 or greater. + + +### Creating network namespaces +Earlier versions of this library managed namespace creation, but as CNI does not actually utilize this feature (and it was essentially unmaintained), it was removed. If you're writing a container runtime, you should implement namespace management yourself. However, there are some gotchas when doing so, especially around handling `/var/run/netns`. A reasonably correct reference implementation, borrowed from `rkt`, can be found in `pkg/testutils/netns_linux.go` if you're in need of a source of inspiration. + + +### Further Reading + - https://github.com/golang/go/wiki/LockOSThread + - http://morsmachine.dk/go-scheduler + - https://github.com/containernetworking/cni/issues/262 + - https://golang.org/pkg/runtime/ + - https://www.weave.works/blog/linux-namespaces-and-go-don-t-mix diff --git a/vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go b/vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go new file mode 100644 index 0000000000000..f260f28132ebd --- /dev/null +++ b/vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go @@ -0,0 +1,234 @@ +// Copyright 2015-2017 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ns + +import ( + "fmt" + "os" + "runtime" + "sync" + "syscall" + + "golang.org/x/sys/unix" +) + +// Returns an object representing the current OS thread's network namespace +func GetCurrentNS() (NetNS, error) { + // Lock the thread in case other goroutine executes in it and changes its + // network namespace after getCurrentThreadNetNSPath(), otherwise it might + // return an unexpected network namespace. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + return GetNS(getCurrentThreadNetNSPath()) +} + +func getCurrentThreadNetNSPath() string { + // /proc/self/ns/net returns the namespace of the main thread, not + // of whatever thread this goroutine is running on. Make sure we + // use the thread's net namespace since the thread is switching around + return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()) +} + +func (ns *netNS) Close() error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + if err := ns.file.Close(); err != nil { + return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err) + } + ns.closed = true + + return nil +} + +func (ns *netNS) Set() error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + if err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil { + return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err) + } + + return nil +} + +type NetNS interface { + // Executes the passed closure in this object's network namespace, + // attempting to restore the original namespace before returning. + // However, since each OS thread can have a different network namespace, + // and Go's thread scheduling is highly variable, callers cannot + // guarantee any specific namespace is set unless operations that + // require that namespace are wrapped with Do(). Also, no code called + // from Do() should call runtime.UnlockOSThread(), or the risk + // of executing code in an incorrect namespace will be greater. See + // https://github.com/golang/go/wiki/LockOSThread for further details. + Do(toRun func(NetNS) error) error + + // Sets the current network namespace to this object's network namespace. + // Note that since Go's thread scheduling is highly variable, callers + // cannot guarantee the requested namespace will be the current namespace + // after this function is called; to ensure this wrap operations that + // require the namespace with Do() instead. + Set() error + + // Returns the filesystem path representing this object's network namespace + Path() string + + // Returns a file descriptor representing this object's network namespace + Fd() uintptr + + // Cleans up this instance of the network namespace; if this instance + // is the last user the namespace will be destroyed + Close() error +} + +type netNS struct { + file *os.File + closed bool +} + +// netNS implements the NetNS interface +var _ NetNS = &netNS{} + +const ( + // https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h + NSFS_MAGIC = unix.NSFS_MAGIC + PROCFS_MAGIC = unix.PROC_SUPER_MAGIC +) + +type NSPathNotExistErr struct{ msg string } + +func (e NSPathNotExistErr) Error() string { return e.msg } + +type NSPathNotNSErr struct{ msg string } + +func (e NSPathNotNSErr) Error() string { return e.msg } + +func IsNSorErr(nspath string) error { + stat := syscall.Statfs_t{} + if err := syscall.Statfs(nspath, &stat); err != nil { + if os.IsNotExist(err) { + err = NSPathNotExistErr{msg: fmt.Sprintf("failed to Statfs %q: %v", nspath, err)} + } else { + err = fmt.Errorf("failed to Statfs %q: %v", nspath, err) + } + return err + } + + switch stat.Type { + case PROCFS_MAGIC, NSFS_MAGIC: + return nil + default: + return NSPathNotNSErr{msg: fmt.Sprintf("unknown FS magic on %q: %x", nspath, stat.Type)} + } +} + +// Returns an object representing the namespace referred to by @path +func GetNS(nspath string) (NetNS, error) { + err := IsNSorErr(nspath) + if err != nil { + return nil, err + } + + fd, err := os.Open(nspath) + if err != nil { + return nil, err + } + + return &netNS{file: fd}, nil +} + +func (ns *netNS) Path() string { + return ns.file.Name() +} + +func (ns *netNS) Fd() uintptr { + return ns.file.Fd() +} + +func (ns *netNS) errorIfClosed() error { + if ns.closed { + return fmt.Errorf("%q has already been closed", ns.file.Name()) + } + return nil +} + +func (ns *netNS) Do(toRun func(NetNS) error) error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + containedCall := func(hostNS NetNS) error { + threadNS, err := GetCurrentNS() + if err != nil { + return fmt.Errorf("failed to open current netns: %v", err) + } + defer threadNS.Close() + + // switch to target namespace + if err = ns.Set(); err != nil { + return fmt.Errorf("error switching to ns %v: %v", ns.file.Name(), err) + } + defer func() { + err := threadNS.Set() // switch back + if err == nil { + // Unlock the current thread only when we successfully switched back + // to the original namespace; otherwise leave the thread locked which + // will force the runtime to scrap the current thread, that is maybe + // not as optimal but at least always safe to do. + runtime.UnlockOSThread() + } + }() + + return toRun(hostNS) + } + + // save a handle to current network namespace + hostNS, err := GetCurrentNS() + if err != nil { + return fmt.Errorf("Failed to open current namespace: %v", err) + } + defer hostNS.Close() + + var wg sync.WaitGroup + wg.Add(1) + + // Start the callback in a new green thread so that if we later fail + // to switch the namespace back to the original one, we can safely + // leave the thread locked to die without a risk of the current thread + // left lingering with incorrect namespace. + var innerError error + go func() { + defer wg.Done() + runtime.LockOSThread() + innerError = containedCall(hostNS) + }() + wg.Wait() + + return innerError +} + +// WithNetNSPath executes the passed closure under the given network +// namespace, restoring the original namespace afterwards. +func WithNetNSPath(nspath string, toRun func(NetNS) error) error { + ns, err := GetNS(nspath) + if err != nil { + return err + } + defer ns.Close() + return ns.Do(toRun) +} diff --git a/vendor/github.com/docker/distribution/reference/helpers_deprecated.go b/vendor/github.com/docker/distribution/reference/helpers_deprecated.go deleted file mode 100644 index cbd119250adf2..0000000000000 --- a/vendor/github.com/docker/distribution/reference/helpers_deprecated.go +++ /dev/null @@ -1,34 +0,0 @@ -package reference - -import "github.com/distribution/reference" - -// IsNameOnly returns true if reference only contains a repo name. -// -// Deprecated: use [reference.IsNameOnly]. -func IsNameOnly(ref reference.Named) bool { - return reference.IsNameOnly(ref) -} - -// FamiliarName returns the familiar name string -// for the given named, familiarizing if needed. -// -// Deprecated: use [reference.FamiliarName]. -func FamiliarName(ref reference.Named) string { - return reference.FamiliarName(ref) -} - -// FamiliarString returns the familiar string representation -// for the given reference, familiarizing if needed. -// -// Deprecated: use [reference.FamiliarString]. -func FamiliarString(ref reference.Reference) string { - return reference.FamiliarString(ref) -} - -// FamiliarMatch reports whether ref matches the specified pattern. -// See [path.Match] for supported patterns. -// -// Deprecated: use [reference.FamiliarMatch]. -func FamiliarMatch(pattern string, ref reference.Reference) (bool, error) { - return reference.FamiliarMatch(pattern, ref) -} diff --git a/vendor/github.com/docker/distribution/reference/normalize_deprecated.go b/vendor/github.com/docker/distribution/reference/normalize_deprecated.go deleted file mode 100644 index 1b4a459d700dd..0000000000000 --- a/vendor/github.com/docker/distribution/reference/normalize_deprecated.go +++ /dev/null @@ -1,92 +0,0 @@ -package reference - -import ( - "regexp" - - "github.com/distribution/reference" - "github.com/opencontainers/go-digest" - "github.com/opencontainers/go-digest/digestset" -) - -// ParseNormalizedNamed parses a string into a named reference -// transforming a familiar name from Docker UI to a fully -// qualified reference. If the value may be an identifier -// use ParseAnyReference. -// -// Deprecated: use [reference.ParseNormalizedNamed]. -func ParseNormalizedNamed(s string) (reference.Named, error) { - return reference.ParseNormalizedNamed(s) -} - -// ParseDockerRef normalizes the image reference following the docker convention, -// which allows for references to contain both a tag and a digest. -// -// Deprecated: use [reference.ParseDockerRef]. -func ParseDockerRef(ref string) (reference.Named, error) { - return reference.ParseDockerRef(ref) -} - -// TagNameOnly adds the default tag "latest" to a reference if it only has -// a repo name. -// -// Deprecated: use [reference.TagNameOnly]. -func TagNameOnly(ref reference.Named) reference.Named { - return reference.TagNameOnly(ref) -} - -// ParseAnyReference parses a reference string as a possible identifier, -// full digest, or familiar name. -// -// Deprecated: use [reference.ParseAnyReference]. -func ParseAnyReference(ref string) (reference.Reference, error) { - return reference.ParseAnyReference(ref) -} - -// Functions and types below have been removed in distribution v3 and -// have not been ported to github.com/distribution/reference. See -// https://github.com/distribution/distribution/pull/3774 - -var ( - // ShortIdentifierRegexp is the format used to represent a prefix - // of an identifier. A prefix may be used to match a sha256 identifier - // within a list of trusted identifiers. - // - // Deprecated: support for short-identifiers is deprecated, and will be removed in v3. - ShortIdentifierRegexp = regexp.MustCompile(shortIdentifier) - - shortIdentifier = `([a-f0-9]{6,64})` - - // anchoredShortIdentifierRegexp is used to check if a value - // is a possible identifier prefix, anchored at start and end - // of string. - anchoredShortIdentifierRegexp = regexp.MustCompile(`^` + shortIdentifier + `$`) -) - -type digestReference digest.Digest - -func (d digestReference) String() string { - return digest.Digest(d).String() -} - -func (d digestReference) Digest() digest.Digest { - return digest.Digest(d) -} - -// ParseAnyReferenceWithSet parses a reference string as a possible short -// identifier to be matched in a digest set, a full digest, or familiar name. -// -// Deprecated: support for short-identifiers is deprecated, and will be removed in v3. -func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { - if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { - dgst, err := ds.Lookup(ref) - if err == nil { - return digestReference(dgst), nil - } - } else { - if dgst, err := digest.Parse(ref); err == nil { - return digestReference(dgst), nil - } - } - - return reference.ParseNormalizedNamed(ref) -} diff --git a/vendor/github.com/docker/distribution/reference/reference_deprecated.go b/vendor/github.com/docker/distribution/reference/reference_deprecated.go deleted file mode 100644 index 5b732498ebf25..0000000000000 --- a/vendor/github.com/docker/distribution/reference/reference_deprecated.go +++ /dev/null @@ -1,172 +0,0 @@ -// Package reference is deprecated, and has moved to github.com/distribution/reference. -// -// Deprecated: use github.com/distribution/reference instead. -package reference - -import ( - "github.com/distribution/reference" - "github.com/opencontainers/go-digest" -) - -const ( - // NameTotalLengthMax is the maximum total number of characters in a repository name. - // - // Deprecated: use [reference.NameTotalLengthMax]. - NameTotalLengthMax = reference.NameTotalLengthMax -) - -var ( - // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. - // - // Deprecated: use [reference.ErrReferenceInvalidFormat]. - ErrReferenceInvalidFormat = reference.ErrReferenceInvalidFormat - - // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. - // - // Deprecated: use [reference.ErrTagInvalidFormat]. - ErrTagInvalidFormat = reference.ErrTagInvalidFormat - - // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. - // - // Deprecated: use [reference.ErrDigestInvalidFormat]. - ErrDigestInvalidFormat = reference.ErrDigestInvalidFormat - - // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. - // - // Deprecated: use [reference.ErrNameContainsUppercase]. - ErrNameContainsUppercase = reference.ErrNameContainsUppercase - - // ErrNameEmpty is returned for empty, invalid repository names. - // - // Deprecated: use [reference.ErrNameEmpty]. - ErrNameEmpty = reference.ErrNameEmpty - - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - // - // Deprecated: use [reference.ErrNameTooLong]. - ErrNameTooLong = reference.ErrNameTooLong - - // ErrNameNotCanonical is returned when a name is not canonical. - // - // Deprecated: use [reference.ErrNameNotCanonical]. - ErrNameNotCanonical = reference.ErrNameNotCanonical -) - -// Reference is an opaque object reference identifier that may include -// modifiers such as a hostname, name, tag, and digest. -// -// Deprecated: use [reference.Reference]. -type Reference = reference.Reference - -// Field provides a wrapper type for resolving correct reference types when -// working with encoding. -// -// Deprecated: use [reference.Field]. -type Field = reference.Field - -// AsField wraps a reference in a Field for encoding. -// -// Deprecated: use [reference.AsField]. -func AsField(ref reference.Reference) reference.Field { - return reference.AsField(ref) -} - -// Named is an object with a full name -// -// Deprecated: use [reference.Named]. -type Named = reference.Named - -// Tagged is an object which has a tag -// -// Deprecated: use [reference.Tagged]. -type Tagged = reference.Tagged - -// NamedTagged is an object including a name and tag. -// -// Deprecated: use [reference.NamedTagged]. -type NamedTagged reference.NamedTagged - -// Digested is an object which has a digest -// in which it can be referenced by -// -// Deprecated: use [reference.Digested]. -type Digested reference.Digested - -// Canonical reference is an object with a fully unique -// name including a name with domain and digest -// -// Deprecated: use [reference.Canonical]. -type Canonical reference.Canonical - -// Domain returns the domain part of the [Named] reference. -// -// Deprecated: use [reference.Domain]. -func Domain(named reference.Named) string { - return reference.Domain(named) -} - -// Path returns the name without the domain part of the [Named] reference. -// -// Deprecated: use [reference.Path]. -func Path(named reference.Named) (name string) { - return reference.Path(named) -} - -// SplitHostname splits a named reference into a -// hostname and name string. If no valid hostname is -// found, the hostname is empty and the full value -// is returned as name -// -// Deprecated: Use [reference.Domain] or [reference.Path]. -func SplitHostname(named reference.Named) (string, string) { - return reference.SplitHostname(named) -} - -// Parse parses s and returns a syntactically valid Reference. -// If an error was encountered it is returned, along with a nil Reference. -// -// Deprecated: use [reference.Parse]. -func Parse(s string) (reference.Reference, error) { - return reference.Parse(s) -} - -// ParseNamed parses s and returns a syntactically valid reference implementing -// the Named interface. The reference must have a name and be in the canonical -// form, otherwise an error is returned. -// If an error was encountered it is returned, along with a nil Reference. -// -// Deprecated: use [reference.ParseNamed]. -func ParseNamed(s string) (reference.Named, error) { - return reference.ParseNamed(s) -} - -// WithName returns a named object representing the given string. If the input -// is invalid ErrReferenceInvalidFormat will be returned. -// -// Deprecated: use [reference.WithName]. -func WithName(name string) (reference.Named, error) { - return reference.WithName(name) -} - -// WithTag combines the name from "name" and the tag from "tag" to form a -// reference incorporating both the name and the tag. -// -// Deprecated: use [reference.WithTag]. -func WithTag(name reference.Named, tag string) (reference.NamedTagged, error) { - return reference.WithTag(name, tag) -} - -// WithDigest combines the name from "name" and the digest from "digest" to form -// a reference incorporating both the name and the digest. -// -// Deprecated: use [reference.WithDigest]. -func WithDigest(name reference.Named, digest digest.Digest) (reference.Canonical, error) { - return reference.WithDigest(name, digest) -} - -// TrimNamed removes any tag or digest from the named reference. -// -// Deprecated: use [reference.TrimNamed]. -func TrimNamed(ref reference.Named) reference.Named { - return reference.TrimNamed(ref) -} diff --git a/vendor/github.com/docker/distribution/reference/regexp_deprecated.go b/vendor/github.com/docker/distribution/reference/regexp_deprecated.go deleted file mode 100644 index 4b9c1b58ebae9..0000000000000 --- a/vendor/github.com/docker/distribution/reference/regexp_deprecated.go +++ /dev/null @@ -1,50 +0,0 @@ -package reference - -import ( - "github.com/distribution/reference" -) - -// DigestRegexp matches well-formed digests, including algorithm (e.g. "sha256:"). -// -// Deprecated: use [reference.DigestRegexp]. -var DigestRegexp = reference.DigestRegexp - -// DomainRegexp matches hostname or IP-addresses, optionally including a port -// number. It defines the structure of potential domain components that may be -// part of image names. This is purposely a subset of what is allowed by DNS to -// ensure backwards compatibility with Docker image names. It may be a subset of -// DNS domain name, an IPv4 address in decimal format, or an IPv6 address between -// square brackets (excluding zone identifiers as defined by [RFC 6874] or special -// addresses such as IPv4-Mapped). -// -// Deprecated: use [reference.DomainRegexp]. -// -// [RFC 6874]: https://www.rfc-editor.org/rfc/rfc6874. -var DomainRegexp = reference.DigestRegexp - -// IdentifierRegexp is the format for string identifier used as a -// content addressable identifier using sha256. These identifiers -// are like digests without the algorithm, since sha256 is used. -// -// Deprecated: use [reference.IdentifierRegexp]. -var IdentifierRegexp = reference.IdentifierRegexp - -// NameRegexp is the format for the name component of references, including -// an optional domain and port, but without tag or digest suffix. -// -// Deprecated: use [reference.NameRegexp]. -var NameRegexp = reference.NameRegexp - -// ReferenceRegexp is the full supported format of a reference. The regexp -// is anchored and has capturing groups for name, tag, and digest -// components. -// -// Deprecated: use [reference.ReferenceRegexp]. -var ReferenceRegexp = reference.ReferenceRegexp - -// TagRegexp matches valid tag names. From [docker/docker:graph/tags.go]. -// -// Deprecated: use [reference.TagRegexp]. -// -// [docker/docker:graph/tags.go]: https://github.com/moby/moby/blob/v1.6.0/graph/tags.go#L26-L28 -var TagRegexp = reference.TagRegexp diff --git a/vendor/github.com/docker/distribution/reference/sort_deprecated.go b/vendor/github.com/docker/distribution/reference/sort_deprecated.go deleted file mode 100644 index a73251b6f5d16..0000000000000 --- a/vendor/github.com/docker/distribution/reference/sort_deprecated.go +++ /dev/null @@ -1,10 +0,0 @@ -package reference - -import "github.com/distribution/reference" - -// Sort sorts string references preferring higher information references. -// -// Deprecated: use [reference.Sort]. -func Sort(references []string) []string { - return reference.Sort(references) -} diff --git a/vendor/github.com/moby/buildkit/AUTHORS b/vendor/github.com/moby/buildkit/AUTHORS index c1dce65586b2b..c5ae03bfcb8d6 100644 --- a/vendor/github.com/moby/buildkit/AUTHORS +++ b/vendor/github.com/moby/buildkit/AUTHORS @@ -1,66 +1,284 @@ # This file lists all individuals having contributed content to the repository. -# For how it is generated, see `scripts/generate-authors.sh`. +# For how it is generated, see hack/dockerfiles/authors.Dockerfile. +a-palchikov Aaron L. Xu Aaron Lehmann +Aaron Lehmann +Abdur Rehman +Addam Hardy +Adrian Plata +Aidan Hobson Sayers Akihiro Suda +Alan Fregtman <941331+darkvertex@users.noreply.github.com> +Alex Couture-Beil +Alex Mayer +Alex Suraci Alexander Morozov +Alexis Murzeau Alice Frosi Allen Sun +Amen Belayneh +Anca Iordache Anda Xu +Anders F Björklund +Andrea Bolognani +Andrea Luzzardi +Andrew Chang +Andrey Smirnov +Andy Alt +Andy Caldwell +Ankush Agarwal Anthony Sottile +Anurag Goel +Anusha Ragunathan Arnaud Bailly +Avi Deitcher +Bastiaan Bakker +Ben Longo +Bertrand Paquet Bin Liu +Brandon Mitchell Brian Goff +Ce Gao +Chaerim Yeo +Changwei Ge +Chanhun Jeong +ChaosGramer +Charles Chan +Charles Korn +Charles Law +Chenbin +Chris Goller +Chris McKinnel +Christian Höltje +Christian Weichel +Ciro S. Costa +Claudiu Belu +Colin Chartier +Corey Larson +Cory Bennett +Cory Snider +coryb +CrazyMax +Csaba Apagyi +Dan Duvall +Daniel Cassidy Daniel Nephin +Darren Shepherd Dave Chen +Dave Henderson +Dave Tucker David Calavera +David Dooling +David Gageot +David Karlsson +Davis Schirmer Dennis Chen +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Derek McGowan +Dharmit Shah +Ding Fei +dito Doug Davis -Edgar Lee +Edgar Lee Eli Uriegas +Elias Faxö +Eng Zer Jun +Eric Engestrom +Erik Sipsma +eyherabh f0 Fernando Miguel +Fiona Klute +Foysal Iqbal +Fred Cox +Frieder Bluemle +Gabriel +Gabriel Adrian Samfira +Gaetan de Villele +Gahl Saraf +genglu.gl +George +ggjulio +Govind Rai +Grant Reaber +Guilhem C +Hans van den Bogert Hao Hu +Hector S Helen Xie Himanshu Pandey Hiromu Nakamura +HowJMay +Hugo Santos Ian Campbell +Ilya Dmitrichenko Iskander (Alex) Sharipov +Jacob Gillespie +Jacob MacElroy Jean-Pierre Huynh +Jeffrey Huang +Jesse Rittner Jessica Frazelle +jgeiger +Jitender Kumar +jlecordier +joey John Howard +John Maguire +John Mulhausen +John Tims +Jon Zeolla +Jonathan Azoff +Jonathan Giannuzzi Jonathan Stoppani +Jonny Stoten +JordanGoasdoue +jroenf +Julian Goede Justas Brazauskas +Justin Chadwell Justin Cormack +Justin Garrison +Jörg Franke <359489+NewJorg@users.noreply.github.com> +Kang, Matthew +Kees Cook +Kevin Burke +kevinmeredith +Kir Kolyshkin +Kohei Tokunaga +Koichi Shiraishi +Kris-Mikael Krister Kunal Kushwaha +Kyle +l00397676 Lajos Papp +lalyos +Levi Harrison +liwenqi +lixiaobing10051267 +lomot +Lu Jingxiao +Luca Visentin +Maciej Kalisz +Madhav Puri +Manu Gupta +Marcus Comstedt +Mark Gordon +Marko Kohtala +Mary Anthony +masibw +Matias Insaurralde +Matt Kang Matt Rickard +Maxime Lagresle Michael Crosby +Michael Friis +Michael Irwin +Miguel Ángel Jimeno +Mihai Borobocea +Mike Brown +mikelinjie <294893458@qq.com> +Mikhail Vasin +Misty Stanley-Jones Miyachi Katsuya +Morgan Bauer +Morlay +msg Nao YONASHIRO Natasha Jarus +Nathan Sullivan +Nick Miyake +Nick Santos +Nikhil Pandeti Noel Georgi <18496730+frezbo@users.noreply.github.com> +Oliver Bristow +Omer Duchovne <79370724+od-cyera@users.noreply.github.com> +Omer Mizrahi Ondrej Fabry +Otto Kekäläinen +Pablo Chico de Guzman +Patrick Hemmer +Patrick Lang Patrick Van Stee +Paul "TBBle" Hampson +Paweł Gronowski +Peter Dave Hello +Petr Fedchenkov +Phil Estes +Pierre Fenoll +pieterdd +Pranav Pandit +Pratik Raj +Prayag Verma +Qiang Huang +Remy Suen Ri Xu +Rob Taylor +Robert Estelle +Rubens Figueiredo +Sam Whited +Sascha Schwarze +Sean P. Kane Sebastiaan van Stijn +Seiya Miyata +Serhat Gülçiçek +Sertac Ozercan Shev Yan +Shijiang Wei +Shingo Omura +Shiwei Zhang +Siebe Schaap +Silvin Lubecki <31478878+silvin-lubecki@users.noreply.github.com> Simon Ferquel +Slava Semushin +Solomon Hykes +squeegels <1674195+squeegels@users.noreply.github.com> +Stefan Scherer Stefan Weil +StefanSchoof +Stepan Blyshchak +Steve Lohr +sunchunming +Sven Dowideit +Takuya Noguchi Thomas Leonard +Thomas Riccardi Thomas Shaw +Tianon Gravi Tibor Vass Tiffany Jernigan +Tim Waugh +Tim Wraight Tino Rusch Tobias Klauser Tomas Tomecek +Tomasz Kopczynski Tomohiro Kusumoto +Troels Liebe Bentsen Tõnis Tiigi +Valentin Lorentz +Vasek - Tom C +Victor Vieux +Victoria Bialas Vincent Demeester +Vlad A. Ionescu +Vladislav Ivanov +Wang Yumu <37442693@qq.com> Wei Fu +Wei Zhang +wingkwong +Xiaofan Zhang +Ximo Guanter +Yamazaki Masashi +Yan Song Yong Tang Yuichiro Kaneko +Yurii Rashkovskii +Zach Badgett +zhangwenlong Ziv Tsarfati +岁丰 +沈陵 郑泽宇 diff --git a/vendor/github.com/moby/buildkit/api/services/control/control.pb.go b/vendor/github.com/moby/buildkit/api/services/control/control.pb.go index 2567a0d9700a7..3c24ebb5b5ccd 100644 --- a/vendor/github.com/moby/buildkit/api/services/control/control.pb.go +++ b/vendor/github.com/moby/buildkit/api/services/control/control.pb.go @@ -367,21 +367,25 @@ func (m *UsageRecord) GetParents() []string { } type SolveRequest struct { - Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"` - Definition *pb.Definition `protobuf:"bytes,2,opt,name=Definition,proto3" json:"Definition,omitempty"` - Exporter string `protobuf:"bytes,3,opt,name=Exporter,proto3" json:"Exporter,omitempty"` - ExporterAttrs map[string]string `protobuf:"bytes,4,rep,name=ExporterAttrs,proto3" json:"ExporterAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Session string `protobuf:"bytes,5,opt,name=Session,proto3" json:"Session,omitempty"` - Frontend string `protobuf:"bytes,6,opt,name=Frontend,proto3" json:"Frontend,omitempty"` - FrontendAttrs map[string]string `protobuf:"bytes,7,rep,name=FrontendAttrs,proto3" json:"FrontendAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Cache CacheOptions `protobuf:"bytes,8,opt,name=Cache,proto3" json:"Cache"` - Entitlements []github_com_moby_buildkit_util_entitlements.Entitlement `protobuf:"bytes,9,rep,name=Entitlements,proto3,customtype=github.com/moby/buildkit/util/entitlements.Entitlement" json:"Entitlements,omitempty"` - FrontendInputs map[string]*pb.Definition `protobuf:"bytes,10,rep,name=FrontendInputs,proto3" json:"FrontendInputs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Internal bool `protobuf:"varint,11,opt,name=Internal,proto3" json:"Internal,omitempty"` - SourcePolicy *pb1.Policy `protobuf:"bytes,12,opt,name=SourcePolicy,proto3" json:"SourcePolicy,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"` + Definition *pb.Definition `protobuf:"bytes,2,opt,name=Definition,proto3" json:"Definition,omitempty"` + // ExporterDeprecated and ExporterAttrsDeprecated are deprecated in favor + // of the new Exporters. If these fields are set, then they will be + // appended to the Exporters field if Exporters was not explicitly set. + ExporterDeprecated string `protobuf:"bytes,3,opt,name=ExporterDeprecated,proto3" json:"ExporterDeprecated,omitempty"` + ExporterAttrsDeprecated map[string]string `protobuf:"bytes,4,rep,name=ExporterAttrsDeprecated,proto3" json:"ExporterAttrsDeprecated,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Session string `protobuf:"bytes,5,opt,name=Session,proto3" json:"Session,omitempty"` + Frontend string `protobuf:"bytes,6,opt,name=Frontend,proto3" json:"Frontend,omitempty"` + FrontendAttrs map[string]string `protobuf:"bytes,7,rep,name=FrontendAttrs,proto3" json:"FrontendAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Cache CacheOptions `protobuf:"bytes,8,opt,name=Cache,proto3" json:"Cache"` + Entitlements []github_com_moby_buildkit_util_entitlements.Entitlement `protobuf:"bytes,9,rep,name=Entitlements,proto3,customtype=github.com/moby/buildkit/util/entitlements.Entitlement" json:"Entitlements,omitempty"` + FrontendInputs map[string]*pb.Definition `protobuf:"bytes,10,rep,name=FrontendInputs,proto3" json:"FrontendInputs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Internal bool `protobuf:"varint,11,opt,name=Internal,proto3" json:"Internal,omitempty"` + SourcePolicy *pb1.Policy `protobuf:"bytes,12,opt,name=SourcePolicy,proto3" json:"SourcePolicy,omitempty"` + Exporters []*Exporter `protobuf:"bytes,13,rep,name=Exporters,proto3" json:"Exporters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *SolveRequest) Reset() { *m = SolveRequest{} } @@ -431,16 +435,16 @@ func (m *SolveRequest) GetDefinition() *pb.Definition { return nil } -func (m *SolveRequest) GetExporter() string { +func (m *SolveRequest) GetExporterDeprecated() string { if m != nil { - return m.Exporter + return m.ExporterDeprecated } return "" } -func (m *SolveRequest) GetExporterAttrs() map[string]string { +func (m *SolveRequest) GetExporterAttrsDeprecated() map[string]string { if m != nil { - return m.ExporterAttrs + return m.ExporterAttrsDeprecated } return nil } @@ -494,6 +498,13 @@ func (m *SolveRequest) GetSourcePolicy() *pb1.Policy { return nil } +func (m *SolveRequest) GetExporters() []*Exporter { + if m != nil { + return m.Exporters + } + return nil +} + type CacheOptions struct { // ExportRefDeprecated is deprecated in favor or the new Exports since BuildKit v0.4.0. // When ExportRefDeprecated is set, the solver appends @@ -1832,11 +1843,12 @@ func (m *Descriptor) GetAnnotations() map[string]string { } type BuildResultInfo struct { - Result *Descriptor `protobuf:"bytes,1,opt,name=Result,proto3" json:"Result,omitempty"` - Attestations []*Descriptor `protobuf:"bytes,2,rep,name=Attestations,proto3" json:"Attestations,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ResultDeprecated *Descriptor `protobuf:"bytes,1,opt,name=ResultDeprecated,proto3" json:"ResultDeprecated,omitempty"` + Attestations []*Descriptor `protobuf:"bytes,2,rep,name=Attestations,proto3" json:"Attestations,omitempty"` + Results map[int64]*Descriptor `protobuf:"bytes,3,rep,name=Results,proto3" json:"Results,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *BuildResultInfo) Reset() { *m = BuildResultInfo{} } @@ -1872,9 +1884,9 @@ func (m *BuildResultInfo) XXX_DiscardUnknown() { var xxx_messageInfo_BuildResultInfo proto.InternalMessageInfo -func (m *BuildResultInfo) GetResult() *Descriptor { +func (m *BuildResultInfo) GetResultDeprecated() *Descriptor { if m != nil { - return m.Result + return m.ResultDeprecated } return nil } @@ -1886,8 +1898,18 @@ func (m *BuildResultInfo) GetAttestations() []*Descriptor { return nil } +func (m *BuildResultInfo) GetResults() map[int64]*Descriptor { + if m != nil { + return m.Results + } + return nil +} + +// Exporter describes the output exporter type Exporter struct { - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + // Type identifies the exporter + Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + // Attrs specifies exporter configuration Attrs map[string]string `protobuf:"bytes,2,rep,name=Attrs,proto3" json:"Attrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1948,7 +1970,7 @@ func init() { proto.RegisterType((*DiskUsageResponse)(nil), "moby.buildkit.v1.DiskUsageResponse") proto.RegisterType((*UsageRecord)(nil), "moby.buildkit.v1.UsageRecord") proto.RegisterType((*SolveRequest)(nil), "moby.buildkit.v1.SolveRequest") - proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.SolveRequest.ExporterAttrsEntry") + proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.SolveRequest.ExporterAttrsDeprecatedEntry") proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.SolveRequest.FrontendAttrsEntry") proto.RegisterMapType((map[string]*pb.Definition)(nil), "moby.buildkit.v1.SolveRequest.FrontendInputsEntry") proto.RegisterType((*CacheOptions)(nil), "moby.buildkit.v1.CacheOptions") @@ -1979,6 +2001,7 @@ func init() { proto.RegisterType((*Descriptor)(nil), "moby.buildkit.v1.Descriptor") proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.Descriptor.AnnotationsEntry") proto.RegisterType((*BuildResultInfo)(nil), "moby.buildkit.v1.BuildResultInfo") + proto.RegisterMapType((map[int64]*Descriptor)(nil), "moby.buildkit.v1.BuildResultInfo.ResultsEntry") proto.RegisterType((*Exporter)(nil), "moby.buildkit.v1.Exporter") proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.Exporter.AttrsEntry") } @@ -1986,149 +2009,152 @@ func init() { func init() { proto.RegisterFile("control.proto", fileDescriptor_0c5120591600887d) } var fileDescriptor_0c5120591600887d = []byte{ - // 2261 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcd, 0x6e, 0x1b, 0xc9, - 0x11, 0xde, 0x21, 0x25, 0xfe, 0x14, 0x29, 0x59, 0x6a, 0x7b, 0x8d, 0xc9, 0xc4, 0x2b, 0xc9, 0xb3, - 0x76, 0x22, 0x38, 0xf6, 0x50, 0xcb, 0xac, 0x63, 0xaf, 0x9c, 0x38, 0x16, 0x45, 0x66, 0x2d, 0xc7, - 0x82, 0xb5, 0x2d, 0x79, 0x0d, 0x2c, 0xe0, 0x04, 0x23, 0xb2, 0x45, 0x0f, 0x34, 0x9c, 0x99, 0x74, - 0x37, 0xb5, 0xe6, 0x3e, 0x40, 0x80, 0xcd, 0x21, 0xc8, 0x25, 0xc8, 0x25, 0xf7, 0x9c, 0x72, 0xce, - 0x13, 0x04, 0xf0, 0x31, 0xe7, 0x3d, 0x38, 0x81, 0x1f, 0x20, 0xc8, 0x31, 0xb9, 0x05, 0xfd, 0x33, - 0xe4, 0x90, 0x33, 0x94, 0x28, 0xdb, 0x27, 0x76, 0x75, 0xd7, 0x57, 0x53, 0x55, 0x5d, 0x5d, 0x5d, - 0xd5, 0x84, 0x85, 0x76, 0x18, 0x70, 0x1a, 0xfa, 0x4e, 0x44, 0x43, 0x1e, 0xa2, 0xa5, 0x5e, 0x78, - 0x38, 0x70, 0x0e, 0xfb, 0x9e, 0xdf, 0x39, 0xf6, 0xb8, 0x73, 0xf2, 0x89, 0x75, 0xab, 0xeb, 0xf1, - 0x17, 0xfd, 0x43, 0xa7, 0x1d, 0xf6, 0x6a, 0xdd, 0xb0, 0x1b, 0xd6, 0x24, 0xe3, 0x61, 0xff, 0x48, - 0x52, 0x92, 0x90, 0x23, 0x25, 0xc0, 0x5a, 0xed, 0x86, 0x61, 0xd7, 0x27, 0x23, 0x2e, 0xee, 0xf5, - 0x08, 0xe3, 0x6e, 0x2f, 0xd2, 0x0c, 0x37, 0x13, 0xf2, 0xc4, 0xc7, 0x6a, 0xf1, 0xc7, 0x6a, 0x2c, - 0xf4, 0x4f, 0x08, 0xad, 0x45, 0x87, 0xb5, 0x30, 0x62, 0x9a, 0xbb, 0x36, 0x95, 0xdb, 0x8d, 0xbc, - 0x1a, 0x1f, 0x44, 0x84, 0xd5, 0xbe, 0x0e, 0xe9, 0x31, 0xa1, 0x1a, 0x50, 0x9f, 0x54, 0x57, 0xe9, - 0xe3, 0x46, 0x1e, 0xd3, 0xc3, 0x1a, 0x8d, 0xda, 0x35, 0xc6, 0x5d, 0xde, 0x8f, 0x3f, 0x72, 0xfb, - 0x14, 0x95, 0xfa, 0xb4, 0x4d, 0xa2, 0xd0, 0xf7, 0xda, 0x03, 0xa1, 0x98, 0x1a, 0x29, 0x98, 0xfd, - 0x5b, 0x03, 0xaa, 0x7b, 0xb4, 0x1f, 0x10, 0x4c, 0x7e, 0xd3, 0x27, 0x8c, 0xa3, 0xcb, 0x50, 0x38, - 0xf2, 0x7c, 0x4e, 0xa8, 0x69, 0xac, 0xe5, 0xd7, 0xcb, 0x58, 0x53, 0x68, 0x09, 0xf2, 0xae, 0xef, - 0x9b, 0xb9, 0x35, 0x63, 0xbd, 0x84, 0xc5, 0x10, 0xad, 0x43, 0xf5, 0x98, 0x90, 0xa8, 0xd9, 0xa7, - 0x2e, 0xf7, 0xc2, 0xc0, 0xcc, 0xaf, 0x19, 0xeb, 0xf9, 0xc6, 0xdc, 0xab, 0xd7, 0xab, 0x06, 0x1e, - 0x5b, 0x41, 0x36, 0x94, 0x05, 0xdd, 0x18, 0x70, 0xc2, 0xcc, 0xb9, 0x04, 0xdb, 0x68, 0xda, 0xbe, - 0x01, 0x4b, 0x4d, 0x8f, 0x1d, 0x3f, 0x65, 0x6e, 0xf7, 0x2c, 0x5d, 0xec, 0x47, 0xb0, 0x9c, 0xe0, - 0x65, 0x51, 0x18, 0x30, 0x82, 0x6e, 0x43, 0x81, 0x92, 0x76, 0x48, 0x3b, 0x92, 0xb9, 0x52, 0xff, - 0xc8, 0x99, 0x0c, 0x03, 0x47, 0x03, 0x04, 0x13, 0xd6, 0xcc, 0xf6, 0x9f, 0xf2, 0x50, 0x49, 0xcc, - 0xa3, 0x45, 0xc8, 0xed, 0x34, 0x4d, 0x63, 0xcd, 0x58, 0x2f, 0xe3, 0xdc, 0x4e, 0x13, 0x99, 0x50, - 0xdc, 0xed, 0x73, 0xf7, 0xd0, 0x27, 0xda, 0xf6, 0x98, 0x44, 0x97, 0x60, 0x7e, 0x27, 0x78, 0xca, - 0x88, 0x34, 0xbc, 0x84, 0x15, 0x81, 0x10, 0xcc, 0xed, 0x7b, 0xdf, 0x10, 0x65, 0x26, 0x96, 0x63, - 0x64, 0x41, 0x61, 0xcf, 0xa5, 0x24, 0xe0, 0xe6, 0xbc, 0x90, 0xdb, 0xc8, 0x99, 0x06, 0xd6, 0x33, - 0xa8, 0x01, 0xe5, 0x6d, 0x4a, 0x5c, 0x4e, 0x3a, 0x5b, 0xdc, 0x2c, 0xac, 0x19, 0xeb, 0x95, 0xba, - 0xe5, 0xa8, 0x4d, 0x76, 0xe2, 0xf8, 0x73, 0x0e, 0xe2, 0xf8, 0x6b, 0x94, 0x5e, 0xbd, 0x5e, 0xfd, - 0xe0, 0x0f, 0xff, 0x14, 0xbe, 0x1b, 0xc2, 0xd0, 0x03, 0x80, 0xc7, 0x2e, 0xe3, 0x4f, 0x99, 0x14, - 0x52, 0x3c, 0x53, 0xc8, 0x9c, 0x14, 0x90, 0xc0, 0xa0, 0x15, 0x00, 0xe9, 0x84, 0xed, 0xb0, 0x1f, - 0x70, 0xb3, 0x24, 0x75, 0x4f, 0xcc, 0xa0, 0x35, 0xa8, 0x34, 0x09, 0x6b, 0x53, 0x2f, 0x92, 0x5b, - 0x5d, 0x96, 0xee, 0x49, 0x4e, 0x09, 0x09, 0xca, 0x83, 0x07, 0x83, 0x88, 0x98, 0x20, 0x19, 0x12, - 0x33, 0x62, 0x2f, 0xf7, 0x5f, 0xb8, 0x94, 0x74, 0xcc, 0x8a, 0x74, 0x97, 0xa6, 0x84, 0x7f, 0x95, - 0x27, 0x98, 0x59, 0x95, 0x9b, 0x1c, 0x93, 0xf6, 0xef, 0x8a, 0x50, 0xdd, 0x17, 0xc7, 0x29, 0x0e, - 0x87, 0x25, 0xc8, 0x63, 0x72, 0xa4, 0xf7, 0x46, 0x0c, 0x91, 0x03, 0xd0, 0x24, 0x47, 0x5e, 0xe0, - 0x49, 0xad, 0x72, 0xd2, 0xf0, 0x45, 0x27, 0x3a, 0x74, 0x46, 0xb3, 0x38, 0xc1, 0x81, 0x2c, 0x28, - 0xb5, 0x5e, 0x46, 0x21, 0x15, 0x21, 0x95, 0x97, 0x62, 0x86, 0x34, 0x7a, 0x06, 0x0b, 0xf1, 0x78, - 0x8b, 0x73, 0x2a, 0x02, 0x55, 0x84, 0xd1, 0x27, 0xe9, 0x30, 0x4a, 0x2a, 0xe5, 0x8c, 0x61, 0x5a, - 0x01, 0xa7, 0x03, 0x3c, 0x2e, 0x47, 0x58, 0xb8, 0x4f, 0x18, 0x13, 0x1a, 0xca, 0xed, 0xc7, 0x31, - 0x29, 0xd4, 0xf9, 0x05, 0x0d, 0x03, 0x4e, 0x82, 0x8e, 0xdc, 0xfa, 0x32, 0x1e, 0xd2, 0x42, 0x9d, - 0x78, 0xac, 0xd4, 0x29, 0xce, 0xa4, 0xce, 0x18, 0x46, 0xab, 0x33, 0x36, 0x87, 0x36, 0x61, 0x7e, - 0xdb, 0x6d, 0xbf, 0x20, 0x72, 0x97, 0x2b, 0xf5, 0x95, 0xb4, 0x40, 0xb9, 0xfc, 0x44, 0x6e, 0x2b, - 0x93, 0x07, 0xf5, 0x03, 0xac, 0x20, 0xe8, 0x57, 0x50, 0x6d, 0x05, 0xdc, 0xe3, 0x3e, 0xe9, 0xc9, - 0x1d, 0x2b, 0x8b, 0x1d, 0x6b, 0x6c, 0x7e, 0xf7, 0x7a, 0xf5, 0x27, 0x53, 0xd3, 0x4f, 0x9f, 0x7b, - 0x7e, 0x8d, 0x24, 0x50, 0x4e, 0x42, 0x04, 0x1e, 0x93, 0x87, 0xbe, 0x82, 0xc5, 0x58, 0xd9, 0x9d, - 0x20, 0xea, 0x73, 0x66, 0x82, 0xb4, 0xba, 0x3e, 0xa3, 0xd5, 0x0a, 0xa4, 0xcc, 0x9e, 0x90, 0x24, - 0x9c, 0xbd, 0x13, 0x70, 0x42, 0x03, 0xd7, 0xd7, 0x21, 0x38, 0xa4, 0xd1, 0x8e, 0x88, 0x34, 0x91, - 0x25, 0xf7, 0x64, 0x6e, 0x34, 0xab, 0xd2, 0x35, 0xd7, 0xd3, 0x5f, 0x4d, 0xe6, 0x52, 0x47, 0x31, - 0xe3, 0x31, 0xa8, 0xf5, 0x00, 0x50, 0x3a, 0x24, 0x44, 0xe8, 0x1e, 0x93, 0x41, 0x1c, 0xba, 0xc7, - 0x64, 0x20, 0xb2, 0xc7, 0x89, 0xeb, 0xf7, 0x55, 0x56, 0x29, 0x63, 0x45, 0x6c, 0xe6, 0xee, 0x1a, - 0x42, 0x42, 0x7a, 0x17, 0xcf, 0x25, 0xe1, 0x0b, 0xb8, 0x98, 0xe1, 0x91, 0x0c, 0x11, 0xd7, 0x92, - 0x22, 0xd2, 0x47, 0x67, 0x24, 0xd2, 0xfe, 0x6b, 0x1e, 0xaa, 0xc9, 0xb8, 0x40, 0x1b, 0x70, 0x51, - 0xd9, 0x89, 0xc9, 0x51, 0x93, 0x44, 0x94, 0xb4, 0x45, 0x32, 0xd2, 0xc2, 0xb3, 0x96, 0x50, 0x1d, - 0x2e, 0xed, 0xf4, 0xf4, 0x34, 0x4b, 0x40, 0x72, 0xf2, 0xd8, 0x67, 0xae, 0xa1, 0x10, 0x3e, 0x54, - 0xa2, 0xa4, 0x27, 0x12, 0xa0, 0xbc, 0x8c, 0x8b, 0xcf, 0x4e, 0x0f, 0x5e, 0x27, 0x13, 0xab, 0xc2, - 0x23, 0x5b, 0x2e, 0xfa, 0x19, 0x14, 0xd5, 0x42, 0x7c, 0xfe, 0x3f, 0x3e, 0xfd, 0x13, 0x4a, 0x58, - 0x8c, 0x11, 0x70, 0x65, 0x07, 0x33, 0xe7, 0xcf, 0x01, 0xd7, 0x18, 0xeb, 0x21, 0x58, 0xd3, 0x55, - 0x3e, 0x4f, 0x08, 0xd8, 0x7f, 0x31, 0x60, 0x39, 0xf5, 0x21, 0x71, 0x39, 0xc9, 0xf4, 0xac, 0x44, - 0xc8, 0x31, 0x6a, 0xc2, 0xbc, 0x4a, 0x30, 0x39, 0xa9, 0xb0, 0x33, 0x83, 0xc2, 0x4e, 0x22, 0xbb, - 0x28, 0xb0, 0x75, 0x17, 0xe0, 0xed, 0x82, 0xd5, 0xfe, 0x9b, 0x01, 0x0b, 0xfa, 0x30, 0xeb, 0x9b, - 0xdc, 0x85, 0xa5, 0xf8, 0x08, 0xc5, 0x73, 0xfa, 0x4e, 0xbf, 0x3d, 0x35, 0x0f, 0x28, 0x36, 0x67, - 0x12, 0xa7, 0x74, 0x4c, 0x89, 0xb3, 0xb6, 0xe3, 0xb8, 0x9a, 0x60, 0x3d, 0x97, 0xe6, 0x57, 0x61, - 0x61, 0x5f, 0x96, 0x60, 0x53, 0x2f, 0x28, 0xfb, 0x3f, 0x06, 0x2c, 0xc6, 0x3c, 0xda, 0xba, 0x4f, - 0xa1, 0x74, 0x42, 0x28, 0x27, 0x2f, 0x09, 0xd3, 0x56, 0x99, 0x69, 0xab, 0xbe, 0x94, 0x1c, 0x78, - 0xc8, 0x89, 0x36, 0xa1, 0xa4, 0xca, 0x3d, 0x12, 0x6f, 0xd4, 0xca, 0x34, 0x94, 0xfe, 0xde, 0x90, - 0x1f, 0xd5, 0x60, 0xce, 0x0f, 0xbb, 0x4c, 0x9f, 0x99, 0xef, 0x4f, 0xc3, 0x3d, 0x0e, 0xbb, 0x58, - 0x32, 0xa2, 0x7b, 0x50, 0xfa, 0xda, 0xa5, 0x81, 0x17, 0x74, 0xe3, 0x53, 0xb0, 0x3a, 0x0d, 0xf4, - 0x4c, 0xf1, 0xe1, 0x21, 0x40, 0x14, 0x54, 0x05, 0xb5, 0x86, 0x1e, 0x41, 0xa1, 0xe3, 0x75, 0x09, - 0xe3, 0xca, 0x25, 0x8d, 0xba, 0xb8, 0x4b, 0xbe, 0x7b, 0xbd, 0x7a, 0x23, 0x71, 0x59, 0x84, 0x11, - 0x09, 0x44, 0xf9, 0xee, 0x7a, 0x01, 0xa1, 0xa2, 0xbc, 0xbd, 0xa5, 0x20, 0x4e, 0x53, 0xfe, 0x60, - 0x2d, 0x41, 0xc8, 0xf2, 0xd4, 0x95, 0x20, 0xf3, 0xc5, 0xdb, 0xc9, 0x52, 0x12, 0xc4, 0x31, 0x08, - 0xdc, 0x1e, 0xd1, 0x25, 0x80, 0x1c, 0x8b, 0xfa, 0xa4, 0x2d, 0xe2, 0xbc, 0x23, 0x2b, 0xb7, 0x12, - 0xd6, 0x14, 0xda, 0x84, 0x22, 0xe3, 0x2e, 0x15, 0x39, 0x67, 0x7e, 0xc6, 0xc2, 0x2a, 0x06, 0xa0, - 0xfb, 0x50, 0x6e, 0x87, 0xbd, 0xc8, 0x27, 0x02, 0x5d, 0x98, 0x11, 0x3d, 0x82, 0x88, 0xd0, 0x23, - 0x94, 0x86, 0x54, 0x96, 0x74, 0x65, 0xac, 0x08, 0x74, 0x07, 0x16, 0x22, 0x1a, 0x76, 0x29, 0x61, - 0xec, 0x73, 0x1a, 0xf6, 0x23, 0x7d, 0x91, 0x2f, 0x8b, 0xe4, 0xbd, 0x97, 0x5c, 0xc0, 0xe3, 0x7c, - 0xf6, 0xbf, 0x73, 0x50, 0x4d, 0x86, 0x48, 0xaa, 0xd6, 0x7d, 0x04, 0x05, 0x15, 0x70, 0x2a, 0xd6, - 0xdf, 0xce, 0xc7, 0x4a, 0x42, 0xa6, 0x8f, 0x4d, 0x28, 0xb6, 0xfb, 0x54, 0x16, 0xc2, 0xaa, 0x3c, - 0x8e, 0x49, 0x61, 0x29, 0x0f, 0xb9, 0xeb, 0x4b, 0x1f, 0xe7, 0xb1, 0x22, 0x44, 0x6d, 0x3c, 0xec, - 0xbc, 0xce, 0x57, 0x1b, 0x0f, 0x61, 0xc9, 0xfd, 0x2b, 0xbe, 0xd3, 0xfe, 0x95, 0xce, 0xbd, 0x7f, - 0xf6, 0xdf, 0x0d, 0x28, 0x0f, 0xcf, 0x56, 0xc2, 0xbb, 0xc6, 0x3b, 0x7b, 0x77, 0xcc, 0x33, 0xb9, - 0xb7, 0xf3, 0xcc, 0x65, 0x28, 0x30, 0x4e, 0x89, 0xdb, 0x53, 0x9d, 0x1b, 0xd6, 0x94, 0xc8, 0x62, - 0x3d, 0xd6, 0x95, 0x3b, 0x54, 0xc5, 0x62, 0x68, 0xff, 0xd7, 0x80, 0x85, 0xb1, 0xe3, 0xfe, 0x5e, - 0x6d, 0xb9, 0x04, 0xf3, 0x3e, 0x39, 0x21, 0xaa, 0xb7, 0xcc, 0x63, 0x45, 0x88, 0x59, 0xf6, 0x22, - 0xa4, 0x5c, 0x2a, 0x57, 0xc5, 0x8a, 0x10, 0x3a, 0x77, 0x08, 0x77, 0x3d, 0x5f, 0xe6, 0xa5, 0x2a, - 0xd6, 0x94, 0xd0, 0xb9, 0x4f, 0x7d, 0x5d, 0x5f, 0x8b, 0x21, 0xb2, 0x61, 0xce, 0x0b, 0x8e, 0x42, - 0x1d, 0x36, 0xb2, 0xb2, 0x51, 0x75, 0xda, 0x4e, 0x70, 0x14, 0x62, 0xb9, 0x86, 0xae, 0x42, 0x81, - 0xba, 0x41, 0x97, 0xc4, 0xc5, 0x75, 0x59, 0x70, 0x61, 0x31, 0x83, 0xf5, 0x82, 0x6d, 0x43, 0x55, - 0xf6, 0xa7, 0xbb, 0x84, 0x89, 0x6e, 0x48, 0x84, 0x75, 0xc7, 0xe5, 0xae, 0x34, 0xbb, 0x8a, 0xe5, - 0xd8, 0xbe, 0x09, 0xe8, 0xb1, 0xc7, 0xf8, 0x33, 0xd9, 0xc2, 0xb3, 0xb3, 0x9a, 0xd7, 0x7d, 0xb8, - 0x38, 0xc6, 0xad, 0xaf, 0x85, 0x9f, 0x4e, 0xb4, 0xaf, 0xd7, 0xd2, 0x19, 0x57, 0xbe, 0x14, 0x38, - 0x0a, 0x38, 0xd1, 0xc5, 0x2e, 0x40, 0x45, 0xda, 0xa5, 0xbe, 0x6d, 0xbb, 0x50, 0x55, 0xa4, 0x16, - 0xfe, 0x05, 0x5c, 0x88, 0x05, 0x7d, 0x49, 0xa8, 0x6c, 0x45, 0x0c, 0xe9, 0x97, 0x1f, 0x4e, 0xfb, - 0x4a, 0x63, 0x9c, 0x1d, 0x4f, 0xe2, 0x6d, 0x02, 0x17, 0x25, 0xcf, 0x43, 0x8f, 0xf1, 0x90, 0x0e, - 0x62, 0xab, 0x57, 0x00, 0xb6, 0xda, 0xdc, 0x3b, 0x21, 0x4f, 0x02, 0x5f, 0x5d, 0xa3, 0x25, 0x9c, - 0x98, 0x89, 0xaf, 0xc8, 0xdc, 0xa8, 0x87, 0xbb, 0x02, 0xe5, 0x96, 0x4b, 0xfd, 0x41, 0xeb, 0xa5, - 0xc7, 0x75, 0x2b, 0x3d, 0x9a, 0xb0, 0x7f, 0x6f, 0xc0, 0x72, 0xf2, 0x3b, 0xad, 0x13, 0x91, 0x2e, - 0xee, 0xc1, 0x1c, 0x8f, 0xeb, 0x98, 0xc5, 0x2c, 0x23, 0x52, 0x10, 0x51, 0xea, 0x60, 0x09, 0x4a, - 0x78, 0x5a, 0x1d, 0x9c, 0x6b, 0xa7, 0xc3, 0x27, 0x3c, 0xfd, 0xbf, 0x12, 0xa0, 0xf4, 0x72, 0x46, - 0x6f, 0x9a, 0x6c, 0xee, 0x72, 0x13, 0xcd, 0xdd, 0xf3, 0xc9, 0xe6, 0x4e, 0x5d, 0xcd, 0x77, 0x66, - 0xd1, 0x64, 0x86, 0x16, 0xef, 0x2e, 0x94, 0xe3, 0xea, 0x26, 0xbe, 0xc0, 0xad, 0xb4, 0xe8, 0x61, - 0x01, 0x34, 0x62, 0x46, 0xeb, 0xf1, 0x8d, 0xa3, 0xee, 0x3a, 0x14, 0xe7, 0x14, 0x1a, 0xb5, 0x1d, - 0x5d, 0x57, 0xe8, 0x5b, 0xe8, 0xfe, 0xf9, 0xde, 0x2d, 0xe6, 0x26, 0xdf, 0x2c, 0x1a, 0x50, 0xd9, - 0x8e, 0x13, 0xe5, 0x39, 0x1e, 0x2d, 0x92, 0x20, 0xb4, 0xa1, 0x0b, 0x1b, 0x95, 0x9a, 0xaf, 0xa4, - 0x4d, 0x8c, 0x1f, 0x28, 0x42, 0xaa, 0x2b, 0x9b, 0xa3, 0x8c, 0xd2, 0xb2, 0x2c, 0x1d, 0xb4, 0x39, - 0x93, 0xef, 0x67, 0xac, 0x2f, 0xd1, 0x67, 0x50, 0xc0, 0x84, 0xf5, 0x7d, 0x2e, 0x5f, 0x42, 0x2a, - 0xf5, 0xab, 0x53, 0xa4, 0x2b, 0x26, 0x79, 0x56, 0x35, 0x00, 0xfd, 0x12, 0x8a, 0x6a, 0xc4, 0xcc, - 0xca, 0xb4, 0x96, 0x3f, 0x43, 0x33, 0x8d, 0xd1, 0x0d, 0x85, 0xa6, 0xc4, 0x71, 0xfc, 0x9c, 0x04, - 0x44, 0xbf, 0xd0, 0x89, 0xb6, 0x76, 0x1e, 0x27, 0x66, 0x50, 0x1d, 0xe6, 0x39, 0x75, 0xdb, 0xc4, - 0x5c, 0x98, 0xc1, 0x85, 0x8a, 0x55, 0x24, 0xb6, 0xc8, 0x0b, 0x02, 0xd2, 0x31, 0x17, 0x55, 0xa5, - 0xa4, 0x28, 0xf4, 0x03, 0x58, 0x0c, 0xfa, 0x3d, 0xd9, 0x2c, 0x74, 0xf6, 0x39, 0x89, 0x98, 0x79, - 0x41, 0x7e, 0x6f, 0x62, 0x16, 0x5d, 0x83, 0x85, 0xa0, 0xdf, 0x3b, 0x10, 0x37, 0xbc, 0x62, 0x5b, - 0x92, 0x6c, 0xe3, 0x93, 0xe8, 0x26, 0x2c, 0x0b, 0x5c, 0xbc, 0xdb, 0x8a, 0x73, 0x59, 0x72, 0xa6, - 0x17, 0xde, 0x43, 0xcf, 0xfc, 0x3e, 0x3a, 0x02, 0xeb, 0x39, 0x54, 0x93, 0xfb, 0x90, 0x81, 0xbd, - 0x33, 0xde, 0x71, 0xcf, 0x10, 0x17, 0x89, 0x86, 0xe3, 0x39, 0x7c, 0xef, 0x69, 0xd4, 0x71, 0x39, - 0xc9, 0xca, 0xbc, 0xe9, 0x0c, 0x74, 0x19, 0x0a, 0x7b, 0x6a, 0xa3, 0xd4, 0xcb, 0xa5, 0xa6, 0xc4, - 0x7c, 0x93, 0x08, 0xe7, 0xe9, 0x74, 0xab, 0x29, 0xfb, 0x0a, 0x58, 0x59, 0xe2, 0x95, 0x33, 0xec, - 0x3f, 0xe7, 0x00, 0x46, 0xc1, 0x80, 0x3e, 0x02, 0xe8, 0x91, 0x8e, 0xe7, 0xfe, 0x9a, 0x8f, 0x1a, - 0xca, 0xb2, 0x9c, 0x91, 0x5d, 0xe5, 0xa8, 0xf4, 0xcf, 0xbd, 0x73, 0xe9, 0x8f, 0x60, 0x8e, 0x79, - 0xdf, 0x10, 0x5d, 0xa6, 0xc8, 0x31, 0x7a, 0x02, 0x15, 0x37, 0x08, 0x42, 0x2e, 0xc3, 0x38, 0x6e, - 0xb6, 0x6f, 0x9d, 0x16, 0xbe, 0xce, 0xd6, 0x88, 0x5f, 0x9d, 0x92, 0xa4, 0x04, 0xeb, 0x3e, 0x2c, - 0x4d, 0x32, 0x9c, 0xab, 0x19, 0xfc, 0xd6, 0x80, 0x0b, 0x13, 0x5b, 0x87, 0x3e, 0x1d, 0x66, 0x01, - 0x63, 0x86, 0xe3, 0x15, 0x27, 0x80, 0x07, 0x50, 0xdd, 0xe2, 0x5c, 0x64, 0x3d, 0x65, 0x9b, 0x6a, - 0xf7, 0x4e, 0xc7, 0x8e, 0x21, 0xec, 0x3f, 0x1a, 0xa3, 0x77, 0xce, 0xcc, 0x9e, 0xff, 0xde, 0x78, - 0xcf, 0x7f, 0x7d, 0xfa, 0xe5, 0xf0, 0x3e, 0x5b, 0xfd, 0x1b, 0x3f, 0x87, 0x0f, 0x33, 0x2f, 0x66, - 0x54, 0x81, 0xe2, 0xfe, 0xc1, 0x16, 0x3e, 0x68, 0x35, 0x97, 0x3e, 0x40, 0x55, 0x28, 0x6d, 0x3f, - 0xd9, 0xdd, 0x7b, 0xdc, 0x3a, 0x68, 0x2d, 0x19, 0x62, 0xa9, 0xd9, 0x12, 0xe3, 0xe6, 0x52, 0xae, - 0xfe, 0x6d, 0x01, 0x8a, 0xdb, 0xea, 0xbf, 0x1e, 0x74, 0x00, 0xe5, 0xe1, 0x9f, 0x00, 0xc8, 0xce, - 0xf0, 0xce, 0xc4, 0xbf, 0x09, 0xd6, 0xc7, 0xa7, 0xf2, 0xe8, 0xc4, 0xfd, 0x10, 0xe6, 0xe5, 0xdf, - 0x21, 0x28, 0xa3, 0xbd, 0x4e, 0xfe, 0x4f, 0x62, 0x9d, 0xfe, 0xf7, 0xc2, 0x86, 0x21, 0x24, 0xc9, - 0xb7, 0x89, 0x2c, 0x49, 0xc9, 0xc7, 0x4b, 0x6b, 0xf5, 0x8c, 0x47, 0x0d, 0xb4, 0x0b, 0x05, 0xdd, - 0xb0, 0x65, 0xb1, 0x26, 0x5f, 0x20, 0xac, 0xb5, 0xe9, 0x0c, 0x4a, 0xd8, 0x86, 0x81, 0x76, 0x87, - 0xef, 0xd1, 0x59, 0xaa, 0x25, 0xab, 0x5d, 0xeb, 0x8c, 0xf5, 0x75, 0x63, 0xc3, 0x40, 0x5f, 0x41, - 0x25, 0x51, 0xcf, 0xa2, 0x8c, 0x6a, 0x2a, 0x5d, 0x1c, 0x5b, 0xd7, 0xcf, 0xe0, 0xd2, 0x96, 0xb7, - 0x60, 0x4e, 0x1e, 0xa4, 0x0c, 0x67, 0x27, 0xca, 0xdd, 0x2c, 0x35, 0xc7, 0xca, 0xdf, 0x43, 0x55, - 0xa0, 0x93, 0x20, 0x19, 0x7d, 0xe8, 0xfa, 0x59, 0xf7, 0xea, 0xd4, 0xb0, 0x49, 0x05, 0xf1, 0x86, - 0x81, 0x42, 0x40, 0xe9, 0xe4, 0x89, 0x7e, 0x94, 0x11, 0x25, 0xd3, 0x32, 0xb8, 0x75, 0x73, 0x36, - 0x66, 0x65, 0x54, 0xa3, 0xfa, 0xea, 0xcd, 0x8a, 0xf1, 0x8f, 0x37, 0x2b, 0xc6, 0xbf, 0xde, 0xac, - 0x18, 0x87, 0x05, 0x59, 0x31, 0xfd, 0xf8, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7c, 0xb8, 0xc3, - 0x68, 0x0b, 0x1d, 0x00, 0x00, + // 2315 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x4f, 0x73, 0x1b, 0x49, + 0x15, 0xcf, 0x48, 0xb2, 0x2c, 0x3d, 0xc9, 0x8e, 0xdc, 0xc9, 0x86, 0x61, 0xc8, 0xda, 0xce, 0x6c, + 0x02, 0xae, 0x90, 0x8c, 0xbc, 0x82, 0x90, 0xac, 0x03, 0x21, 0xb6, 0x25, 0x36, 0x0e, 0x49, 0xc5, + 0xdb, 0x76, 0x36, 0xd4, 0x56, 0x05, 0x6a, 0x2c, 0xb5, 0x95, 0x29, 0x8f, 0x66, 0x86, 0xee, 0x96, + 0x37, 0xde, 0x13, 0x27, 0xaa, 0xb8, 0x50, 0x5c, 0x28, 0x2e, 0xdc, 0x39, 0x71, 0xe6, 0xcc, 0x81, + 0xaa, 0x1c, 0x39, 0xef, 0x21, 0x50, 0xf9, 0x00, 0x14, 0x47, 0xb8, 0x6d, 0xf5, 0x9f, 0x91, 0x46, + 0x9a, 0x91, 0x2d, 0x25, 0x39, 0xa9, 0x5f, 0xf7, 0xfb, 0xbd, 0x79, 0xef, 0xf5, 0xeb, 0xd7, 0xef, + 0xb5, 0x60, 0xa1, 0x1d, 0x06, 0x9c, 0x86, 0xbe, 0x13, 0xd1, 0x90, 0x87, 0xa8, 0xd6, 0x0b, 0x0f, + 0x4e, 0x9c, 0x83, 0xbe, 0xe7, 0x77, 0x8e, 0x3c, 0xee, 0x1c, 0x7f, 0x6c, 0x35, 0xba, 0x1e, 0x7f, + 0xd1, 0x3f, 0x70, 0xda, 0x61, 0xaf, 0xde, 0x0d, 0xbb, 0x61, 0xbd, 0x1b, 0x86, 0x5d, 0x9f, 0xb8, + 0x91, 0xc7, 0xf4, 0xb0, 0x4e, 0xa3, 0x76, 0x9d, 0x71, 0x97, 0xf7, 0x99, 0x92, 0x62, 0xdd, 0x1c, + 0xc7, 0xc8, 0xe9, 0x83, 0xfe, 0xa1, 0xa4, 0x24, 0x21, 0x47, 0x9a, 0xbd, 0x9e, 0x60, 0x17, 0xdf, + 0xaf, 0xc7, 0xdf, 0xaf, 0xbb, 0x91, 0x57, 0xe7, 0x27, 0x11, 0x61, 0xf5, 0x2f, 0x43, 0x7a, 0x44, + 0xa8, 0x06, 0xdc, 0x98, 0x08, 0x60, 0xa1, 0x7f, 0x4c, 0x68, 0x3d, 0x3a, 0xa8, 0x87, 0x51, 0xac, + 0xcd, 0xad, 0x53, 0xb8, 0xfb, 0xb4, 0x4d, 0xa2, 0xd0, 0xf7, 0xda, 0x27, 0x02, 0xa3, 0x46, 0x1a, + 0xb6, 0xa2, 0xad, 0x1b, 0xe8, 0xce, 0xbd, 0x1e, 0x61, 0xdc, 0xed, 0x45, 0x8a, 0xc1, 0xfe, 0xad, + 0x01, 0xd5, 0x5d, 0xda, 0x0f, 0x08, 0x26, 0xbf, 0xee, 0x13, 0xc6, 0xd1, 0x25, 0x28, 0x1e, 0x7a, + 0x3e, 0x27, 0xd4, 0x34, 0x56, 0xf3, 0x6b, 0x65, 0xac, 0x29, 0x54, 0x83, 0xbc, 0xeb, 0xfb, 0x66, + 0x6e, 0xd5, 0x58, 0x2b, 0x61, 0x31, 0x44, 0x6b, 0x50, 0x3d, 0x22, 0x24, 0x6a, 0xf6, 0xa9, 0xcb, + 0xbd, 0x30, 0x30, 0xf3, 0xab, 0xc6, 0x5a, 0x7e, 0xab, 0xf0, 0xea, 0xf5, 0x8a, 0x81, 0x47, 0x56, + 0x90, 0x0d, 0x65, 0x41, 0x6f, 0x9d, 0x70, 0xc2, 0xcc, 0x42, 0x82, 0x6d, 0x38, 0x6d, 0x5f, 0x87, + 0x5a, 0xd3, 0x63, 0x47, 0x4f, 0x99, 0xdb, 0x3d, 0x4b, 0x17, 0xfb, 0x21, 0x2c, 0x25, 0x78, 0x59, + 0x14, 0x06, 0x8c, 0xa0, 0x5b, 0x50, 0xa4, 0xa4, 0x1d, 0xd2, 0x8e, 0x64, 0xae, 0x34, 0x3e, 0x74, + 0xc6, 0xc3, 0xc0, 0xd1, 0x00, 0xc1, 0x84, 0x35, 0xb3, 0xfd, 0xa7, 0x3c, 0x54, 0x12, 0xf3, 0x68, + 0x11, 0x72, 0x3b, 0x4d, 0xd3, 0x58, 0x35, 0xd6, 0xca, 0x38, 0xb7, 0xd3, 0x44, 0x26, 0xcc, 0x3f, + 0xee, 0x73, 0xf7, 0xc0, 0x27, 0xda, 0xf6, 0x98, 0x44, 0x17, 0x61, 0x6e, 0x27, 0x78, 0xca, 0x88, + 0x34, 0xbc, 0x84, 0x15, 0x81, 0x10, 0x14, 0xf6, 0xbc, 0xaf, 0x88, 0x32, 0x13, 0xcb, 0x31, 0xb2, + 0xa0, 0xb8, 0xeb, 0x52, 0x12, 0x70, 0x73, 0x4e, 0xc8, 0xdd, 0xca, 0x99, 0x06, 0xd6, 0x33, 0x68, + 0x0b, 0xca, 0xdb, 0x94, 0xb8, 0x9c, 0x74, 0x36, 0xb9, 0x59, 0x5c, 0x35, 0xd6, 0x2a, 0x0d, 0xcb, + 0x51, 0xbb, 0xe6, 0xc4, 0xbb, 0xe6, 0xec, 0xc7, 0xbb, 0xb6, 0x55, 0x7a, 0xf5, 0x7a, 0xe5, 0xdc, + 0x1f, 0xfe, 0x25, 0x7c, 0x37, 0x80, 0xa1, 0xfb, 0x00, 0x8f, 0x5c, 0xc6, 0x9f, 0x32, 0x29, 0x64, + 0xfe, 0x4c, 0x21, 0x05, 0x29, 0x20, 0x81, 0x41, 0xcb, 0x00, 0xd2, 0x09, 0xdb, 0x61, 0x3f, 0xe0, + 0x66, 0x49, 0xea, 0x9e, 0x98, 0x41, 0xab, 0x50, 0x69, 0x12, 0xd6, 0xa6, 0x5e, 0x24, 0xb7, 0xba, + 0x2c, 0xdd, 0x93, 0x9c, 0x12, 0x12, 0x94, 0x07, 0xf7, 0x4f, 0x22, 0x62, 0x82, 0x64, 0x48, 0xcc, + 0x88, 0xbd, 0xdc, 0x7b, 0xe1, 0x52, 0xd2, 0x31, 0x2b, 0xd2, 0x5d, 0x9a, 0x12, 0xfe, 0x55, 0x9e, + 0x60, 0x66, 0x55, 0x6e, 0x72, 0x4c, 0xda, 0xbf, 0x29, 0x41, 0x75, 0x4f, 0x1c, 0x85, 0x38, 0x1c, + 0x6a, 0x90, 0xc7, 0xe4, 0x50, 0xef, 0x8d, 0x18, 0x22, 0x07, 0xa0, 0x49, 0x0e, 0xbd, 0xc0, 0x93, + 0x5a, 0xe5, 0xa4, 0xe1, 0x8b, 0x4e, 0x74, 0xe0, 0x0c, 0x67, 0x71, 0x82, 0x03, 0x39, 0x80, 0x5a, + 0x2f, 0xa3, 0x90, 0x72, 0x42, 0x9b, 0x24, 0xa2, 0xa4, 0x2d, 0x1c, 0x28, 0xf7, 0xaf, 0x8c, 0x33, + 0x56, 0x50, 0x1f, 0xbe, 0x15, 0xcf, 0x6e, 0x72, 0x4e, 0x59, 0x02, 0x54, 0x90, 0x41, 0x76, 0x37, + 0x1d, 0x64, 0x49, 0x95, 0x9d, 0x09, 0xe8, 0x56, 0xc0, 0xe9, 0x09, 0x9e, 0x24, 0x5b, 0xf8, 0x64, + 0x8f, 0x30, 0x26, 0x6c, 0x92, 0x01, 0x83, 0x63, 0x12, 0x59, 0x50, 0xfa, 0x19, 0x0d, 0x03, 0x4e, + 0x82, 0x8e, 0x0c, 0x96, 0x32, 0x1e, 0xd0, 0xe8, 0x19, 0x2c, 0xc4, 0x63, 0x29, 0xd0, 0x9c, 0x97, + 0x2a, 0x7e, 0x7c, 0x86, 0x8a, 0x23, 0x18, 0xa5, 0xd8, 0xa8, 0x1c, 0xb4, 0x01, 0x73, 0xdb, 0x6e, + 0xfb, 0x05, 0x91, 0x71, 0x51, 0x69, 0x2c, 0xa7, 0x05, 0xca, 0xe5, 0x27, 0x32, 0x10, 0x98, 0x3c, + 0xda, 0xe7, 0xb0, 0x82, 0xa0, 0x5f, 0x42, 0xb5, 0x15, 0x70, 0x8f, 0xfb, 0xa4, 0x27, 0xf7, 0xb8, + 0x2c, 0xf6, 0x78, 0x6b, 0xe3, 0xeb, 0xd7, 0x2b, 0x3f, 0x9a, 0x98, 0xd1, 0xfa, 0xdc, 0xf3, 0xeb, + 0x24, 0x81, 0x72, 0x12, 0x22, 0xf0, 0x88, 0x3c, 0xf4, 0x05, 0x2c, 0xc6, 0xca, 0xee, 0x04, 0x51, + 0x9f, 0x33, 0x13, 0xa4, 0xd5, 0x8d, 0x29, 0xad, 0x56, 0x20, 0x65, 0xf6, 0x98, 0x24, 0xe1, 0xec, + 0x9d, 0x80, 0x13, 0x1a, 0xb8, 0xbe, 0x0e, 0xda, 0x01, 0x8d, 0x76, 0x44, 0x6c, 0x8a, 0xc4, 0xbb, + 0x2b, 0xd3, 0xad, 0x59, 0x95, 0xae, 0xb9, 0x96, 0xfe, 0x6a, 0x32, 0x3d, 0x3b, 0x8a, 0x19, 0x8f, + 0x40, 0xd1, 0x1d, 0x28, 0xc7, 0x81, 0xc0, 0xcc, 0x05, 0xa9, 0xbd, 0x95, 0x96, 0x13, 0xb3, 0xe0, + 0x21, 0xb3, 0xf5, 0x10, 0x2e, 0x9f, 0x16, 0x60, 0xe2, 0xc0, 0x1c, 0x91, 0x93, 0xf8, 0xc0, 0x1c, + 0x91, 0x13, 0x91, 0xb3, 0x8e, 0x5d, 0xbf, 0xaf, 0x72, 0x59, 0x19, 0x2b, 0x62, 0x23, 0x77, 0xc7, + 0xb0, 0xee, 0x03, 0x4a, 0x47, 0xc2, 0x4c, 0x12, 0x3e, 0x83, 0x0b, 0x19, 0x5e, 0xcd, 0x10, 0x71, + 0x35, 0x29, 0x22, 0x7d, 0x60, 0x87, 0x22, 0xed, 0xbf, 0xe6, 0xa1, 0x9a, 0x8c, 0x2d, 0xb4, 0x0e, + 0x17, 0x94, 0xc5, 0x98, 0x1c, 0x26, 0x0e, 0xa3, 0x12, 0x9e, 0xb5, 0x84, 0x1a, 0x70, 0x71, 0xa7, + 0xa7, 0xa7, 0x93, 0xe7, 0x37, 0x27, 0x93, 0x4d, 0xe6, 0x1a, 0x0a, 0xe1, 0x03, 0x25, 0x6a, 0xfc, + 0xd0, 0xe7, 0xe5, 0xee, 0x7c, 0x72, 0xfa, 0x01, 0x70, 0x32, 0xb1, 0x2a, 0xc4, 0xb2, 0xe5, 0xa2, + 0x9f, 0xc0, 0xbc, 0x5a, 0x60, 0x3a, 0xaf, 0x7c, 0x74, 0xfa, 0x27, 0x94, 0xb0, 0x18, 0x23, 0xe0, + 0xca, 0x0e, 0x66, 0xce, 0xcd, 0x00, 0xd7, 0x18, 0xeb, 0x01, 0x58, 0x93, 0x55, 0x9e, 0x25, 0x04, + 0xec, 0xbf, 0x18, 0xb0, 0x94, 0xfa, 0x90, 0xb8, 0x12, 0xe5, 0xa5, 0xa0, 0x44, 0xc8, 0x31, 0x6a, + 0xc2, 0x9c, 0x4a, 0x52, 0x39, 0xa9, 0xb0, 0x33, 0x85, 0xc2, 0x4e, 0x22, 0x43, 0x29, 0xb0, 0x75, + 0x07, 0xe0, 0xed, 0x82, 0xd5, 0xfe, 0x9b, 0x01, 0x0b, 0x3a, 0x21, 0xe8, 0xfa, 0xc1, 0x85, 0xda, + 0xe0, 0x8c, 0xe9, 0x39, 0x5d, 0x49, 0xdc, 0x9a, 0x98, 0x4b, 0x14, 0x9b, 0x33, 0x8e, 0x53, 0x3a, + 0xa6, 0xc4, 0x59, 0xdb, 0x71, 0x5c, 0x8d, 0xb1, 0xce, 0xa4, 0xf9, 0x15, 0x58, 0xd8, 0x93, 0x75, + 0xea, 0xc4, 0x6b, 0xd1, 0xfe, 0xaf, 0x01, 0x8b, 0x31, 0x8f, 0xb6, 0xee, 0x87, 0x50, 0x3a, 0x26, + 0x94, 0x93, 0x97, 0x84, 0x69, 0xab, 0xcc, 0xb4, 0x55, 0x9f, 0x4b, 0x0e, 0x3c, 0xe0, 0x44, 0x1b, + 0x50, 0x52, 0x35, 0x31, 0x89, 0x37, 0x6a, 0x79, 0x12, 0x4a, 0x7f, 0x6f, 0xc0, 0x8f, 0xea, 0x50, + 0xf0, 0xc3, 0x2e, 0xd3, 0x67, 0xe6, 0x3b, 0x93, 0x70, 0x8f, 0xc2, 0x2e, 0x96, 0x8c, 0xe8, 0x2e, + 0x94, 0xbe, 0x74, 0x69, 0xe0, 0x05, 0xdd, 0xf8, 0x14, 0xac, 0x4c, 0x02, 0x3d, 0x53, 0x7c, 0x78, + 0x00, 0x10, 0x65, 0x5c, 0x51, 0xad, 0xa1, 0x87, 0x50, 0xec, 0x78, 0x5d, 0xc2, 0xb8, 0x72, 0xc9, + 0x56, 0x43, 0xdc, 0x47, 0x5f, 0xbf, 0x5e, 0xb9, 0x9e, 0xb8, 0x70, 0xc2, 0x88, 0x04, 0xa2, 0x69, + 0x70, 0xbd, 0x80, 0x50, 0xd1, 0x03, 0xdc, 0x54, 0x10, 0xa7, 0x29, 0x7f, 0xb0, 0x96, 0x20, 0x64, + 0x79, 0xea, 0x5a, 0x91, 0xf9, 0xe2, 0xed, 0x64, 0x29, 0x09, 0xe2, 0x18, 0x04, 0x6e, 0x8f, 0xe8, + 0x72, 0x43, 0x8e, 0x45, 0x55, 0xd4, 0x16, 0x71, 0xde, 0x91, 0xf5, 0x62, 0x09, 0x6b, 0x0a, 0x6d, + 0xc0, 0x3c, 0xe3, 0x2e, 0x15, 0x39, 0x67, 0x6e, 0xca, 0x72, 0x2e, 0x06, 0xa0, 0x7b, 0x50, 0x6e, + 0x87, 0xbd, 0xc8, 0x27, 0x02, 0x5d, 0x9c, 0x12, 0x3d, 0x84, 0x88, 0xd0, 0x23, 0x94, 0x86, 0x54, + 0x16, 0x92, 0x65, 0xac, 0x08, 0x74, 0x1b, 0x16, 0x22, 0x1a, 0x76, 0x29, 0x61, 0xec, 0x53, 0x1a, + 0xf6, 0x23, 0x5d, 0x0c, 0x2c, 0x89, 0xe4, 0xbd, 0x9b, 0x5c, 0xc0, 0xa3, 0x7c, 0xf6, 0x7f, 0x72, + 0x50, 0x4d, 0x86, 0x48, 0xaa, 0xc2, 0x7e, 0x08, 0x45, 0x15, 0x70, 0x2a, 0xd6, 0xdf, 0xce, 0xc7, + 0x4a, 0x42, 0xa6, 0x8f, 0x4d, 0x98, 0x6f, 0xf7, 0xa9, 0x2c, 0xbf, 0x55, 0x51, 0x1e, 0x93, 0xc2, + 0x52, 0x1e, 0x72, 0xd7, 0x97, 0x3e, 0xce, 0x63, 0x45, 0x88, 0x8a, 0x7c, 0xd0, 0x25, 0xcd, 0x56, + 0x91, 0x0f, 0x60, 0xc9, 0xfd, 0x9b, 0x7f, 0xa7, 0xfd, 0x2b, 0xcd, 0xbc, 0x7f, 0xf6, 0x3f, 0x0c, + 0x28, 0x0f, 0xce, 0x56, 0xc2, 0xbb, 0xc6, 0x3b, 0x7b, 0x77, 0xc4, 0x33, 0xb9, 0xb7, 0xf3, 0xcc, + 0x25, 0x28, 0x32, 0x4e, 0x89, 0xdb, 0x53, 0xfd, 0x22, 0xd6, 0x94, 0xc8, 0x62, 0x3d, 0xd6, 0x95, + 0x3b, 0x54, 0xc5, 0x62, 0x68, 0xff, 0xcf, 0x80, 0x85, 0x91, 0xe3, 0xfe, 0x5e, 0x6d, 0xb9, 0x08, + 0x73, 0x3e, 0x39, 0x26, 0xaa, 0xa3, 0xcd, 0x63, 0x45, 0x88, 0x59, 0xf6, 0x22, 0xa4, 0x5c, 0x2a, + 0x57, 0xc5, 0x8a, 0x10, 0x3a, 0x77, 0x08, 0x77, 0x3d, 0x5f, 0xe6, 0xa5, 0x2a, 0xd6, 0x94, 0xd0, + 0xb9, 0x4f, 0x7d, 0x5d, 0xa3, 0x8b, 0x21, 0xb2, 0xa1, 0xe0, 0x05, 0x87, 0xa1, 0x0e, 0x1b, 0x59, + 0xd9, 0xa8, 0x5a, 0x6f, 0x27, 0x38, 0x0c, 0xb1, 0x5c, 0x43, 0x57, 0xa0, 0x48, 0xdd, 0xa0, 0x4b, + 0xe2, 0x02, 0xbd, 0x2c, 0xb8, 0xb0, 0x98, 0xc1, 0x7a, 0xc1, 0xb6, 0xa1, 0x2a, 0xbb, 0xe2, 0xc7, + 0x84, 0x89, 0x1e, 0x4c, 0x84, 0x75, 0xc7, 0xe5, 0xae, 0x34, 0xbb, 0x8a, 0xe5, 0xd8, 0xbe, 0x01, + 0xe8, 0x91, 0xc7, 0xf8, 0x33, 0xf9, 0xa6, 0xc0, 0xce, 0x6a, 0x99, 0xf7, 0xe0, 0xc2, 0x08, 0xb7, + 0xbe, 0x16, 0x7e, 0x3c, 0xd6, 0x34, 0x5f, 0x4d, 0x67, 0x5c, 0xf9, 0x74, 0xe1, 0x28, 0xe0, 0x58, + 0xef, 0xbc, 0x00, 0x15, 0x69, 0x97, 0xfa, 0xb6, 0xed, 0x42, 0x55, 0x91, 0x5a, 0xf8, 0x67, 0x70, + 0x3e, 0x16, 0xf4, 0x39, 0xa1, 0xb2, 0x9d, 0x31, 0xa4, 0x5f, 0xbe, 0x37, 0xe9, 0x2b, 0x5b, 0xa3, + 0xec, 0x78, 0x1c, 0x6f, 0x13, 0xb8, 0x20, 0x79, 0x1e, 0x78, 0x8c, 0x87, 0xf4, 0x24, 0xb6, 0x7a, + 0x19, 0x60, 0xb3, 0xcd, 0xbd, 0x63, 0xf2, 0x24, 0xf0, 0xd5, 0x35, 0x5a, 0xc2, 0x89, 0x99, 0xf8, + 0x8a, 0xcc, 0x0d, 0x3b, 0xc7, 0xcb, 0x50, 0x6e, 0xb9, 0xd4, 0x3f, 0x69, 0xbd, 0xf4, 0xb8, 0x6e, + 0xe0, 0x87, 0x13, 0xf6, 0xef, 0x0d, 0x58, 0x4a, 0x7e, 0xa7, 0x75, 0x2c, 0xd2, 0xc5, 0x5d, 0x28, + 0xf0, 0xb8, 0x8e, 0x59, 0xcc, 0x32, 0x22, 0x05, 0x11, 0xa5, 0x0e, 0x96, 0xa0, 0x84, 0xa7, 0xd5, + 0xc1, 0xb9, 0x7a, 0x3a, 0x7c, 0xcc, 0xd3, 0xff, 0x2f, 0x01, 0x4a, 0x2f, 0x67, 0x74, 0xc4, 0xc9, + 0x06, 0x31, 0x37, 0xd6, 0x20, 0x3e, 0x1f, 0x6f, 0x10, 0xd5, 0xd5, 0x7c, 0x7b, 0x1a, 0x4d, 0xa6, + 0x68, 0x13, 0x47, 0xfa, 0x98, 0xc2, 0x0c, 0x7d, 0x0c, 0x5a, 0x8b, 0x6f, 0x1c, 0x75, 0xd7, 0xa1, + 0x38, 0xa7, 0xd0, 0xa8, 0xed, 0xe8, 0xba, 0x42, 0xdf, 0x42, 0xf7, 0x66, 0x7b, 0x2d, 0x29, 0x8c, + 0xbf, 0x94, 0x6c, 0x41, 0x65, 0x3b, 0x4e, 0x94, 0x33, 0x3c, 0x95, 0x24, 0x41, 0x68, 0x5d, 0x17, + 0x36, 0x2a, 0x35, 0x5f, 0x4e, 0x9b, 0x18, 0x3f, 0x8b, 0x84, 0x54, 0x57, 0x36, 0x87, 0x19, 0xa5, + 0x65, 0x59, 0x3a, 0x68, 0x63, 0x2a, 0xdf, 0x4f, 0x59, 0x5f, 0xa2, 0x4f, 0xa0, 0x88, 0x09, 0xeb, + 0xfb, 0x5c, 0xbe, 0xbf, 0x54, 0x1a, 0x57, 0x26, 0x48, 0x57, 0x4c, 0xf2, 0xac, 0x6a, 0x00, 0xfa, + 0x39, 0xcc, 0xab, 0x11, 0x33, 0x2b, 0x93, 0x9e, 0x0d, 0x32, 0x34, 0xd3, 0x18, 0xdd, 0x50, 0x68, + 0x4a, 0x1c, 0xc7, 0x4f, 0x49, 0x40, 0xf4, 0xbb, 0xa0, 0x68, 0x8d, 0xe7, 0x70, 0x62, 0x06, 0x35, + 0x60, 0x8e, 0x53, 0xb7, 0x4d, 0xcc, 0x85, 0x29, 0x5c, 0xa8, 0x58, 0x45, 0x62, 0x8b, 0xbc, 0x20, + 0x20, 0x1d, 0x73, 0x51, 0x55, 0x4a, 0x8a, 0x42, 0xdf, 0x85, 0xc5, 0xa0, 0xdf, 0x93, 0xcd, 0x42, + 0x67, 0x8f, 0x93, 0x88, 0x99, 0xe7, 0xe5, 0xf7, 0xc6, 0x66, 0xd1, 0x55, 0x58, 0x08, 0xfa, 0xbd, + 0x7d, 0x71, 0xc3, 0x2b, 0xb6, 0x9a, 0x64, 0x1b, 0x9d, 0x44, 0x37, 0x60, 0x49, 0xe0, 0xe2, 0xdd, + 0x56, 0x9c, 0x4b, 0x92, 0x33, 0xbd, 0xf0, 0x1e, 0x7a, 0xe6, 0xf7, 0xd1, 0x11, 0x58, 0xcf, 0xa1, + 0x9a, 0xdc, 0x87, 0x0c, 0xec, 0xed, 0xd1, 0x8e, 0x7b, 0x8a, 0xb8, 0x48, 0x34, 0x1c, 0xcf, 0xe1, + 0xdb, 0x4f, 0xa3, 0x8e, 0xcb, 0x49, 0x56, 0xe6, 0x4d, 0x67, 0xa0, 0x4b, 0x50, 0xdc, 0x55, 0x1b, + 0xa5, 0xde, 0x4b, 0x35, 0x25, 0xe6, 0x9b, 0x44, 0x38, 0x4f, 0xa7, 0x5b, 0x4d, 0xd9, 0x97, 0xc1, + 0xca, 0x12, 0xaf, 0x9c, 0x61, 0xff, 0x39, 0x07, 0x30, 0x0c, 0x06, 0xf4, 0x21, 0x40, 0x8f, 0x74, + 0x3c, 0xf7, 0x57, 0x7c, 0xd8, 0x50, 0x96, 0xe5, 0x8c, 0xec, 0x2a, 0x87, 0xa5, 0x7f, 0xee, 0x9d, + 0x4b, 0x7f, 0x04, 0x05, 0xe6, 0x7d, 0x45, 0x74, 0x99, 0x22, 0xc7, 0xe8, 0x09, 0x54, 0xdc, 0x20, + 0x08, 0xb9, 0x0c, 0xe3, 0xb8, 0xd9, 0xbe, 0x79, 0x5a, 0xf8, 0x3a, 0x9b, 0x43, 0x7e, 0x75, 0x4a, + 0x92, 0x12, 0xac, 0x7b, 0x50, 0x1b, 0x67, 0x98, 0xa9, 0x19, 0xfc, 0x7b, 0x0e, 0xce, 0x8f, 0x6d, + 0x1d, 0x7a, 0x00, 0x35, 0x45, 0x8d, 0x3d, 0x90, 0x9c, 0x75, 0xd0, 0x52, 0x28, 0x74, 0x1f, 0xaa, + 0x9b, 0x9c, 0x8b, 0x4c, 0xa8, 0xec, 0x55, 0x2d, 0xe0, 0xe9, 0x52, 0x46, 0x10, 0xe8, 0xc1, 0x30, + 0xad, 0xe4, 0x27, 0x35, 0xfa, 0x63, 0xfa, 0x67, 0xe7, 0x14, 0xeb, 0x17, 0x93, 0x83, 0x3c, 0xaf, + 0xbc, 0xd4, 0x18, 0x0d, 0xf2, 0x33, 0xb2, 0xca, 0xd0, 0x87, 0x7f, 0x34, 0xa0, 0x14, 0x1f, 0xc2, + 0xcc, 0xb7, 0x8a, 0xbb, 0xa3, 0x6f, 0x15, 0xd7, 0x26, 0x5f, 0x6a, 0xef, 0xf3, 0x89, 0xe2, 0xfa, + 0x4f, 0xe1, 0x83, 0xcc, 0x82, 0x02, 0x55, 0x60, 0x7e, 0x6f, 0x7f, 0x13, 0xef, 0xb7, 0x9a, 0xb5, + 0x73, 0xa8, 0x0a, 0xa5, 0xed, 0x27, 0x8f, 0x77, 0x1f, 0xb5, 0xf6, 0x5b, 0x35, 0x43, 0x2c, 0x35, + 0x5b, 0x62, 0xdc, 0xac, 0xe5, 0x1a, 0xbf, 0x2b, 0xc2, 0xfc, 0xb6, 0xfa, 0x67, 0x0c, 0xed, 0x43, + 0x79, 0xf0, 0x97, 0x09, 0xb2, 0x33, 0x5c, 0x33, 0xf6, 0xdf, 0x8b, 0xf5, 0xd1, 0xa9, 0x3c, 0xfa, + 0xc2, 0x79, 0x00, 0x73, 0xf2, 0xcf, 0x23, 0x94, 0xf1, 0x2c, 0x90, 0xfc, 0x57, 0xc9, 0x3a, 0xfd, + 0xcf, 0x98, 0x75, 0x43, 0x48, 0x92, 0x6f, 0x2a, 0x59, 0x92, 0x92, 0x0f, 0xb7, 0xd6, 0xca, 0x19, + 0x8f, 0x31, 0xe8, 0x31, 0x14, 0x75, 0xa3, 0x99, 0xc5, 0x9a, 0x7c, 0x39, 0xb1, 0x56, 0x27, 0x33, + 0x28, 0x61, 0xeb, 0x06, 0x7a, 0x3c, 0x78, 0x8b, 0xcf, 0x52, 0x2d, 0x59, 0xa5, 0x5b, 0x67, 0xac, + 0xaf, 0x19, 0xeb, 0x06, 0xfa, 0x02, 0x2a, 0x89, 0x3a, 0x1c, 0x65, 0x54, 0x81, 0xe9, 0xa2, 0xde, + 0xba, 0x76, 0x06, 0x97, 0xb6, 0xbc, 0x05, 0x05, 0x99, 0x00, 0x32, 0x9c, 0x9d, 0x28, 0xd3, 0xb3, + 0xd4, 0x1c, 0x29, 0xdb, 0x0f, 0x54, 0x63, 0x41, 0x82, 0x64, 0xf4, 0xa1, 0x6b, 0x67, 0xd5, 0x03, + 0x13, 0xc3, 0x26, 0x15, 0xc4, 0xeb, 0x06, 0x0a, 0x01, 0xa5, 0x93, 0x3e, 0xfa, 0x7e, 0x46, 0x94, + 0x4c, 0xba, 0x79, 0xac, 0x1b, 0xd3, 0x31, 0x2b, 0xa3, 0xb6, 0xaa, 0xaf, 0xde, 0x2c, 0x1b, 0xff, + 0x7c, 0xb3, 0x6c, 0xfc, 0xfb, 0xcd, 0xb2, 0x71, 0x50, 0x94, 0x95, 0xde, 0x0f, 0xbe, 0x09, 0x00, + 0x00, 0xff, 0xff, 0x16, 0xc8, 0xe5, 0x4c, 0x39, 0x1e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2892,6 +2918,20 @@ func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.Exporters) > 0 { + for iNdEx := len(m.Exporters) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Exporters[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintControl(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + } if m.SourcePolicy != nil { { size, err := m.SourcePolicy.MarshalToSizedBuffer(dAtA[:i]) @@ -2992,9 +3032,9 @@ func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x2a } - if len(m.ExporterAttrs) > 0 { - for k := range m.ExporterAttrs { - v := m.ExporterAttrs[k] + if len(m.ExporterAttrsDeprecated) > 0 { + for k := range m.ExporterAttrsDeprecated { + v := m.ExporterAttrsDeprecated[k] baseI := i i -= len(v) copy(dAtA[i:], v) @@ -3011,10 +3051,10 @@ func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x22 } } - if len(m.Exporter) > 0 { - i -= len(m.Exporter) - copy(dAtA[i:], m.Exporter) - i = encodeVarintControl(dAtA, i, uint64(len(m.Exporter))) + if len(m.ExporterDeprecated) > 0 { + i -= len(m.ExporterDeprecated) + copy(dAtA[i:], m.ExporterDeprecated) + i = encodeVarintControl(dAtA, i, uint64(len(m.ExporterDeprecated))) i-- dAtA[i] = 0x1a } @@ -4339,6 +4379,30 @@ func (m *BuildResultInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.Results) > 0 { + for k := range m.Results { + v := m.Results[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintControl(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i = encodeVarintControl(dAtA, i, uint64(k)) + i-- + dAtA[i] = 0x8 + i = encodeVarintControl(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } + } if len(m.Attestations) > 0 { for iNdEx := len(m.Attestations) - 1; iNdEx >= 0; iNdEx-- { { @@ -4353,9 +4417,9 @@ func (m *BuildResultInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - if m.Result != nil { + if m.ResultDeprecated != nil { { - size, err := m.Result.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ResultDeprecated.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -4564,12 +4628,12 @@ func (m *SolveRequest) Size() (n int) { l = m.Definition.Size() n += 1 + l + sovControl(uint64(l)) } - l = len(m.Exporter) + l = len(m.ExporterDeprecated) if l > 0 { n += 1 + l + sovControl(uint64(l)) } - if len(m.ExporterAttrs) > 0 { - for k, v := range m.ExporterAttrs { + if len(m.ExporterAttrsDeprecated) > 0 { + for k, v := range m.ExporterAttrsDeprecated { _ = k _ = v mapEntrySize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v))) @@ -4620,6 +4684,12 @@ func (m *SolveRequest) Size() (n int) { l = m.SourcePolicy.Size() n += 1 + l + sovControl(uint64(l)) } + if len(m.Exporters) > 0 { + for _, e := range m.Exporters { + l = e.Size() + n += 1 + l + sovControl(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -5203,8 +5273,8 @@ func (m *BuildResultInfo) Size() (n int) { } var l int _ = l - if m.Result != nil { - l = m.Result.Size() + if m.ResultDeprecated != nil { + l = m.ResultDeprecated.Size() n += 1 + l + sovControl(uint64(l)) } if len(m.Attestations) > 0 { @@ -5213,6 +5283,19 @@ func (m *BuildResultInfo) Size() (n int) { n += 1 + l + sovControl(uint64(l)) } } + if len(m.Results) > 0 { + for k, v := range m.Results { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovControl(uint64(l)) + } + mapEntrySize := 1 + sovControl(uint64(k)) + l + n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6035,7 +6118,7 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Exporter", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExporterDeprecated", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6063,11 +6146,11 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Exporter = string(dAtA[iNdEx:postIndex]) + m.ExporterDeprecated = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExporterAttrs", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExporterAttrsDeprecated", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -6094,8 +6177,8 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.ExporterAttrs == nil { - m.ExporterAttrs = make(map[string]string) + if m.ExporterAttrsDeprecated == nil { + m.ExporterAttrsDeprecated = make(map[string]string) } var mapkey string var mapvalue string @@ -6190,7 +6273,7 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { iNdEx += skippy } } - m.ExporterAttrs[mapkey] = mapvalue + m.ExporterAttrsDeprecated[mapkey] = mapvalue iNdEx = postIndex case 5: if wireType != 2 { @@ -6633,6 +6716,40 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Exporters", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthControl + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Exporters = append(m.Exporters, &Exporter{}) + if err := m.Exporters[len(m.Exporters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipControl(dAtA[iNdEx:]) @@ -10589,7 +10706,7 @@ func (m *BuildResultInfo) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ResultDeprecated", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -10616,10 +10733,10 @@ func (m *BuildResultInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Result == nil { - m.Result = &Descriptor{} + if m.ResultDeprecated == nil { + m.ResultDeprecated = &Descriptor{} } - if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ResultDeprecated.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -10657,6 +10774,121 @@ func (m *BuildResultInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Results", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthControl + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Results == nil { + m.Results = make(map[int64]*Descriptor) + } + var mapkey int64 + var mapvalue *Descriptor + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapkey |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthControl + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthControl + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &Descriptor{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipControl(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthControl + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Results[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipControl(dAtA[iNdEx:]) diff --git a/vendor/github.com/moby/buildkit/api/services/control/control.proto b/vendor/github.com/moby/buildkit/api/services/control/control.proto index 327c9eeaf420e..919b1dd8c3872 100644 --- a/vendor/github.com/moby/buildkit/api/services/control/control.proto +++ b/vendor/github.com/moby/buildkit/api/services/control/control.proto @@ -2,13 +2,13 @@ syntax = "proto3"; package moby.buildkit.v1; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; -import "github.com/moby/buildkit/solver/pb/ops.proto"; -import "github.com/moby/buildkit/api/types/worker.proto"; // import "github.com/containerd/containerd/api/types/descriptor.proto"; import "github.com/gogo/googleapis/google/rpc/status.proto"; +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +import "github.com/moby/buildkit/api/types/worker.proto"; +import "github.com/moby/buildkit/solver/pb/ops.proto"; import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto"; +import "google/protobuf/timestamp.proto"; option (gogoproto.sizer_all) = true; option (gogoproto.marshaler_all) = true; @@ -60,8 +60,11 @@ message UsageRecord { message SolveRequest { string Ref = 1; pb.Definition Definition = 2; - string Exporter = 3; - map ExporterAttrs = 4; + // ExporterDeprecated and ExporterAttrsDeprecated are deprecated in favor + // of the new Exporters. If these fields are set, then they will be + // appended to the Exporters field if Exporters was not explicitly set. + string ExporterDeprecated = 3; + map ExporterAttrsDeprecated = 4; string Session = 5; string Frontend = 6; map FrontendAttrs = 7; @@ -70,6 +73,7 @@ message SolveRequest { map FrontendInputs = 10; bool Internal = 11; // Internal builds are not recorded in build history moby.buildkit.v1.sourcepolicy.Policy SourcePolicy = 12; + repeated Exporter Exporters = 13; } message CacheOptions { @@ -227,11 +231,15 @@ message Descriptor { } message BuildResultInfo { - Descriptor Result = 1; + Descriptor ResultDeprecated = 1; repeated Descriptor Attestations = 2; + map Results = 3; } +// Exporter describes the output exporter message Exporter { + // Type identifies the exporter string Type = 1; + // Attrs specifies exporter configuration map Attrs = 2; } diff --git a/vendor/github.com/moby/buildkit/cache/blobs.go b/vendor/github.com/moby/buildkit/cache/blobs.go index 33e9693f1982c..824b1d0a9fd04 100644 --- a/vendor/github.com/moby/buildkit/cache/blobs.go +++ b/vendor/github.com/moby/buildkit/cache/blobs.go @@ -8,12 +8,15 @@ import ( "github.com/containerd/containerd/diff" "github.com/containerd/containerd/diff/walking" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/leases" "github.com/containerd/containerd/mount" "github.com/moby/buildkit/session" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" + "github.com/moby/buildkit/util/converter" "github.com/moby/buildkit/util/flightcontrol" + "github.com/moby/buildkit/util/leaseutil" "github.com/moby/buildkit/util/winlayers" digest "github.com/opencontainers/go-digest" imagespecidentity "github.com/opencontainers/image-spec/identity" @@ -22,11 +25,9 @@ import ( "golang.org/x/sync/errgroup" ) -var g flightcontrol.Group[struct{}] +var g flightcontrol.Group[*leaseutil.LeaseRef] var gFileList flightcontrol.Group[[]string] -const containerdUncompressed = "containerd.io/uncompressed" - var ErrNoBlobs = errors.Errorf("no blobs for snapshot") // computeBlobChain ensures every ref in a parent chain has an associated blob in the content store. If @@ -87,13 +88,23 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool if _, ok := filter[sr.ID()]; ok { eg.Go(func() error { - _, err := g.Do(ctx, fmt.Sprintf("%s-%t", sr.ID(), createIfNeeded), func(ctx context.Context) (struct{}, error) { + l, err := g.Do(ctx, fmt.Sprintf("%s-%t", sr.ID(), createIfNeeded), func(ctx context.Context) (_ *leaseutil.LeaseRef, err error) { if sr.getBlob() != "" { - return struct{}{}, nil + return nil, nil } if !createIfNeeded { - return struct{}{}, errors.WithStack(ErrNoBlobs) + return nil, errors.WithStack(ErrNoBlobs) + } + + l, ctx, err := leaseutil.NewLease(ctx, sr.cm.LeaseManager, leaseutil.MakeTemporary) + if err != nil { + return nil, err } + defer func() { + if err != nil { + l.Discard() + } + }() compressorFunc, finalize := comp.Type.Compress(ctx, comp) mediaType := comp.Type.MediaType() @@ -109,12 +120,12 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool if lowerRef != nil { m, err := lowerRef.Mount(ctx, true, s) if err != nil { - return struct{}{}, err + return nil, err } var release func() error lower, release, err = m.Mount() if err != nil { - return struct{}{}, err + return nil, err } if release != nil { defer release() @@ -132,12 +143,12 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool if upperRef != nil { m, err := upperRef.Mount(ctx, true, s) if err != nil { - return struct{}{}, err + return nil, err } var release func() error upper, release, err = m.Mount() if err != nil { - return struct{}{}, err + return nil, err } if release != nil { defer release() @@ -145,14 +156,13 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool } var desc ocispecs.Descriptor - var err error // Determine differ and error/log handling according to the platform, envvar and the snapshotter. var enableOverlay, fallback, logWarnOnErr bool if forceOvlStr := os.Getenv("BUILDKIT_DEBUG_FORCE_OVERLAY_DIFF"); forceOvlStr != "" && sr.kind() != Diff { enableOverlay, err = strconv.ParseBool(forceOvlStr) if err != nil { - return struct{}{}, errors.Wrapf(err, "invalid boolean in BUILDKIT_DEBUG_FORCE_OVERLAY_DIFF") + return nil, errors.Wrapf(err, "invalid boolean in BUILDKIT_DEBUG_FORCE_OVERLAY_DIFF") } fallback = false // prohibit fallback on debug } else if !isTypeWindows(sr) { @@ -174,10 +184,10 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool if !ok || err != nil { if !fallback { if !ok { - return struct{}{}, errors.Errorf("overlay mounts not detected (lower=%+v,upper=%+v)", lower, upper) + return nil, errors.Errorf("overlay mounts not detected (lower=%+v,upper=%+v)", lower, upper) } if err != nil { - return struct{}{}, errors.Wrapf(err, "failed to compute overlay diff") + return nil, errors.Wrapf(err, "failed to compute overlay diff") } } if logWarnOnErr { @@ -189,7 +199,7 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool } } - if desc.Digest == "" && !isTypeWindows(sr) && comp.Type.NeedsComputeDiffBySelf() { + if desc.Digest == "" && !isTypeWindows(sr) && comp.Type.NeedsComputeDiffBySelf(comp) { // These compression types aren't supported by containerd differ. So try to compute diff on buildkit side. // This case can be happen on containerd worker + non-overlayfs snapshotter (e.g. native). // See also: https://github.com/containerd/containerd/issues/4263 @@ -210,7 +220,7 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool diff.WithCompressor(compressorFunc), ) if err != nil { - return struct{}{}, err + return nil, err } } @@ -220,7 +230,7 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool if finalize != nil { a, err := finalize(ctx, sr.cm.ContentStore) if err != nil { - return struct{}{}, errors.Wrapf(err, "failed to finalize compression") + return nil, errors.Wrapf(err, "failed to finalize compression") } for k, v := range a { desc.Annotations[k] = v @@ -228,26 +238,32 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool } info, err := sr.cm.ContentStore.Info(ctx, desc.Digest) if err != nil { - return struct{}{}, err + return nil, err } - if diffID, ok := info.Labels[containerdUncompressed]; ok { - desc.Annotations[containerdUncompressed] = diffID + if diffID, ok := info.Labels[labels.LabelUncompressed]; ok { + desc.Annotations[labels.LabelUncompressed] = diffID } else if mediaType == ocispecs.MediaTypeImageLayer { - desc.Annotations[containerdUncompressed] = desc.Digest.String() + desc.Annotations[labels.LabelUncompressed] = desc.Digest.String() } else { - return struct{}{}, errors.Errorf("unknown layer compression type") + return nil, errors.Errorf("unknown layer compression type") } if err := sr.setBlob(ctx, desc); err != nil { - return struct{}{}, err + return nil, err } - return struct{}{}, nil + return l, nil }) if err != nil { return err } + if l != nil { + if err := l.Adopt(ctx); err != nil { + return err + } + } + if comp.Force { if err := ensureCompression(ctx, sr, comp, s); err != nil { return errors.Wrapf(err, "failed to ensure compression type of %q", comp.Type) @@ -416,29 +432,42 @@ func isTypeWindows(sr *immutableRef) bool { // ensureCompression ensures the specified ref has the blob of the specified compression Type. func ensureCompression(ctx context.Context, ref *immutableRef, comp compression.Config, s session.Group) error { - _, err := g.Do(ctx, fmt.Sprintf("ensureComp-%s-%s", ref.ID(), comp.Type), func(ctx context.Context) (struct{}, error) { + l, err := g.Do(ctx, fmt.Sprintf("ensureComp-%s-%s", ref.ID(), comp.Type), func(ctx context.Context) (_ *leaseutil.LeaseRef, err error) { desc, err := ref.ociDesc(ctx, ref.descHandlers, true) if err != nil { - return struct{}{}, err + return nil, err } + l, ctx, err := leaseutil.NewLease(ctx, ref.cm.LeaseManager, leaseutil.MakeTemporary) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + l.Discard() + } + }() + // Resolve converters - layerConvertFunc, err := getConverter(ctx, ref.cm.ContentStore, desc, comp) + layerConvertFunc, err := converter.New(ctx, ref.cm.ContentStore, desc, comp) if err != nil { - return struct{}{}, err + return nil, err } else if layerConvertFunc == nil { if isLazy, err := ref.isLazy(ctx); err != nil { - return struct{}{}, err + return nil, err } else if isLazy { // This ref can be used as the specified compressionType. Keep it lazy. - return struct{}{}, nil + return l, nil } - return struct{}{}, ref.linkBlob(ctx, desc) + if err := ref.linkBlob(ctx, desc); err != nil { + return nil, err + } + return l, nil } // First, lookup local content store if _, err := ref.getBlobWithCompression(ctx, comp.Type); err == nil { - return struct{}{}, nil // found the compression variant. no need to convert. + return l, nil // found the compression variant. no need to convert. } // Convert layer compression type @@ -448,18 +477,26 @@ func ensureCompression(ctx context.Context, ref *immutableRef, comp compression. dh: ref.descHandlers[desc.Digest], session: s, }).Unlazy(ctx); err != nil { - return struct{}{}, err + return l, err } newDesc, err := layerConvertFunc(ctx, ref.cm.ContentStore, desc) if err != nil { - return struct{}{}, errors.Wrapf(err, "failed to convert") + return nil, errors.Wrapf(err, "failed to convert") } // Start to track converted layer if err := ref.linkBlob(ctx, *newDesc); err != nil { - return struct{}{}, errors.Wrapf(err, "failed to add compression blob") + return nil, errors.Wrapf(err, "failed to add compression blob") } - return struct{}{}, nil + return l, nil }) - return err + if err != nil { + return err + } + if l != nil { + if err := l.Adopt(ctx); err != nil { + return err + } + } + return nil } diff --git a/vendor/github.com/moby/buildkit/cache/blobs_linux.go b/vendor/github.com/moby/buildkit/cache/blobs_linux.go index ce41275e6b74c..1ea5cbbf01a18 100644 --- a/vendor/github.com/moby/buildkit/cache/blobs_linux.go +++ b/vendor/github.com/moby/buildkit/cache/blobs_linux.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" + labelspkg "github.com/containerd/containerd/labels" "github.com/containerd/containerd/mount" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" @@ -42,14 +43,27 @@ func (sr *immutableRef) tryComputeOverlayBlob(ctx context.Context, lower, upper if err != nil { return emptyDesc, false, errors.Wrap(err, "failed to open writer") } + defer func() { if cw != nil { + // after commit success cw will be set to nil, if cw isn't nil, error + // happened before commit, we should abort this ingest, and because the + // error may incured by ctx cancel, use a new context here. And since + // cm.Close will unlock this ref in the content store, we invoke abort + // to remove the ingest root in advance. + if aerr := sr.cm.ContentStore.Abort(context.Background(), ref); aerr != nil { + bklog.G(ctx).WithError(aerr).Warnf("failed to abort writer %q", ref) + } if cerr := cw.Close(); cerr != nil { bklog.G(ctx).WithError(cerr).Warnf("failed to close writer %q", ref) } } }() + if err = cw.Truncate(0); err != nil { + return emptyDesc, false, errors.Wrap(err, "failed to truncate writer") + } + bufW := bufio.NewWriterSize(cw, 128*1024) var labels map[string]string if compressorFunc != nil { @@ -69,7 +83,7 @@ func (sr *immutableRef) tryComputeOverlayBlob(ctx context.Context, lower, upper if labels == nil { labels = map[string]string{} } - labels[containerdUncompressed] = dgstr.Digest().String() + labels[labelspkg.LabelUncompressed] = dgstr.Digest().String() } else { if err = overlay.WriteUpperdir(ctx, bufW, upperdir, lower); err != nil { return emptyDesc, false, errors.Wrap(err, "failed to write diff") @@ -101,9 +115,9 @@ func (sr *immutableRef) tryComputeOverlayBlob(ctx context.Context, lower, upper cinfo.Labels = make(map[string]string) } // Set uncompressed label if digest already existed without label - if _, ok := cinfo.Labels[containerdUncompressed]; !ok { - cinfo.Labels[containerdUncompressed] = labels[containerdUncompressed] - if _, err := sr.cm.ContentStore.Update(ctx, cinfo, "labels."+containerdUncompressed); err != nil { + if _, ok := cinfo.Labels[labelspkg.LabelUncompressed]; !ok { + cinfo.Labels[labelspkg.LabelUncompressed] = labels[labelspkg.LabelUncompressed] + if _, err := sr.cm.ContentStore.Update(ctx, cinfo, "labels."+labelspkg.LabelUncompressed); err != nil { return emptyDesc, false, errors.Wrap(err, "error setting uncompressed label") } } diff --git a/vendor/github.com/moby/buildkit/cache/blobs_nolinux.go b/vendor/github.com/moby/buildkit/cache/blobs_nolinux.go index 1567768c1939b..7283cbf0e2561 100644 --- a/vendor/github.com/moby/buildkit/cache/blobs_nolinux.go +++ b/vendor/github.com/moby/buildkit/cache/blobs_nolinux.go @@ -6,8 +6,8 @@ package cache import ( "context" - "github.com/moby/buildkit/util/compression" "github.com/containerd/containerd/mount" + "github.com/moby/buildkit/util/compression" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) diff --git a/vendor/github.com/moby/buildkit/cache/compression.go b/vendor/github.com/moby/buildkit/cache/compression.go deleted file mode 100644 index bede8d932278e..0000000000000 --- a/vendor/github.com/moby/buildkit/cache/compression.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build !nydus -// +build !nydus - -package cache - -import ( - "context" - - "github.com/containerd/containerd/content" - "github.com/moby/buildkit/cache/config" - ocispecs "github.com/opencontainers/image-spec/specs-go/v1" -) - -func needsForceCompression(ctx context.Context, cs content.Store, source ocispecs.Descriptor, refCfg config.RefConfig) bool { - return refCfg.Compression.Force -} diff --git a/vendor/github.com/moby/buildkit/cache/compression_nydus.go b/vendor/github.com/moby/buildkit/cache/compression_nydus.go index 1b6443064759b..b50d7971f5a5d 100644 --- a/vendor/github.com/moby/buildkit/cache/compression_nydus.go +++ b/vendor/github.com/moby/buildkit/cache/compression_nydus.go @@ -10,7 +10,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" - "github.com/moby/buildkit/cache/config" + "github.com/containerd/containerd/labels" "github.com/moby/buildkit/session" "github.com/moby/buildkit/util/compression" digest "github.com/opencontainers/go-digest" @@ -27,20 +27,6 @@ func init() { ) } -// Nydus compression type can't be mixed with other compression types in the same image, -// so if `source` is this kind of layer, but the target is other compression type, we -// should do the forced compression. -func needsForceCompression(ctx context.Context, cs content.Store, source ocispecs.Descriptor, refCfg config.RefConfig) bool { - if refCfg.Compression.Force { - return true - } - isNydusBlob, _ := compression.Nydus.Is(ctx, cs, source) - if refCfg.Compression.Type == compression.Nydus { - return !isNydusBlob - } - return isNydusBlob -} - // MergeNydus does two steps: // 1. Extracts nydus bootstrap from nydus format (nydus blob + nydus bootstrap) for each layer. // 2. Merge all nydus bootstraps into a final bootstrap (will as an extra layer). @@ -58,7 +44,6 @@ func MergeNydus(ctx context.Context, ref ImmutableRef, comp compression.Config, // Extracts nydus bootstrap from nydus format for each layer. var cm *cacheManager layers := []converter.Layer{} - blobIDs := []string{} for _, ref := range refs { blobDesc, err := getBlobWithCompressionWithRetry(ctx, ref, comp, s) if err != nil { @@ -72,7 +57,6 @@ func MergeNydus(ctx context.Context, ref ImmutableRef, comp compression.Config, if cm == nil { cm = ref.cm } - blobIDs = append(blobIDs, blobDesc.Digest.Hex()) layers = append(layers, converter.Layer{ Digest: blobDesc.Digest, ReaderAt: ra, @@ -109,7 +93,7 @@ func MergeNydus(ctx context.Context, ref ImmutableRef, comp compression.Config, compressedDgst := cw.Digest() if err := cw.Commit(ctx, 0, compressedDgst, content.WithLabels(map[string]string{ - containerdUncompressed: uncompressedDgst.Digest().String(), + labels.LabelUncompressed: uncompressedDgst.Digest().String(), })); err != nil { if !errdefs.IsAlreadyExists(err) { return nil, errors.Wrap(err, "commit to content store") @@ -129,7 +113,7 @@ func MergeNydus(ctx context.Context, ref ImmutableRef, comp compression.Config, Size: info.Size, MediaType: ocispecs.MediaTypeImageLayerGzip, Annotations: map[string]string{ - containerdUncompressed: uncompressedDgst.Digest().String(), + labels.LabelUncompressed: uncompressedDgst.Digest().String(), // Use this annotation to identify nydus bootstrap layer. converter.LayerAnnotationNydusBootstrap: "true", }, diff --git a/vendor/github.com/moby/buildkit/cache/contenthash/filehash_unix.go b/vendor/github.com/moby/buildkit/cache/contenthash/filehash_unix.go index 99bba604f2b54..a566f2fd77609 100644 --- a/vendor/github.com/moby/buildkit/cache/contenthash/filehash_unix.go +++ b/vendor/github.com/moby/buildkit/cache/contenthash/filehash_unix.go @@ -20,8 +20,8 @@ func setUnixOpt(path string, fi os.FileInfo, stat *fstypes.Stat) error { stat.Gid = s.Gid if !fi.IsDir() { - if s.Mode&syscall.S_IFBLK != 0 || - s.Mode&syscall.S_IFCHR != 0 { + if s.Mode&syscall.S_IFLNK == 0 && (s.Mode&syscall.S_IFBLK != 0 || + s.Mode&syscall.S_IFCHR != 0) { stat.Devmajor = int64(unix.Major(uint64(s.Rdev))) stat.Devminor = int64(unix.Minor(uint64(s.Rdev))) } diff --git a/vendor/github.com/moby/buildkit/cache/filelist.go b/vendor/github.com/moby/buildkit/cache/filelist.go index 0cb2e9b60ac47..225a520043b20 100644 --- a/vendor/github.com/moby/buildkit/cache/filelist.go +++ b/vendor/github.com/moby/buildkit/cache/filelist.go @@ -35,7 +35,7 @@ func (sr *immutableRef) FileList(ctx context.Context, s session.Group) ([]string } // lazy blobs need to be pulled first - if err := sr.Extract(ctx, s); err != nil { + if err := sr.ensureLocalContentBlob(ctx, s); err != nil { return nil, err } diff --git a/vendor/github.com/moby/buildkit/cache/manager.go b/vendor/github.com/moby/buildkit/cache/manager.go index 64322055ef67c..c09ada3b99195 100644 --- a/vendor/github.com/moby/buildkit/cache/manager.go +++ b/vendor/github.com/moby/buildkit/cache/manager.go @@ -13,6 +13,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/gc" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/leases" "github.com/docker/docker/pkg/idtools" "github.com/moby/buildkit/cache/metadata" @@ -36,6 +37,8 @@ var ( errInvalid = errors.New("invalid") ) +const maxPruneBatch = 10 // maximum number of refs to prune while holding the manager lock + type ManagerOpt struct { Snapshotter snapshot.Snapshotter ContentStore content.Store @@ -300,7 +303,7 @@ func (cm *cacheManager) GetByBlob(ctx context.Context, desc ocispecs.Descriptor, ref := rec.ref(true, descHandlers, nil) if s := unlazySessionOf(opts...); s != nil { - if err := ref.unlazy(ctx, ref.descHandlers, ref.progress, s, true); err != nil { + if err := ref.unlazy(ctx, ref.descHandlers, ref.progress, s, true, false); err != nil { return nil, err } } @@ -321,6 +324,7 @@ func (cm *cacheManager) init(ctx context.Context) error { bklog.G(ctx).Debugf("could not load snapshot %s: %+v", si.ID(), err) cm.MetadataStore.Clear(si.ID()) cm.LeaseManager.Delete(ctx, leases.Lease{ID: si.ID()}) + cm.LeaseManager.Delete(ctx, leases.Lease{ID: si.ID() + "-variants"}) } } return nil @@ -1055,7 +1059,7 @@ func (cm *cacheManager) pruneOnce(ctx context.Context, ch chan client.UsageInfo, }) } -func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt pruneOpt) error { +func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt pruneOpt) (err error) { var toDelete []*deleteRecord if opt.keepBytes != 0 && opt.totalSize < opt.keepBytes { @@ -1128,48 +1132,49 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt lastUsedAt: c.LastUsedAt, usageCount: c.UsageCount, }) - if !gcMode { - cr.dead = true - - // mark metadata as deleted in case we crash before cleanup finished - if err := cr.queueDeleted(); err != nil { - cr.mu.Unlock() - cm.mu.Unlock() - return err - } - if err := cr.commitMetadata(); err != nil { - cr.mu.Unlock() - cm.mu.Unlock() - return err - } - } else { - locked[cr.mu] = struct{}{} - continue // leave the record locked - } + locked[cr.mu] = struct{}{} + continue // leave the record locked } } cr.mu.Unlock() } + batchSize := len(toDelete) if gcMode && len(toDelete) > 0 { + batchSize = 1 sortDeleteRecords(toDelete) - var err error - for i, cr := range toDelete { - // only remove single record at a time - if i == 0 { - cr.dead = true - err = cr.queueDeleted() - if err == nil { - err = cr.commitMetadata() - } + } else if batchSize > maxPruneBatch { + batchSize = maxPruneBatch + } + + releaseLocks := func() { + for _, cr := range toDelete { + if !cr.released { + cr.released = true + cr.mu.Unlock() } - cr.mu.Unlock() } - if err != nil { - return err + cm.mu.Unlock() + } + + for i, cr := range toDelete { + // only remove single record at a time + if i < batchSize { + cr.dead = true + // mark metadata as deleted in case we crash before cleanup finished + if err := cr.queueDeleted(); err != nil { + releaseLocks() + return err + } + if err := cr.commitMetadata(); err != nil { + releaseLocks() + return err + } } - toDelete = toDelete[:1] + cr.mu.Unlock() + cr.released = true } + toDelete = toDelete[:batchSize] cm.mu.Unlock() @@ -1193,7 +1198,6 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt } cm.mu.Lock() - var err error for _, cr := range toDelete { cr.mu.Lock() @@ -1254,7 +1258,7 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) default: return cm.prune(ctx, ch, opt) } @@ -1611,6 +1615,7 @@ type deleteRecord struct { usageCount int lastUsedAtIndex int usageCountIndex int + released bool } func sortDeleteRecords(toDelete []*deleteRecord) { @@ -1657,7 +1662,7 @@ func sortDeleteRecords(toDelete []*deleteRecord) { } func diffIDFromDescriptor(desc ocispecs.Descriptor) (digest.Digest, error) { - diffIDStr, ok := desc.Annotations["containerd.io/uncompressed"] + diffIDStr, ok := desc.Annotations[labels.LabelUncompressed] if !ok { return "", errors.Errorf("missing uncompressed annotation for %s", desc.Digest) } diff --git a/vendor/github.com/moby/buildkit/cache/refs.go b/vendor/github.com/moby/buildkit/cache/refs.go index e448f94b29d24..fbb47db9c9c75 100644 --- a/vendor/github.com/moby/buildkit/cache/refs.go +++ b/vendor/github.com/moby/buildkit/cache/refs.go @@ -12,6 +12,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/leases" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/pkg/userns" @@ -39,7 +40,7 @@ import ( "golang.org/x/sync/errgroup" ) -var additionalAnnotations = append(compression.EStargzAnnotations, containerdUncompressed) +var additionalAnnotations = append(compression.EStargzAnnotations, labels.LabelUncompressed) // Ref is a reference to cacheable objects. type Ref interface { @@ -443,7 +444,7 @@ func (cr *cacheRecord) remove(ctx context.Context, removeSnapshot bool) (rerr er "id": cr.ID(), "refCount": len(cr.refs), "removeSnapshot": removeSnapshot, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), }) if rerr != nil { l = l.WithError(rerr) @@ -487,7 +488,7 @@ func (sr *immutableRef) traceLogFields() logrus.Fields { "refID": fmt.Sprintf("%p", sr), "newRefCount": len(sr.refs), "mutable": false, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), } if sr.equalMutable != nil { m["equalMutableID"] = sr.equalMutable.ID() @@ -627,7 +628,7 @@ func (sr *mutableRef) traceLogFields() logrus.Fields { "refID": fmt.Sprintf("%p", sr), "newRefCount": len(sr.refs), "mutable": true, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), } if sr.equalMutable != nil { m["equalMutableID"] = sr.equalMutable.ID() @@ -733,7 +734,7 @@ func (sr *immutableRef) ociDesc(ctx context.Context, dhs DescHandlers, preferNon diffID := sr.getDiffID() if diffID != "" { - desc.Annotations["containerd.io/uncompressed"] = string(diffID) + desc.Annotations[labels.LabelUncompressed] = string(diffID) } createdAt := sr.GetCreatedAt() @@ -991,6 +992,14 @@ func (sr *immutableRef) Mount(ctx context.Context, readonly bool, s session.Grou return mnt, nil } +func (sr *immutableRef) ensureLocalContentBlob(ctx context.Context, s session.Group) error { + if (sr.kind() == Layer || sr.kind() == BaseLayer) && !sr.getBlobOnly() { + return nil + } + + return sr.unlazy(ctx, sr.descHandlers, sr.progress, s, true, true) +} + func (sr *immutableRef) Extract(ctx context.Context, s session.Group) (rerr error) { if (sr.kind() == Layer || sr.kind() == BaseLayer) && !sr.getBlobOnly() { return nil @@ -1001,14 +1010,14 @@ func (sr *immutableRef) Extract(ctx context.Context, s session.Group) (rerr erro if rerr = sr.prepareRemoteSnapshotsStargzMode(ctx, s); rerr != nil { return } - rerr = sr.unlazy(ctx, sr.descHandlers, sr.progress, s, true) + rerr = sr.unlazy(ctx, sr.descHandlers, sr.progress, s, true, false) }); err != nil { return err } return rerr } - return sr.unlazy(ctx, sr.descHandlers, sr.progress, s, true) + return sr.unlazy(ctx, sr.descHandlers, sr.progress, s, true, false) } func (sr *immutableRef) withRemoteSnapshotLabelsStargzMode(ctx context.Context, s session.Group, f func()) error { @@ -1053,7 +1062,7 @@ func (sr *immutableRef) withRemoteSnapshotLabelsStargzMode(ctx context.Context, } func (sr *immutableRef) prepareRemoteSnapshotsStargzMode(ctx context.Context, s session.Group) error { - _, err := g.Do(ctx, sr.ID()+"-prepare-remote-snapshot", func(ctx context.Context) (_ struct{}, rerr error) { + _, err := g.Do(ctx, sr.ID()+"-prepare-remote-snapshot", func(ctx context.Context) (_ *leaseutil.LeaseRef, rerr error) { dhs := sr.descHandlers for _, r := range sr.layerChain() { r := r @@ -1065,7 +1074,7 @@ func (sr *immutableRef) prepareRemoteSnapshotsStargzMode(ctx context.Context, s dh := dhs[digest.Digest(r.getBlob())] if dh == nil { // We cannot prepare remote snapshots without descHandler. - return struct{}{}, nil + return nil, nil } // tmpLabels contains dh.SnapshotLabels + session IDs. All keys contain @@ -1098,8 +1107,17 @@ func (sr *immutableRef) prepareRemoteSnapshotsStargzMode(ctx context.Context, s if err == nil { // usable as remote snapshot without unlazying. defer func() { // Remove tmp labels appended in this func - for k := range tmpLabels { - info.Labels[k] = "" + if info.Labels != nil { + for k := range tmpLabels { + info.Labels[k] = "" + } + } else { + // We are logging here to track to try to debug when and why labels are nil. + // Log can be removed when not happening anymore. + bklog.G(ctx). + WithField("snapshotID", snapshotID). + WithField("name", info.Name). + Debug("snapshots exist but labels are nil") } if _, err := r.cm.Snapshotter.Update(ctx, info, tmpFields...); err != nil { bklog.G(ctx).Warn(errors.Wrapf(err, @@ -1117,7 +1135,7 @@ func (sr *immutableRef) prepareRemoteSnapshotsStargzMode(ctx context.Context, s break } - return struct{}{}, nil + return nil, nil }) return err } @@ -1139,25 +1157,36 @@ func makeTmpLabelsStargzMode(labels map[string]string, s session.Group) (fields return } -func (sr *immutableRef) unlazy(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group, topLevel bool) error { - _, err := g.Do(ctx, sr.ID()+"-unlazy", func(ctx context.Context) (_ struct{}, rerr error) { +func (sr *immutableRef) unlazy(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group, topLevel bool, ensureContentStore bool) error { + _, err := g.Do(ctx, sr.ID()+"-unlazy", func(ctx context.Context) (_ *leaseutil.LeaseRef, rerr error) { if _, err := sr.cm.Snapshotter.Stat(ctx, sr.getSnapshotID()); err == nil { - return struct{}{}, nil + if !ensureContentStore { + return nil, nil + } + if blob := sr.getBlob(); blob == "" { + return nil, nil + } + if _, err := sr.cm.ContentStore.Info(ctx, sr.getBlob()); err == nil { + return nil, nil + } } switch sr.kind() { case Merge, Diff: - return struct{}{}, sr.unlazyDiffMerge(ctx, dhs, pg, s, topLevel) + return nil, sr.unlazyDiffMerge(ctx, dhs, pg, s, topLevel, ensureContentStore) case Layer, BaseLayer: - return struct{}{}, sr.unlazyLayer(ctx, dhs, pg, s) + return nil, sr.unlazyLayer(ctx, dhs, pg, s, ensureContentStore) } - return struct{}{}, nil + return nil, nil }) - return err + if err != nil { + return err + } + return nil } // should be called within sizeG.Do call for this ref's ID -func (sr *immutableRef) unlazyDiffMerge(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group, topLevel bool) (rerr error) { +func (sr *immutableRef) unlazyDiffMerge(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group, topLevel bool, ensureContentStore bool) (rerr error) { eg, egctx := errgroup.WithContext(ctx) var diffs []snapshot.Diff sr.layerWalk(func(sr *immutableRef) { @@ -1167,13 +1196,13 @@ func (sr *immutableRef) unlazyDiffMerge(ctx context.Context, dhs DescHandlers, p if sr.diffParents.lower != nil { diff.Lower = sr.diffParents.lower.getSnapshotID() eg.Go(func() error { - return sr.diffParents.lower.unlazy(egctx, dhs, pg, s, false) + return sr.diffParents.lower.unlazy(egctx, dhs, pg, s, false, ensureContentStore) }) } if sr.diffParents.upper != nil { diff.Upper = sr.diffParents.upper.getSnapshotID() eg.Go(func() error { - return sr.diffParents.upper.unlazy(egctx, dhs, pg, s, false) + return sr.diffParents.upper.unlazy(egctx, dhs, pg, s, false, ensureContentStore) }) } case Layer: @@ -1182,7 +1211,7 @@ func (sr *immutableRef) unlazyDiffMerge(ctx context.Context, dhs DescHandlers, p case BaseLayer: diff.Upper = sr.getSnapshotID() eg.Go(func() error { - return sr.unlazy(egctx, dhs, pg, s, false) + return sr.unlazy(egctx, dhs, pg, s, false, ensureContentStore) }) } diffs = append(diffs, diff) @@ -1213,7 +1242,7 @@ func (sr *immutableRef) unlazyDiffMerge(ctx context.Context, dhs DescHandlers, p } // should be called within sizeG.Do call for this ref's ID -func (sr *immutableRef) unlazyLayer(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group) (rerr error) { +func (sr *immutableRef) unlazyLayer(ctx context.Context, dhs DescHandlers, pg progress.Controller, s session.Group, ensureContentStore bool) (rerr error) { if !sr.getBlobOnly() { return nil } @@ -1240,7 +1269,7 @@ func (sr *immutableRef) unlazyLayer(ctx context.Context, dhs DescHandlers, pg pr parentID := "" if sr.layerParent != nil { eg.Go(func() error { - if err := sr.layerParent.unlazy(egctx, dhs, pg, s, false); err != nil { + if err := sr.layerParent.unlazy(egctx, dhs, pg, s, false, ensureContentStore); err != nil { return err } parentID = sr.layerParent.getSnapshotID() diff --git a/vendor/github.com/moby/buildkit/cache/remote.go b/vendor/github.com/moby/buildkit/cache/remote.go index cfafef4cb57a7..0607c7aab5218 100644 --- a/vendor/github.com/moby/buildkit/cache/remote.go +++ b/vendor/github.com/moby/buildkit/cache/remote.go @@ -212,7 +212,7 @@ func (sr *immutableRef) getRemote(ctx context.Context, createIfNeeded bool, refC } } - if needsForceCompression(ctx, sr.cm.ContentStore, desc, refCfg) { + if refCfg.Compression.Force { if needs, err := refCfg.Compression.Type.NeedsConversion(ctx, sr.cm.ContentStore, desc); err != nil { return nil, err } else if needs { diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/export.go b/vendor/github.com/moby/buildkit/cache/remotecache/export.go index fbb475132d6cb..64347eb0865fe 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/export.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/export.go @@ -11,6 +11,7 @@ import ( v1 "github.com/moby/buildkit/cache/remotecache/v1" "github.com/moby/buildkit/session" "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" "github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/progress" @@ -185,6 +186,11 @@ func (ce *contentCacheExporter) Finalize(ctx context.Context) (map[string]string return nil, err } + if len(config.Layers) == 0 { + bklog.G(ctx).Warn("failed to match any cache with layers") + return nil, progress.OneOff(ctx, "skipping cache export for empty result")(nil) + } + cache, err := NewExportableCache(ce.oci, ce.imageManifest) if err != nil { return nil, err diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/gha/gha.go b/vendor/github.com/moby/buildkit/cache/remotecache/gha/gha.go index c24755e93d078..81e17102f8bbe 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/gha/gha.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/gha/gha.go @@ -11,6 +11,7 @@ import ( "time" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/labels" "github.com/moby/buildkit/cache/remotecache" v1 "github.com/moby/buildkit/cache/remotecache/v1" "github.com/moby/buildkit/session" @@ -133,7 +134,7 @@ func (ce *exporter) Finalize(ctx context.Context) (map[string]string, error) { return nil, errors.Errorf("invalid descriptor without annotations") } var diffID digest.Digest - v, ok := dgstPair.Descriptor.Annotations["containerd.io/uncompressed"] + v, ok := dgstPair.Descriptor.Annotations[labels.LabelUncompressed] if !ok { return nil, errors.Errorf("invalid descriptor without uncompressed annotation") } @@ -226,7 +227,7 @@ func (ci *importer) makeDescriptorProviderPair(l v1.CacheLayer) (*v1.DescriptorP if l.Annotations.DiffID == "" { return nil, errors.Errorf("cache layer with missing diffid") } - annotations["containerd.io/uncompressed"] = l.Annotations.DiffID.String() + annotations[labels.LabelUncompressed] = l.Annotations.DiffID.String() if !l.Annotations.CreatedAt.IsZero() { txt, err := l.Annotations.CreatedAt.MarshalText() if err != nil { diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/import.go b/vendor/github.com/moby/buildkit/cache/remotecache/import.go index 347d935e4a641..99b9695f866cb 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/import.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/import.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" v1 "github.com/moby/buildkit/cache/remotecache/v1" "github.com/moby/buildkit/session" "github.com/moby/buildkit/solver" @@ -221,7 +222,7 @@ func (ci *contentCacheImporter) importInlineCache(ctx context.Context, dt []byte if createdBy := createdMsg[i]; createdBy != "" { m.Annotations["buildkit/description"] = createdBy } - m.Annotations["containerd.io/uncompressed"] = img.Rootfs.DiffIDs[i].String() + m.Annotations[labels.LabelUncompressed] = img.Rootfs.DiffIDs[i].String() layers[m.Digest] = v1.DescriptorProviderPair{ Descriptor: m, Provider: ci.provider, diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go b/vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go index 3b7b0c68d2e77..4e1c763d80273 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/inline/inline.go @@ -1,9 +1,10 @@ -package registry +package inline import ( "context" "encoding/json" + "github.com/containerd/containerd/labels" "github.com/moby/buildkit/cache/remotecache" v1 "github.com/moby/buildkit/cache/remotecache/v1" "github.com/moby/buildkit/session" @@ -67,7 +68,7 @@ func (ce *exporter) ExportForLayers(ctx context.Context, layers []digest.Digest) } // fallback for uncompressed digests for _, v := range descs { - if uc := v.Descriptor.Annotations["containerd.io/uncompressed"]; uc == string(k) { + if uc := v.Descriptor.Annotations[labels.LabelUncompressed]; uc == string(k) { descs2[v.Descriptor.Digest] = v layerBlobDigests[i] = v.Descriptor.Digest } diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/local/local.go b/vendor/github.com/moby/buildkit/cache/remotecache/local/local.go index 818f9b441ee4f..5acff332bff1f 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/local/local.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/local/local.go @@ -105,8 +105,9 @@ func getContentStore(ctx context.Context, sm *session.Manager, g session.Group, if sessionID == "" { return nil, errors.New("local cache exporter/importer requires session") } - timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(context.Background()) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) caller, err := sm.Get(timeoutCtx, sessionID, false) if err != nil { diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go b/vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go index 007da98855091..c806dba6b10f9 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/registry/registry.go @@ -7,7 +7,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/snapshots" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/moby/buildkit/cache/remotecache" "github.com/moby/buildkit/session" "github.com/moby/buildkit/util/compression" diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go b/vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go index 11ea24b865f84..8eac0da8939b5 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/v1/chains.go @@ -21,21 +21,26 @@ type CacheChains struct { visited map[interface{}]struct{} } +var _ solver.CacheExporterTarget = &CacheChains{} + func (c *CacheChains) Add(dgst digest.Digest) solver.CacheExporterRecord { if strings.HasPrefix(dgst.String(), "random:") { + // random digests will be different *every* run - so we shouldn't cache + // it, since there's a zero chance this random digest collides again return &nopRecord{} } - it := &item{c: c, dgst: dgst, backlinks: map[*item]struct{}{}} + + it := &item{dgst: dgst, backlinks: map[*item]struct{}{}} c.items = append(c.items, it) return it } -func (c *CacheChains) Visit(v interface{}) { - c.visited[v] = struct{}{} +func (c *CacheChains) Visit(target any) { + c.visited[target] = struct{}{} } -func (c *CacheChains) Visited(v interface{}) bool { - _, ok := c.visited[v] +func (c *CacheChains) Visited(target any) bool { + _, ok := c.visited[target] return ok } @@ -76,6 +81,12 @@ func (c *CacheChains) normalize(ctx context.Context) error { return nil } +// Marshal converts the cache chains structure into a cache config and a +// collection of providers for reading the results from. +// +// Marshal aims to validate, normalize and sort the output to ensure a +// consistent digest (since cache configs are typically uploaded and stored in +// content-addressable OCI registries). func (c *CacheChains) Marshal(ctx context.Context) (*CacheConfig, DescriptorProvider, error) { if err := c.normalize(ctx); err != nil { return nil, nil, err @@ -109,19 +120,37 @@ type DescriptorProviderPair struct { Provider content.Provider } +// item is an implementation of a record in the cache chain. After validation, +// normalization and marshalling into the cache config, the item results form +// into the "layers", while the digests and the links form into the "records". type item struct { - c *CacheChains + // dgst is the unique identifier for each record. + // This *roughly* corresponds to an edge (vertex cachekey + index) in the + // solver - however, a single vertex can produce multiple unique cache keys + // (e.g. fast/slow), so it's a one-to-many relation. dgst digest.Digest + // links are what connect records to each other (with an optional selector), + // organized by input index (which correspond to vertex inputs). + // We can have multiple links for each index, since *any* of these could be + // used to get to this item (e.g. we could retrieve by fast/slow key). + links []map[link]struct{} + + // backlinks are the inverse of a link - these don't actually get directly + // exported, but they're internally used to help efficiently navigate the + // graph. + backlinks map[*item]struct{} + backlinksMu sync.Mutex + + // result is the result of computing the edge - this is the target of the + // data we actually want to store in the cache chain. result *solver.Remote resultTime time.Time - links []map[link]struct{} - backlinksMu sync.Mutex - backlinks map[*item]struct{} - invalid bool + invalid bool } +// link is a pointer to an item, with an optional selector. type link struct { src *item selector string @@ -170,25 +199,46 @@ func (c *item) LinkFrom(rec solver.CacheExporterRecord, index int, selector stri src.backlinksMu.Unlock() } +// validate checks if an item is valid (i.e. each index has at least one link) +// and marks it as such. +// +// Essentially, if an index has no links, it means that this cache record is +// unreachable by the cache importer, so we should remove it. Once we've marked +// an item as invalid, we remove it from it's backlinks and check it's +// validity again - since now this linked item may be unreachable too. func (c *item) validate() { + if c.invalid { + // early exit, if the item is already invalid, we've already gone + // through the backlinks + return + } + for _, m := range c.links { + // if an index has no links, there's no way to access this record, so + // mark it as invalid if len(m) == 0 { c.invalid = true - for bl := range c.backlinks { - changed := false - for _, m := range bl.links { - for l := range m { - if l.src == c { - delete(m, l) - changed = true - } + break + } + } + + if c.invalid { + for bl := range c.backlinks { + // remove ourselves from the backlinked item + changed := false + for _, m := range bl.links { + for l := range m { + if l.src == c { + delete(m, l) + changed = true } } - if changed { - bl.validate() - } } - return + + // if we've removed ourselves, we need to check it again + if changed { + bl.validate() + } } } } @@ -211,6 +261,7 @@ func (c *item) walkAllResults(fn func(i *item) error, visited map[*item]struct{} return nil } +// nopRecord is used to discard cache results that we're not interested in storing. type nopRecord struct { } @@ -219,5 +270,3 @@ func (c *nopRecord) AddResult(_ digest.Digest, _ int, createdAt time.Time, resul func (c *nopRecord) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) { } - -var _ solver.CacheExporterTarget = &CacheChains{} diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go b/vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go index a1b00d86f68fc..1e3cf32e0086e 100644 --- a/vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go +++ b/vendor/github.com/moby/buildkit/cache/remotecache/v1/doc.go @@ -30,7 +30,6 @@ package cacheimport // }, // { // "digest": "sha256:deadbeef", -// "output": 1, <- optional output index // "layers": [ <- optional array of layer pointers // { // "createdat": "", diff --git a/vendor/github.com/moby/buildkit/cache/util/fsutil.go b/vendor/github.com/moby/buildkit/cache/util/fsutil.go index 945e017168aa4..6ed594c7b058d 100644 --- a/vendor/github.com/moby/buildkit/cache/util/fsutil.go +++ b/vendor/github.com/moby/buildkit/cache/util/fsutil.go @@ -90,17 +90,17 @@ type ReadDirRequest struct { func ReadDir(ctx context.Context, mount snapshot.Mountable, req ReadDirRequest) ([]*fstypes.Stat, error) { var ( rd []*fstypes.Stat - wo fsutil.WalkOpt + fo fsutil.FilterOpt ) if req.IncludePattern != "" { - wo.IncludePatterns = append(wo.IncludePatterns, req.IncludePattern) + fo.IncludePatterns = append(fo.IncludePatterns, req.IncludePattern) } err := withMount(ctx, mount, func(root string) error { fp, err := fs.RootPath(root, req.Path) if err != nil { return errors.WithStack(err) } - return fsutil.Walk(ctx, fp, &wo, func(path string, info os.FileInfo, err error) error { + return fsutil.Walk(ctx, fp, &fo, func(path string, info os.FileInfo, err error) error { if err != nil { return errors.Wrapf(err, "walking %q", root) } @@ -128,6 +128,16 @@ func StatFile(ctx context.Context, mount snapshot.Mountable, path string) (*fsty return errors.WithStack(err) } if st, err = fsutil.Stat(fp); err != nil { + // The filename here is internal to the mount, so we can restore + // the request base path for error reporting. + // See os.DirFS.Open for details. + err1 := err + if err := errors.Cause(err); err != nil { + err1 = err + } + if pe, ok := err1.(*os.PathError); ok { + pe.Path = path + } return errors.WithStack(err) } return nil diff --git a/vendor/github.com/moby/buildkit/client/build.go b/vendor/github.com/moby/buildkit/client/build.go index 2a4bc9e105d19..5ba648177ec2b 100644 --- a/vendor/github.com/moby/buildkit/client/build.go +++ b/vendor/github.com/moby/buildkit/client/build.go @@ -84,6 +84,11 @@ func (g *gatewayClientForBuild) ResolveImageConfig(ctx context.Context, in *gate return g.gateway.ResolveImageConfig(ctx, in, opts...) } +func (g *gatewayClientForBuild) ResolveSourceMeta(ctx context.Context, in *gatewayapi.ResolveSourceMetaRequest, opts ...grpc.CallOption) (*gatewayapi.ResolveSourceMetaResponse, error) { + ctx = buildid.AppendToOutgoingContext(ctx, g.buildID) + return g.gateway.ResolveSourceMeta(ctx, in, opts...) +} + func (g *gatewayClientForBuild) Solve(ctx context.Context, in *gatewayapi.SolveRequest, opts ...grpc.CallOption) (*gatewayapi.SolveResponse, error) { ctx = buildid.AppendToOutgoingContext(ctx, g.buildID) return g.gateway.Solve(ctx, in, opts...) diff --git a/vendor/github.com/moby/buildkit/client/client.go b/vendor/github.com/moby/buildkit/client/client.go index 71a72bf9f6a53..26c91c37423b8 100644 --- a/vendor/github.com/moby/buildkit/client/client.go +++ b/vendor/github.com/moby/buildkit/client/client.go @@ -59,9 +59,6 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error var creds *withCredentials for _, o := range opts { - if _, ok := o.(*withFailFast); ok { - gopts = append(gopts, grpc.FailOnNonTempDialError(true)) - } if credInfo, ok := o.(*withCredentials); ok { if creds == nil { creds = &withCredentials{} @@ -105,8 +102,8 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error if tracerProvider != nil { var propagators = propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) - unary = append(unary, filterInterceptor(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators)))) - stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators))) + unary = append(unary, filterInterceptor(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 + stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 } if needDialer { @@ -205,7 +202,7 @@ func (c *Client) Wait(ctx context.Context) error { select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) case <-time.After(time.Second): } c.conn.ResetConnectBackoff() @@ -216,14 +213,6 @@ func (c *Client) Close() error { return c.conn.Close() } -type withFailFast struct{} - -func (*withFailFast) isClientOpt() {} - -func WithFailFast() ClientOpt { - return &withFailFast{} -} - type withDialer struct { dialer func(context.Context, string) (net.Conn, error) } diff --git a/vendor/github.com/moby/buildkit/client/graph.go b/vendor/github.com/moby/buildkit/client/graph.go index aaa96f293f1af..c24e73d45e08a 100644 --- a/vendor/github.com/moby/buildkit/client/graph.go +++ b/vendor/github.com/moby/buildkit/client/graph.go @@ -8,49 +8,50 @@ import ( ) type Vertex struct { - Digest digest.Digest - Inputs []digest.Digest - Name string - Started *time.Time - Completed *time.Time - Cached bool - Error string - ProgressGroup *pb.ProgressGroup + Digest digest.Digest `json:"digest,omitempty"` + Inputs []digest.Digest `json:"inputs,omitempty"` + Name string `json:"name,omitempty"` + Started *time.Time `json:"started,omitempty"` + Completed *time.Time `json:"completed,omitempty"` + Cached bool `json:"cached,omitempty"` + Error string `json:"error,omitempty"` + ProgressGroup *pb.ProgressGroup `json:"progressGroup,omitempty"` } type VertexStatus struct { - ID string - Vertex digest.Digest - Name string - Total int64 - Current int64 - Timestamp time.Time - Started *time.Time - Completed *time.Time + ID string `json:"id"` + Vertex digest.Digest `json:"vertex,omitempty"` + Name string `json:"name,omitempty"` + Total int64 `json:"total,omitempty"` + Current int64 `json:"current"` + Timestamp time.Time `json:"timestamp,omitempty"` + Started *time.Time `json:"started,omitempty"` + Completed *time.Time `json:"completed,omitempty"` } type VertexLog struct { - Vertex digest.Digest - Stream int - Data []byte - Timestamp time.Time + Vertex digest.Digest `json:"vertex,omitempty"` + Stream int `json:"stream,omitempty"` + Data []byte `json:"data"` + Timestamp time.Time `json:"timestamp"` } type VertexWarning struct { - Vertex digest.Digest - Level int - Short []byte - Detail [][]byte - URL string - SourceInfo *pb.SourceInfo - Range []*pb.Range + Vertex digest.Digest `json:"vertex,omitempty"` + Level int `json:"level,omitempty"` + Short []byte `json:"short,omitempty"` + Detail [][]byte `json:"detail,omitempty"` + URL string `json:"url,omitempty"` + + SourceInfo *pb.SourceInfo `json:"sourceInfo,omitempty"` + Range []*pb.Range `json:"range,omitempty"` } type SolveStatus struct { - Vertexes []*Vertex - Statuses []*VertexStatus - Logs []*VertexLog - Warnings []*VertexWarning + Vertexes []*Vertex `json:"vertexes,omitempty"` + Statuses []*VertexStatus `json:"statuses,omitempty"` + Logs []*VertexLog `json:"logs,omitempty"` + Warnings []*VertexWarning `json:"warnings,omitempty"` } type SolveResponse struct { diff --git a/vendor/github.com/moby/buildkit/client/llb/async.go b/vendor/github.com/moby/buildkit/client/llb/async.go index 8771c71978f89..cadbb5ef363ea 100644 --- a/vendor/github.com/moby/buildkit/client/llb/async.go +++ b/vendor/github.com/moby/buildkit/client/llb/async.go @@ -61,7 +61,7 @@ func (as *asyncState) Do(ctx context.Context, c *Constraints) error { if err != nil { select { case <-ctx.Done(): - if errors.Is(err, ctx.Err()) { + if errors.Is(err, context.Cause(ctx)) { return res, err } default: diff --git a/vendor/github.com/moby/buildkit/client/llb/exec.go b/vendor/github.com/moby/buildkit/client/llb/exec.go index 0eed6774c2ebd..17d6cd754687f 100644 --- a/vendor/github.com/moby/buildkit/client/llb/exec.go +++ b/vendor/github.com/moby/buildkit/client/llb/exec.go @@ -46,6 +46,7 @@ type mount struct { tmpfsOpt TmpfsInfo cacheSharing CacheMountSharingMode noOutput bool + contentCache MountContentCache } type ExecOp struct { @@ -281,6 +282,9 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, [] } else if m.source != nil { addCap(&e.constraints, pb.CapExecMountBind) } + if m.contentCache != MountContentCacheDefault { + addCap(&e.constraints, pb.CapExecMountContentCache) + } } if len(e.secrets) > 0 { @@ -366,6 +370,14 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, [] pm.CacheOpt.Sharing = pb.CacheSharingOpt_LOCKED } } + switch m.contentCache { + case MountContentCacheDefault: + pm.ContentCache = pb.MountContentCache_DEFAULT + case MountContentCacheOn: + pm.ContentCache = pb.MountContentCache_ON + case MountContentCacheOff: + pm.ContentCache = pb.MountContentCache_OFF + } if m.tmpfs { pm.MountType = pb.MountType_TMPFS pm.TmpfsOpt = &pb.TmpfsOpt{ @@ -492,6 +504,12 @@ func ForceNoOutput(m *mount) { m.noOutput = true } +func ContentCache(cache MountContentCache) MountOption { + return func(m *mount) { + m.contentCache = cache + } +} + func AsPersistentCacheDir(id string, sharing CacheMountSharingMode) MountOption { return func(m *mount) { m.cacheID = id @@ -783,3 +801,11 @@ const ( UlimitSigpending UlimitName = "sigpending" UlimitStack UlimitName = "stack" ) + +type MountContentCache int + +const ( + MountContentCacheDefault MountContentCache = iota + MountContentCacheOn + MountContentCacheOff +) diff --git a/vendor/github.com/moby/buildkit/client/llb/fileop.go b/vendor/github.com/moby/buildkit/client/llb/fileop.go index 7fc445c4c9254..1b01113e66109 100644 --- a/vendor/github.com/moby/buildkit/client/llb/fileop.go +++ b/vendor/github.com/moby/buildkit/client/llb/fileop.go @@ -398,6 +398,18 @@ func WithAllowWildcard(b bool) RmOption { }) } +type excludeOnCopyAction struct { + patterns []string +} + +func (e *excludeOnCopyAction) SetCopyOption(i *CopyInfo) { + i.ExcludePatterns = append(i.ExcludePatterns, e.patterns...) +} + +func WithExcludePatterns(patterns []string) CopyOption { + return &excludeOnCopyAction{patterns} +} + type fileActionRm struct { file string info RmInfo diff --git a/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go b/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go index 8a3a629954938..78ab06616f7a4 100644 --- a/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go +++ b/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/imageutil" "github.com/moby/buildkit/version" @@ -70,32 +71,31 @@ type imageMetaResolver struct { } type resolveResult struct { - ref string config []byte dgst digest.Digest } -func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (string, digest.Digest, []byte, error) { +func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) { imr.locker.Lock(ref) defer imr.locker.Unlock(ref) - platform := opt.Platform - if platform == nil { - platform = imr.platform + platform := imr.platform + if opt.Platform != nil { + platform = opt.Platform } k := imr.key(ref, platform) if res, ok := imr.cache[k]; ok { - return res.ref, res.dgst, res.config, nil + return ref, res.dgst, res.config, nil } - ref, dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, nil, platform, opt.SourcePolicies) + dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, nil, platform) if err != nil { return "", "", nil, err } - imr.cache[k] = resolveResult{dgst: dgst, config: config, ref: ref} + imr.cache[k] = resolveResult{dgst: dgst, config: config} return ref, dgst, config, nil } diff --git a/vendor/github.com/moby/buildkit/client/llb/marshal.go b/vendor/github.com/moby/buildkit/client/llb/marshal.go index 3b02299e431d9..48adaed80911b 100644 --- a/vendor/github.com/moby/buildkit/client/llb/marshal.go +++ b/vendor/github.com/moby/buildkit/client/llb/marshal.go @@ -95,14 +95,18 @@ func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) { c.Platform = &defaultPlatform } + opPlatform := pb.Platform{ + OS: c.Platform.OS, + Architecture: c.Platform.Architecture, + Variant: c.Platform.Variant, + OSVersion: c.Platform.OSVersion, + } + if c.Platform.OSFeatures != nil { + opPlatform.OSFeatures = append([]string{}, c.Platform.OSFeatures...) + } + return &pb.Op{ - Platform: &pb.Platform{ - OS: c.Platform.OS, - Architecture: c.Platform.Architecture, - Variant: c.Platform.Variant, - OSVersion: c.Platform.OSVersion, - OSFeatures: c.Platform.OSFeatures, - }, + Platform: &opPlatform, Constraints: &pb.WorkerConstraints{ Filter: c.WorkerConstraints, }, diff --git a/vendor/github.com/moby/buildkit/client/llb/resolver.go b/vendor/github.com/moby/buildkit/client/llb/resolver.go index 02644f62c78ba..da92b5ef084df 100644 --- a/vendor/github.com/moby/buildkit/client/llb/resolver.go +++ b/vendor/github.com/moby/buildkit/client/llb/resolver.go @@ -1,11 +1,7 @@ package llb import ( - "context" - - spb "github.com/moby/buildkit/sourcepolicy/pb" - digest "github.com/opencontainers/go-digest" - ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/moby/buildkit/client/llb/sourceresolver" ) // WithMetaResolver adds a metadata resolver to an image @@ -31,30 +27,4 @@ func WithLayerLimit(l int) ImageOption { } // ImageMetaResolver can resolve image config metadata from a reference -type ImageMetaResolver interface { - ResolveImageConfig(ctx context.Context, ref string, opt ResolveImageConfigOpt) (string, digest.Digest, []byte, error) -} - -type ResolverType int - -const ( - ResolverTypeRegistry ResolverType = iota - ResolverTypeOCILayout -) - -type ResolveImageConfigOpt struct { - ResolverType - - Platform *ocispecs.Platform - ResolveMode string - LogName string - - Store ResolveImageConfigOptStore - - SourcePolicies []*spb.Policy -} - -type ResolveImageConfigOptStore struct { - SessionID string - StoreID string -} +type ImageMetaResolver = sourceresolver.ImageMetaResolver diff --git a/vendor/github.com/moby/buildkit/client/llb/source.go b/vendor/github.com/moby/buildkit/client/llb/source.go index fa1096a67c233..3139a7b4e924b 100644 --- a/vendor/github.com/moby/buildkit/client/llb/source.go +++ b/vendor/github.com/moby/buildkit/client/llb/source.go @@ -5,10 +5,12 @@ import ( _ "crypto/sha256" // for opencontainers/go-digest "encoding/json" "os" + "path" "strconv" "strings" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/apicaps" "github.com/moby/buildkit/util/gitutil" @@ -135,10 +137,11 @@ func Image(ref string, opts ...ImageOption) State { if p == nil { p = c.Platform } - _, _, dt, err := info.metaResolver.ResolveImageConfig(ctx, ref, ResolveImageConfigOpt{ - Platform: p, - ResolveMode: info.resolveMode.String(), - ResolverType: ResolverTypeRegistry, + _, _, dt, err := info.metaResolver.ResolveImageConfig(ctx, ref, sourceresolver.Opt{ + Platform: p, + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: info.resolveMode.String(), + }, }) if err != nil { return State{}, err @@ -151,10 +154,11 @@ func Image(ref string, opts ...ImageOption) State { if p == nil { p = c.Platform } - ref, dgst, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref, ResolveImageConfigOpt{ - Platform: p, - ResolveMode: info.resolveMode.String(), - ResolverType: ResolverTypeRegistry, + ref, dgst, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref, sourceresolver.Opt{ + Platform: p, + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: info.resolveMode.String(), + }, }) if err != nil { return State{}, err @@ -226,7 +230,7 @@ type ImageInfo struct { // Git returns a state that represents a git repository. // Example: // -// st := llb.Git("https://github.com/moby/buildkit.git#v0.11.6") +// st := llb.Git("https://github.com/moby/buildkit.git", "v0.11.6") // // The example fetches the v0.11.6 tag of the buildkit repository. // You can also use a commit hash or a branch name. @@ -237,29 +241,29 @@ type ImageInfo struct { // // By default the git repository is cloned with `--depth=1` to reduce the amount of data downloaded. // Additionally the ".git" directory is removed after the clone, you can keep ith with the [KeepGitDir] [GitOption]. -func Git(remote, ref string, opts ...GitOption) State { - url := strings.Split(remote, "#")[0] - - var protocolType int - remote, protocolType = gitutil.ParseProtocol(remote) - - var sshHost string - if protocolType == gitutil.SSHProtocol { - parts := strings.SplitN(remote, ":", 2) - if len(parts) == 2 { - sshHost = parts[0] - // keep remote consistent with http(s) version - remote = parts[0] + "/" + parts[1] - } - } - if protocolType == gitutil.UnknownProtocol { +func Git(url, ref string, opts ...GitOption) State { + remote, err := gitutil.ParseURL(url) + if errors.Is(err, gitutil.ErrUnknownProtocol) { url = "https://" + url + remote, err = gitutil.ParseURL(url) + } + if remote != nil { + url = remote.Remote } - id := remote - - if ref != "" { - id += "#" + ref + var id string + if err != nil { + // If we can't parse the URL, just use the full URL as the ID. The git + // operation will fail later on. + id = url + } else { + // We construct the ID manually here, so that we can create the same ID + // for different protocols (e.g. https and ssh) that have the same + // host/path/fragment combination. + id = remote.Host + path.Join("/", remote.Path) + if ref != "" { + id += "#" + ref + } } gi := &GitInfo{ @@ -290,11 +294,11 @@ func Git(remote, ref string, opts ...GitOption) State { addCap(&gi.Constraints, pb.CapSourceGitHTTPAuth) } } - if protocolType == gitutil.SSHProtocol { + if remote != nil && remote.Scheme == gitutil.SSHProtocol { if gi.KnownSSHHosts != "" { attrs[pb.AttrKnownSSHHosts] = gi.KnownSSHHosts - } else if sshHost != "" { - keyscan, err := sshutil.SSHKeyScan(sshHost) + } else { + keyscan, err := sshutil.SSHKeyScan(remote.Host) if err == nil { // best effort attrs[pb.AttrKnownSSHHosts] = keyscan diff --git a/vendor/github.com/moby/buildkit/client/llb/sourceresolver/imageresolver.go b/vendor/github.com/moby/buildkit/client/llb/sourceresolver/imageresolver.go new file mode 100644 index 0000000000000..fa370900886df --- /dev/null +++ b/vendor/github.com/moby/buildkit/client/llb/sourceresolver/imageresolver.go @@ -0,0 +1,59 @@ +package sourceresolver + +import ( + "context" + "strings" + + "github.com/distribution/reference" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/imageutil" + digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +type ImageMetaResolver interface { + ResolveImageConfig(ctx context.Context, ref string, opt Opt) (string, digest.Digest, []byte, error) +} + +type imageMetaResolver struct { + mr MetaResolver +} + +var _ ImageMetaResolver = &imageMetaResolver{} + +func NewImageMetaResolver(mr MetaResolver) ImageMetaResolver { + return &imageMetaResolver{ + mr: mr, + } +} + +func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt Opt) (string, digest.Digest, []byte, error) { + parsed, err := reference.ParseNormalizedNamed(ref) + if err != nil { + return "", "", nil, errors.Wrapf(err, "could not parse reference %q", ref) + } + ref = parsed.String() + op := &pb.SourceOp{ + Identifier: "docker-image://" + ref, + } + if opt := opt.OCILayoutOpt; opt != nil { + op.Identifier = "oci-layout://" + ref + op.Attrs = map[string]string{} + if opt.Store.SessionID != "" { + op.Attrs[pb.AttrOCILayoutSessionID] = opt.Store.SessionID + } + if opt.Store.StoreID != "" { + op.Attrs[pb.AttrOCILayoutStoreID] = opt.Store.StoreID + } + } + res, err := imr.mr.ResolveSourceMetadata(ctx, op, opt) + if err != nil { + return "", "", nil, errors.Wrapf(err, "failed to resolve source metadata for %s", ref) + } + if res.Image == nil { + return "", "", nil, &imageutil.ResolveToNonImageError{Ref: ref, Updated: res.Op.Identifier} + } + ref = strings.TrimPrefix(res.Op.Identifier, "docker-image://") + ref = strings.TrimPrefix(ref, "oci-layout://") + return ref, res.Image.Digest, res.Image.Config, nil +} diff --git a/vendor/github.com/moby/buildkit/client/llb/sourceresolver/types.go b/vendor/github.com/moby/buildkit/client/llb/sourceresolver/types.go new file mode 100644 index 0000000000000..dc8b586a12e06 --- /dev/null +++ b/vendor/github.com/moby/buildkit/client/llb/sourceresolver/types.go @@ -0,0 +1,54 @@ +package sourceresolver + +import ( + "context" + + "github.com/moby/buildkit/solver/pb" + spb "github.com/moby/buildkit/sourcepolicy/pb" + digest "github.com/opencontainers/go-digest" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" +) + +type ResolverType int + +const ( + ResolverTypeRegistry ResolverType = iota + ResolverTypeOCILayout +) + +type MetaResolver interface { + ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt Opt) (*MetaResponse, error) +} + +type Opt struct { + LogName string + SourcePolicies []*spb.Policy + Platform *ocispecs.Platform + + ImageOpt *ResolveImageOpt + OCILayoutOpt *ResolveOCILayoutOpt +} + +type MetaResponse struct { + Op *pb.SourceOp + + Image *ResolveImageResponse +} + +type ResolveImageOpt struct { + ResolveMode string +} + +type ResolveImageResponse struct { + Digest digest.Digest + Config []byte +} + +type ResolveOCILayoutOpt struct { + Store ResolveImageConfigOptStore +} + +type ResolveImageConfigOptStore struct { + SessionID string + StoreID string +} diff --git a/vendor/github.com/moby/buildkit/client/llb/state.go b/vendor/github.com/moby/buildkit/client/llb/state.go index f15fad87ab214..1637e41770d6c 100644 --- a/vendor/github.com/moby/buildkit/client/llb/state.go +++ b/vendor/github.com/moby/buildkit/client/llb/state.go @@ -229,7 +229,7 @@ func (s State) Output() Output { return s.out } -// WithOutput creats a new state with the output set to the given output. +// WithOutput creates a new state with the output set to the given output. func (s State) WithOutput(o Output) State { prev := s s = State{ @@ -258,16 +258,21 @@ func (s State) WithImageConfig(c []byte) (State, error) { } s = s.Dir(img.Config.WorkingDir) if img.Architecture != "" && img.OS != "" { - s = s.Platform(ocispecs.Platform{ + plat := ocispecs.Platform{ OS: img.OS, Architecture: img.Architecture, Variant: img.Variant, - }) + OSVersion: img.OSVersion, + } + if img.OSFeatures != nil { + plat.OSFeatures = append([]string{}, img.OSFeatures...) + } + s = s.Platform(plat) } return s, nil } -// Run performs the command specified by the arguments within the contexst of the current [State]. +// Run performs the command specified by the arguments within the context of the current [State]. // The command is executed as a container with the [State]'s filesystem as the root filesystem. // As such any command you run must be present in the [State]'s filesystem. // Constraints such as [State.Ulimit], [State.ParentCgroup], [State.Network], etc. are applied to the container. diff --git a/vendor/github.com/moby/buildkit/client/ociindex/ociindex.go b/vendor/github.com/moby/buildkit/client/ociindex/ociindex.go index 156976f5dd869..512a77a68e679 100644 --- a/vendor/github.com/moby/buildkit/client/ociindex/ociindex.go +++ b/vendor/github.com/moby/buildkit/client/ociindex/ociindex.go @@ -12,9 +12,6 @@ import ( ) const ( - // indexFile is the name of the index file - indexFile = "index.json" - // lockFileSuffix is the suffix of the lock file lockFileSuffix = ".lock" ) @@ -26,7 +23,7 @@ type StoreIndex struct { } func NewStoreIndex(storePath string) StoreIndex { - indexPath := path.Join(storePath, indexFile) + indexPath := path.Join(storePath, ocispecs.ImageIndexFile) layoutPath := path.Join(storePath, ocispecs.ImageLayoutFile) return StoreIndex{ indexPath: indexPath, diff --git a/vendor/github.com/moby/buildkit/client/solve.go b/vendor/github.com/moby/buildkit/client/solve.go index 22ff2031d4421..6c4dcff67c412 100644 --- a/vendor/github.com/moby/buildkit/client/solve.go +++ b/vendor/github.com/moby/buildkit/client/solve.go @@ -35,7 +35,8 @@ import ( type SolveOpt struct { Exports []ExportEntry - LocalDirs map[string]string + LocalDirs map[string]string // Deprecated: use LocalMounts + LocalMounts map[string]fsutil.FS OCIStores map[string]content.Store SharedKey string Frontend string @@ -55,8 +56,8 @@ type SolveOpt struct { type ExportEntry struct { Type string Attrs map[string]string - Output func(map[string]string) (io.WriteCloser, error) // for ExporterOCI and ExporterDocker - OutputDir string // for ExporterLocal + Output filesync.FileOutputFunc // for ExporterOCI and ExporterDocker + OutputDir string // for ExporterLocal } type CacheOptionsEntry struct { @@ -90,7 +91,11 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG return nil, errors.New("invalid with def and cb") } - syncedDirs, err := prepareSyncedDirs(def, opt.LocalDirs) + mounts, err := prepareMounts(&opt) + if err != nil { + return nil, err + } + syncedDirs, err := prepareSyncedFiles(def, mounts) if err != nil { return nil, err } @@ -101,8 +106,8 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG } eg, ctx := errgroup.WithContext(ctx) - statusContext, cancelStatus := context.WithCancel(context.Background()) - defer cancelStatus() + statusContext, cancelStatus := context.WithCancelCause(context.Background()) + defer cancelStatus(errors.WithStack(context.Canceled)) if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { statusContext = trace.ContextWithSpan(statusContext, span) @@ -125,14 +130,6 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG return nil, err } - var ex ExportEntry - if len(opt.Exports) > 1 { - return nil, errors.New("currently only single Exports can be specified") - } - if len(opt.Exports) == 1 { - ex = opt.Exports[0] - } - storesToUpdate := []string{} if !opt.SessionPreInitialized { @@ -156,51 +153,52 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG contentStores[key2] = store } - var supportFile bool - var supportDir bool - switch ex.Type { - case ExporterLocal: - supportDir = true - case ExporterTar: - supportFile = true - case ExporterOCI, ExporterDocker: - supportDir = ex.OutputDir != "" - supportFile = ex.Output != nil - } - - if supportFile && supportDir { - return nil, errors.Errorf("both file and directory output is not supported by %s exporter", ex.Type) - } - if !supportFile && ex.Output != nil { - return nil, errors.Errorf("output file writer is not supported by %s exporter", ex.Type) - } - if !supportDir && ex.OutputDir != "" { - return nil, errors.Errorf("output directory is not supported by %s exporter", ex.Type) - } - - if supportFile { - if ex.Output == nil { - return nil, errors.Errorf("output file writer is required for %s exporter", ex.Type) - } - s.Allow(filesync.NewFSSyncTarget(ex.Output)) - } - if supportDir { - if ex.OutputDir == "" { - return nil, errors.Errorf("output directory is required for %s exporter", ex.Type) - } + var syncTargets []filesync.FSSyncTarget + for exID, ex := range opt.Exports { + var supportFile bool + var supportDir bool switch ex.Type { + case ExporterLocal: + supportDir = true + case ExporterTar: + supportFile = true case ExporterOCI, ExporterDocker: - if err := os.MkdirAll(ex.OutputDir, 0755); err != nil { - return nil, err + supportDir = ex.OutputDir != "" + supportFile = ex.Output != nil + } + if supportFile && supportDir { + return nil, errors.Errorf("both file and directory output is not supported by %s exporter", ex.Type) + } + if !supportFile && ex.Output != nil { + return nil, errors.Errorf("output file writer is not supported by %s exporter", ex.Type) + } + if !supportDir && ex.OutputDir != "" { + return nil, errors.Errorf("output directory is not supported by %s exporter", ex.Type) + } + if supportFile { + if ex.Output == nil { + return nil, errors.Errorf("output file writer is required for %s exporter", ex.Type) } - cs, err := contentlocal.NewStore(ex.OutputDir) - if err != nil { - return nil, err + syncTargets = append(syncTargets, filesync.WithFSSync(exID, ex.Output)) + } + if supportDir { + if ex.OutputDir == "" { + return nil, errors.Errorf("output directory is required for %s exporter", ex.Type) + } + switch ex.Type { + case ExporterOCI, ExporterDocker: + if err := os.MkdirAll(ex.OutputDir, 0755); err != nil { + return nil, err + } + cs, err := contentlocal.NewStore(ex.OutputDir) + if err != nil { + return nil, err + } + contentStores["export"] = cs + storesToUpdate = append(storesToUpdate, ex.OutputDir) + default: + syncTargets = append(syncTargets, filesync.WithFSSyncDir(exID, ex.OutputDir)) } - contentStores["export"] = cs - storesToUpdate = append(storesToUpdate, ex.OutputDir) - default: - s.Allow(filesync.NewFSSyncTargetDir(ex.OutputDir)) } } @@ -208,6 +206,10 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG s.Allow(sessioncontent.NewAttachable(contentStores)) } + if len(syncTargets) > 0 { + s.Allow(filesync.NewFSSyncTarget(syncTargets...)) + } + eg.Go(func() error { sd := c.sessionDialer if sd == nil { @@ -225,16 +227,16 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG frontendAttrs[k] = v } - solveCtx, cancelSolve := context.WithCancel(ctx) + solveCtx, cancelSolve := context.WithCancelCause(ctx) var res *SolveResponse eg.Go(func() error { ctx := solveCtx - defer cancelSolve() + defer cancelSolve(errors.WithStack(context.Canceled)) defer func() { // make sure the Status ends cleanly on build errors go func() { <-time.After(3 * time.Second) - cancelStatus() + cancelStatus(errors.WithStack(context.Canceled)) }() if !opt.SessionPreInitialized { bklog.G(ctx).Debugf("stopping session") @@ -255,19 +257,34 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG frontendInputs[key] = def.ToPB() } + exports := make([]*controlapi.Exporter, 0, len(opt.Exports)) + exportDeprecated := "" + exportAttrDeprecated := map[string]string{} + for i, exp := range opt.Exports { + if i == 0 { + exportDeprecated = exp.Type + exportAttrDeprecated = exp.Attrs + } + exports = append(exports, &controlapi.Exporter{ + Type: exp.Type, + Attrs: exp.Attrs, + }) + } + resp, err := c.ControlClient().Solve(ctx, &controlapi.SolveRequest{ - Ref: ref, - Definition: pbd, - Exporter: ex.Type, - ExporterAttrs: ex.Attrs, - Session: s.ID(), - Frontend: opt.Frontend, - FrontendAttrs: frontendAttrs, - FrontendInputs: frontendInputs, - Cache: cacheOpt.options, - Entitlements: opt.AllowedEntitlements, - Internal: opt.Internal, - SourcePolicy: opt.SourcePolicy, + Ref: ref, + Definition: pbd, + Exporters: exports, + ExporterDeprecated: exportDeprecated, + ExporterAttrsDeprecated: exportAttrDeprecated, + Session: s.ID(), + Frontend: opt.Frontend, + FrontendAttrs: frontendAttrs, + FrontendInputs: frontendInputs, + Cache: cacheOpt.options, + Entitlements: opt.AllowedEntitlements, + Internal: opt.Internal, + SourcePolicy: opt.SourcePolicy, }) if err != nil { return errors.Wrap(err, "failed to solve") @@ -293,7 +310,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG select { case <-solveCtx.Done(): case <-time.After(5 * time.Second): - cancelSolve() + cancelSolve(errors.WithStack(context.Canceled)) } return err @@ -361,26 +378,23 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG return res, nil } -func prepareSyncedDirs(def *llb.Definition, localDirs map[string]string) (filesync.StaticDirSource, error) { - for _, d := range localDirs { - fi, err := os.Stat(d) - if err != nil { - return nil, errors.Wrapf(err, "could not find %s", d) - } - if !fi.IsDir() { - return nil, errors.Errorf("%s not a directory", d) - } - } +func prepareSyncedFiles(def *llb.Definition, localMounts map[string]fsutil.FS) (filesync.StaticDirSource, error) { resetUIDAndGID := func(p string, st *fstypes.Stat) fsutil.MapResult { st.Uid = 0 st.Gid = 0 return fsutil.MapResultKeep } - dirs := make(filesync.StaticDirSource, len(localDirs)) + result := make(filesync.StaticDirSource, len(localMounts)) if def == nil { - for name, d := range localDirs { - dirs[name] = filesync.SyncedDir{Dir: d, Map: resetUIDAndGID} + for name, mount := range localMounts { + mount, err := fsutil.NewFilterFS(mount, &fsutil.FilterOpt{ + Map: resetUIDAndGID, + }) + if err != nil { + return nil, err + } + result[name] = mount } } else { for _, dt := range def.Def { @@ -391,16 +405,22 @@ func prepareSyncedDirs(def *llb.Definition, localDirs map[string]string) (filesy if src := op.GetSource(); src != nil { if strings.HasPrefix(src.Identifier, "local://") { name := strings.TrimPrefix(src.Identifier, "local://") - d, ok := localDirs[name] + mount, ok := localMounts[name] if !ok { return nil, errors.Errorf("local directory %s not enabled", name) } - dirs[name] = filesync.SyncedDir{Dir: d, Map: resetUIDAndGID} + mount, err := fsutil.NewFilterFS(mount, &fsutil.FilterOpt{ + Map: resetUIDAndGID, + }) + if err != nil { + return nil, err + } + result[name] = mount } } } } - return dirs, nil + return result, nil } func defaultSessionName() string { @@ -523,3 +543,22 @@ func parseCacheOptions(ctx context.Context, isGateway bool, opt SolveOpt) (*cach } return &res, nil } + +func prepareMounts(opt *SolveOpt) (map[string]fsutil.FS, error) { + // merge local mounts and fallback local directories together + mounts := make(map[string]fsutil.FS) + for k, mount := range opt.LocalMounts { + mounts[k] = mount + } + for k, dir := range opt.LocalDirs { + mount, err := fsutil.NewFS(dir) + if err != nil { + return nil, err + } + if _, ok := mounts[k]; ok { + return nil, errors.Errorf("local mount %s already exists", k) + } + mounts[k] = mount + } + return mounts, nil +} diff --git a/vendor/github.com/moby/buildkit/cmd/buildkitd/config/config.go b/vendor/github.com/moby/buildkit/cmd/buildkitd/config/config.go index a92588e53f979..9af4156f68de5 100644 --- a/vendor/github.com/moby/buildkit/cmd/buildkitd/config/config.go +++ b/vendor/github.com/moby/buildkit/cmd/buildkitd/config/config.go @@ -14,9 +14,15 @@ type Config struct { // Entitlements e.g. security.insecure, network.host Entitlements []string `toml:"insecure-entitlements"` + + // LogFormat is the format of the logs. It can be "json" or "text". + Log LogConfig `toml:"log"` + // GRPC configuration settings GRPC GRPCConfig `toml:"grpc"` + OTEL OTELConfig `toml:"otel"` + Workers struct { OCI OCIConfig `toml:"oci"` Containerd ContainerdConfig `toml:"containerd"` @@ -29,6 +35,10 @@ type Config struct { History *HistoryConfig `toml:"history"` } +type LogConfig struct { + Format string `toml:"format"` +} + type GRPCConfig struct { Address []string `toml:"address"` DebugAddress string `toml:"debugAddress"` @@ -46,6 +56,10 @@ type TLSConfig struct { CA string `toml:"ca"` } +type OTELConfig struct { + SocketPath string `toml:"socketPath"` +} + type GCConfig struct { GC *bool `toml:"gc"` GCKeepStorage DiskSpace `toml:"gckeepstorage"` @@ -57,6 +71,8 @@ type NetworkConfig struct { CNIConfigPath string `toml:"cniConfigPath"` CNIBinaryPath string `toml:"cniBinaryPath"` CNIPoolSize int `toml:"cniPoolSize"` + BridgeName string `toml:"bridgeName"` + BridgeSubnet string `toml:"bridgeSubnet"` } type OCIConfig struct { @@ -98,6 +114,7 @@ type ContainerdConfig struct { Labels map[string]string `toml:"labels"` Platforms []string `toml:"platforms"` Namespace string `toml:"namespace"` + Runtime ContainerdRuntime `toml:"runtime"` GCConfig NetworkConfig Snapshotter string `toml:"snapshotter"` @@ -114,6 +131,12 @@ type ContainerdConfig struct { Rootless bool `toml:"rootless"` } +type ContainerdRuntime struct { + Name string `toml:"name"` + Path string `toml:"path"` + Options map[string]interface{} `toml:"options"` +} + type GCPolicy struct { All bool `toml:"all"` KeepBytes DiskSpace `toml:"keepBytes"` diff --git a/vendor/github.com/moby/buildkit/control/control.go b/vendor/github.com/moby/buildkit/control/control.go index ce2b1e68c70d0..40058f8fe1f1c 100644 --- a/vendor/github.com/moby/buildkit/control/control.go +++ b/vendor/github.com/moby/buildkit/control/control.go @@ -11,7 +11,7 @@ import ( contentapi "github.com/containerd/containerd/api/services/content/v1" "github.com/containerd/containerd/content" "github.com/containerd/containerd/services/content/contentserver" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/hashicorp/go-multierror" "github.com/mitchellh/hashstructure/v2" controlapi "github.com/moby/buildkit/api/services/control" @@ -130,11 +130,12 @@ func (c *Controller) Close() error { if err := c.opt.WorkerController.Close(); err != nil { rerr = multierror.Append(rerr, err) } - if err := c.opt.CacheStore.Close(); err != nil { rerr = multierror.Append(rerr, err) } - + if err := c.solver.Close(); err != nil { + rerr = multierror.Append(rerr, err) + } return rerr } @@ -313,6 +314,7 @@ func translateLegacySolveRequest(req *controlapi.SolveRequest) { req.Cache.ExportRefDeprecated = "" req.Cache.ExportAttrsDeprecated = nil } + // translates ImportRefs to new Imports (v0.4.0) for _, legacyImportRef := range req.Cache.ImportRefsDeprecated { im := &controlapi.CacheOptionsEntry{ @@ -323,6 +325,16 @@ func translateLegacySolveRequest(req *controlapi.SolveRequest) { req.Cache.Imports = append(req.Cache.Imports, im) } req.Cache.ImportRefsDeprecated = nil + + // translate single exporter to a slice (v0.13.0) + if len(req.Exporters) == 0 && req.ExporterDeprecated != "" { + req.Exporters = append(req.Exporters, &controlapi.Exporter{ + Type: req.ExporterDeprecated, + Attrs: req.ExporterAttrsDeprecated, + }) + req.ExporterDeprecated = "" + req.ExporterAttrsDeprecated = nil + } } func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*controlapi.SolveResponse, error) { @@ -335,7 +347,6 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (* time.AfterFunc(time.Second, c.throttledGC) }() - var expi exporter.ExporterInstance // TODO: multiworker // This is actually tricky, as the exporter should come from the worker that has the returned reference. We may need to delay this so that the solver loads this. w, err := c.opt.WorkerController.GetDefault() @@ -343,25 +354,29 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (* return nil, err } - // if SOURCE_DATE_EPOCH is set, enable it for the exporter + // if SOURCE_DATE_EPOCH is set, enable it for the exporters if v, ok := epoch.ParseBuildArgs(req.FrontendAttrs); ok { - if _, ok := req.ExporterAttrs[string(exptypes.OptKeySourceDateEpoch)]; !ok { - if req.ExporterAttrs == nil { - req.ExporterAttrs = make(map[string]string) + for _, ex := range req.Exporters { + if _, ok := ex.Attrs[string(exptypes.OptKeySourceDateEpoch)]; !ok { + if ex.Attrs == nil { + ex.Attrs = make(map[string]string) + } + ex.Attrs[string(exptypes.OptKeySourceDateEpoch)] = v } - req.ExporterAttrs[string(exptypes.OptKeySourceDateEpoch)] = v } } - if req.Exporter != "" { - exp, err := w.Exporter(req.Exporter, c.opt.SessionManager) + var expis []exporter.ExporterInstance + for i, ex := range req.Exporters { + exp, err := w.Exporter(ex.Type, c.opt.SessionManager) if err != nil { return nil, err } - expi, err = exp.Resolve(ctx, req.ExporterAttrs) + expi, err := exp.Resolve(ctx, i, ex.Attrs) if err != nil { return nil, err } + expis = append(expis, expi) } if c, err := findDuplicateCacheOptions(req.Cache.Exports); err != nil { @@ -456,10 +471,8 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (* FrontendInputs: req.FrontendInputs, CacheImports: cacheImports, }, llbsolver.ExporterRequest{ - Exporter: expi, + Exporters: expis, CacheExporters: cacheExporters, - Type: req.Exporter, - Attrs: req.ExporterAttrs, }, req.Entitlements, procs, req.Internal, req.SourcePolicy) if err != nil { return nil, err @@ -508,10 +521,10 @@ func (c *Controller) Session(stream controlapi.Control_SessionServer) error { conn, closeCh, opts := grpchijack.Hijack(stream) defer conn.Close() - ctx, cancel := context.WithCancel(stream.Context()) + ctx, cancel := context.WithCancelCause(stream.Context()) go func() { <-closeCh - cancel() + cancel(errors.WithStack(context.Canceled)) }() err := c.opt.SessionManager.HandleConn(ctx, conn, opts) diff --git a/vendor/github.com/moby/buildkit/control/gateway/gateway.go b/vendor/github.com/moby/buildkit/control/gateway/gateway.go index 4451e022d322c..3012c1e269a1c 100644 --- a/vendor/github.com/moby/buildkit/control/gateway/gateway.go +++ b/vendor/github.com/moby/buildkit/control/gateway/gateway.go @@ -8,6 +8,7 @@ import ( "github.com/moby/buildkit/client/buildid" "github.com/moby/buildkit/frontend/gateway" gwapi "github.com/moby/buildkit/frontend/gateway/pb" + "github.com/moby/buildkit/solver/errdefs" "github.com/pkg/errors" "google.golang.org/grpc" ) @@ -58,8 +59,9 @@ func (gwf *GatewayForwarder) lookupForwarder(ctx context.Context) (gateway.LLBBr return nil, errors.New("no buildid found in context") } - ctx, cancel := context.WithTimeout(ctx, 3*time.Second) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + ctx, _ = context.WithTimeoutCause(ctx, 3*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) go func() { <-ctx.Done() @@ -73,7 +75,7 @@ func (gwf *GatewayForwarder) lookupForwarder(ctx context.Context) (gateway.LLBBr for { select { case <-ctx.Done(): - return nil, errors.Errorf("no such job %s", bid) + return nil, errdefs.NewUnknownJobError(bid) default: } fwd, ok := gwf.builds[bid] @@ -94,6 +96,15 @@ func (gwf *GatewayForwarder) ResolveImageConfig(ctx context.Context, req *gwapi. return fwd.ResolveImageConfig(ctx, req) } +func (gwf *GatewayForwarder) ResolveSourceMeta(ctx context.Context, req *gwapi.ResolveSourceMetaRequest) (*gwapi.ResolveSourceMetaResponse, error) { + fwd, err := gwf.lookupForwarder(ctx) + if err != nil { + return nil, errors.Wrap(err, "forwarding ResolveSourceMeta") + } + + return fwd.ResolveSourceMeta(ctx, req) +} + func (gwf *GatewayForwarder) Solve(ctx context.Context, req *gwapi.SolveRequest) (*gwapi.SolveResponse, error) { fwd, err := gwf.lookupForwarder(ctx) if err != nil { diff --git a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go index fa578c6d48fad..ccb22f06ec3e6 100644 --- a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go +++ b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go @@ -16,19 +16,13 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/mount" - containerdoci "github.com/containerd/containerd/oci" - "github.com/containerd/continuity/fs" - "github.com/docker/docker/pkg/idtools" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/executor/oci" resourcestypes "github.com/moby/buildkit/executor/resources/types" gatewayapi "github.com/moby/buildkit/frontend/gateway/pb" "github.com/moby/buildkit/identity" - "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/network" - rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -38,12 +32,13 @@ type containerdExecutor struct { networkProviders map[pb.NetMode]network.Provider cgroupParent string dnsConfig *oci.DNSConfig - running map[string]chan error + running map[string]*containerState mu sync.Mutex apparmorProfile string selinux bool traceSocket string rootless bool + runtime *RuntimeInfo } // OnCreateRuntimer provides an alternative to OCI hooks for applying network @@ -59,8 +54,14 @@ type OnCreateRuntimer interface { OnCreateRuntime(pid uint32) error } +type RuntimeInfo struct { + Name string + Path string + Options any +} + // New creates a new executor backed by connection to containerd API -func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string, selinux bool, traceSocket string, rootless bool) executor.Executor { +func New(client *containerd.Client, root, cgroup string, networkProviders map[pb.NetMode]network.Provider, dnsConfig *oci.DNSConfig, apparmorProfile string, selinux bool, traceSocket string, rootless bool, runtime *RuntimeInfo) executor.Executor { // clean up old hosts/resolv.conf file. ignore errors os.RemoveAll(filepath.Join(root, "hosts")) os.RemoveAll(filepath.Join(root, "resolv.conf")) @@ -71,14 +72,25 @@ func New(client *containerd.Client, root, cgroup string, networkProviders map[pb networkProviders: networkProviders, cgroupParent: cgroup, dnsConfig: dnsConfig, - running: make(map[string]chan error), + running: make(map[string]*containerState), apparmorProfile: apparmorProfile, selinux: selinux, traceSocket: traceSocket, rootless: rootless, + runtime: runtime, } } +type containerState struct { + done chan error + // On linux the rootfsPath is used to ensure the CWD exists, to fetch user information + // and as a bind mount for the root FS of the container. + rootfsPath string + // On Windows we need to use the root mounts to achieve the same thing that Linux does + // with rootfsPath. So we save both in details. + rootMounts []mount.Mount +} + func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.Mount, mounts []executor.Mount, process executor.ProcessInfo, started chan<- struct{}) (rec resourcestypes.Recorder, err error) { if id == "" { id = identity.NewID() @@ -86,8 +98,11 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M startedOnce := sync.Once{} done := make(chan error, 1) + details := &containerState{ + done: done, + } w.mu.Lock() - w.running[id] = done + w.running[id] = details w.mu.Unlock() defer func() { w.mu.Lock() @@ -103,96 +118,49 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M }() meta := process.Meta - - resolvConf, err := oci.GetResolvConf(ctx, w.root, nil, w.dnsConfig) - if err != nil { - return nil, err - } - - hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts, nil, meta.Hostname) - if err != nil { - return nil, err - } - if clean != nil { - defer clean() + if meta.NetMode == pb.NetMode_HOST { + bklog.G(ctx).Info("enabling HostNetworking") } - mountable, err := root.Src.Mount(ctx, false) - if err != nil { - return nil, err + provider, ok := w.networkProviders[meta.NetMode] + if !ok { + return nil, errors.Errorf("unknown network mode %s", meta.NetMode) } - rootMounts, release, err := mountable.Mount() + resolvConf, hostsFile, releasers, err := w.prepareExecutionEnv(ctx, root, mounts, meta, details, meta.NetMode) if err != nil { return nil, err } - if release != nil { - defer release() - } - lm := snapshot.LocalMounterWithMounts(rootMounts) - rootfsPath, err := lm.Mount() - if err != nil { - return nil, err + if releasers != nil { + defer releasers() } - defer lm.Unmount() - defer executor.MountStubsCleaner(ctx, rootfsPath, mounts, meta.RemoveMountStubsRecursive)() - uid, gid, sgids, err := oci.GetUser(rootfsPath, meta.User) - if err != nil { + if err := w.ensureCWD(ctx, details, meta); err != nil { return nil, err } - identity := idtools.Identity{ - UID: int(uid), - GID: int(gid), - } - - newp, err := fs.RootPath(rootfsPath, meta.Cwd) - if err != nil { - return nil, errors.Wrapf(err, "working dir %s points to invalid target", newp) - } - if _, err := os.Stat(newp); err != nil { - if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil { - return nil, errors.Wrapf(err, "failed to create working directory %s", newp) - } - } - - provider, ok := w.networkProviders[meta.NetMode] - if !ok { - return nil, errors.Errorf("unknown network mode %s", meta.NetMode) - } namespace, err := provider.New(ctx, meta.Hostname) if err != nil { return nil, err } defer namespace.Close() - if meta.NetMode == pb.NetMode_HOST { - bklog.G(ctx).Info("enabling HostNetworking") - } - - opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)} - if meta.ReadonlyRootFS { - opts = append(opts, containerdoci.WithRootFSReadonly()) - } - - processMode := oci.ProcessSandbox // FIXME(AkihiroSuda) - spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, processMode, nil, w.apparmorProfile, w.selinux, w.traceSocket, opts...) + spec, releaseSpec, err := w.createOCISpec(ctx, id, resolvConf, hostsFile, namespace, mounts, meta, details) if err != nil { return nil, err } - defer cleanup() - spec.Process.Terminal = meta.Tty - if w.rootless { - if err := rootlessspecconv.ToRootless(spec); err != nil { - return nil, err - } + if releaseSpec != nil { + defer releaseSpec() } - container, err := w.client.NewContainer(ctx, id, + opts := []containerd.NewContainerOpts{ containerd.WithSpec(spec), - ) + } + if w.runtime != nil { + opts = append(opts, containerd.WithRuntime(w.runtime.Name, w.runtime.Options)) + } + container, err := w.client.NewContainer(ctx, id, opts...) if err != nil { return nil, err } @@ -209,11 +177,14 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M cioOpts = append(cioOpts, cio.WithTerminal) } - task, err := container.NewTask(ctx, cio.NewCreator(cioOpts...), containerd.WithRootFS([]mount.Mount{{ - Source: rootfsPath, - Type: "bind", - Options: []string{"rbind"}, - }})) + taskOpts, err := details.getTaskOpts() + if err != nil { + return nil, err + } + if w.runtime != nil && w.runtime.Path != "" { + taskOpts = append(taskOpts, containerd.WithRuntimePath(w.runtime.Path)) + } + task, err := container.NewTask(ctx, cio.NewCreator(cioOpts...), taskOpts...) if err != nil { return nil, err } @@ -249,17 +220,16 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut // is in the process of being created and check again every 100ms or until // context is canceled. + w.mu.Lock() + details, ok := w.running[id] + w.mu.Unlock() + + if !ok { + return errors.Errorf("container %s not found", id) + } var container containerd.Container var task containerd.Task for { - w.mu.Lock() - done, ok := w.running[id] - w.mu.Unlock() - - if !ok { - return errors.Errorf("container %s not found", id) - } - if container == nil { container, _ = w.client.LoadContainer(ctx, id) } @@ -274,8 +244,8 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut } select { case <-ctx.Done(): - return ctx.Err() - case err, ok := <-done: + return context.Cause(ctx) + case err, ok := <-details.done: if !ok || err == nil { return errors.Errorf("container %s has stopped", id) } @@ -291,23 +261,20 @@ func (w *containerdExecutor) Exec(ctx context.Context, id string, process execut } proc := spec.Process - - // TODO how do we get rootfsPath for oci.GetUser in case user passed in username rather than uid:gid? - // For now only support uid:gid if meta.User != "" { - uid, gid, err := oci.ParseUIDGID(meta.User) + userSpec, err := getUserSpec(meta.User, details.rootfsPath) if err != nil { return errors.WithStack(err) } - proc.User = specs.User{ - UID: uid, - GID: gid, - AdditionalGids: []uint32{}, - } + proc.User = userSpec } proc.Terminal = meta.Tty - proc.Args = meta.Args + // setArgs will set the proper command line arguments for this process. + // On Windows, this will set the CommandLine field. On Linux it will set the + // Args field. + setArgs(proc, meta.Args) + if meta.Cwd != "" { spec.Process.Cwd = meta.Cwd } @@ -370,8 +337,8 @@ func (w *containerdExecutor) runProcess(ctx context.Context, p containerd.Proces // handle signals (and resize) in separate go loop so it does not // potentially block the container cancel/exit status loop below. - eventCtx, eventCancel := context.WithCancel(ctx) - defer eventCancel() + eventCtx, eventCancel := context.WithCancelCause(ctx) + defer eventCancel(errors.WithStack(context.Canceled)) go func() { for { select { @@ -405,7 +372,7 @@ func (w *containerdExecutor) runProcess(ctx context.Context, p containerd.Proces } }() - var cancel func() + var cancel func(error) var killCtxDone <-chan struct{} ctxDone := ctx.Done() for { @@ -413,13 +380,14 @@ func (w *containerdExecutor) runProcess(ctx context.Context, p containerd.Proces case <-ctxDone: ctxDone = nil var killCtx context.Context - killCtx, cancel = context.WithTimeout(context.Background(), 10*time.Second) + killCtx, cancel = context.WithCancelCause(context.Background()) + killCtx, _ = context.WithTimeoutCause(killCtx, 10*time.Second, errors.WithStack(context.DeadlineExceeded)) killCtxDone = killCtx.Done() p.Kill(killCtx, syscall.SIGKILL) io.Cancel() case status := <-statusCh: if cancel != nil { - cancel() + cancel(errors.WithStack(context.Canceled)) } trace.SpanFromContext(ctx).AddEvent( "Container exited", @@ -437,7 +405,7 @@ func (w *containerdExecutor) runProcess(ctx context.Context, p containerd.Proces } select { case <-ctx.Done(): - exitErr.Err = errors.Wrap(ctx.Err(), exitErr.Error()) + exitErr.Err = errors.Wrap(context.Cause(ctx), exitErr.Error()) default: } return exitErr @@ -445,7 +413,7 @@ func (w *containerdExecutor) runProcess(ctx context.Context, p containerd.Proces return nil case <-killCtxDone: if cancel != nil { - cancel() + cancel(errors.WithStack(context.Canceled)) } io.Cancel() return errors.Errorf("failed to kill process on cancel") diff --git a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_unix.go b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_unix.go new file mode 100644 index 0000000000000..229f360b3d026 --- /dev/null +++ b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_unix.go @@ -0,0 +1,183 @@ +//go:build !windows +// +build !windows + +package containerdexecutor + +import ( + "context" + "os" + "runtime" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/mount" + containerdoci "github.com/containerd/containerd/oci" + "github.com/containerd/continuity/fs" + "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/executor" + "github.com/moby/buildkit/executor/oci" + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/bklog" + "github.com/moby/buildkit/util/network" + rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +func getUserSpec(user, rootfsPath string) (specs.User, error) { + var err error + var uid, gid uint32 + var sgids []uint32 + if rootfsPath != "" { + uid, gid, sgids, err = oci.GetUser(rootfsPath, user) + } else { + uid, gid, err = oci.ParseUIDGID(user) + } + if err != nil { + return specs.User{}, errors.WithStack(err) + } + return specs.User{ + UID: uid, + GID: gid, + AdditionalGids: sgids, + }, nil +} + +func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount executor.Mount, mounts []executor.Mount, meta executor.Meta, details *containerState, netMode pb.NetMode) (string, string, func(), error) { + var releasers []func() + releaseAll := func() { + for i := len(releasers) - 1; i >= 0; i-- { + releasers[i]() + } + } + + resolvConf, err := oci.GetResolvConf(ctx, w.root, nil, w.dnsConfig, netMode) + if err != nil { + releaseAll() + return "", "", nil, err + } + + hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts, nil, meta.Hostname) + if err != nil { + releaseAll() + return "", "", nil, err + } + if clean != nil { + releasers = append(releasers, clean) + } + mountable, err := rootMount.Src.Mount(ctx, false) + if err != nil { + releaseAll() + return "", "", nil, err + } + + rootMounts, release, err := mountable.Mount() + if err != nil { + releaseAll() + return "", "", nil, err + } + details.rootMounts = rootMounts + + if release != nil { + releasers = append(releasers, func() { + if err := release(); err != nil { + bklog.G(ctx).WithError(err).Error("failed to release root mount") + } + }) + } + lm := snapshot.LocalMounterWithMounts(rootMounts) + rootfsPath, err := lm.Mount() + if err != nil { + releaseAll() + return "", "", nil, err + } + details.rootfsPath = rootfsPath + releasers = append(releasers, func() { + if err := lm.Unmount(); err != nil { + bklog.G(ctx).WithError(err).Error("failed to unmount rootfs") + } + }) + releasers = append(releasers, executor.MountStubsCleaner(ctx, details.rootfsPath, mounts, meta.RemoveMountStubsRecursive)) + + return resolvConf, hostsFile, releaseAll, nil +} + +func (w *containerdExecutor) ensureCWD(ctx context.Context, details *containerState, meta executor.Meta) error { + newp, err := fs.RootPath(details.rootfsPath, meta.Cwd) + if err != nil { + return errors.Wrapf(err, "working dir %s points to invalid target", newp) + } + + uid, gid, _, err := oci.GetUser(details.rootfsPath, meta.User) + if err != nil { + return err + } + + identity := idtools.Identity{ + UID: int(uid), + GID: int(gid), + } + + if _, err := os.Stat(newp); err != nil { + if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil { + return errors.Wrapf(err, "failed to create working directory %s", newp) + } + } + return nil +} + +func (w *containerdExecutor) createOCISpec(ctx context.Context, id, resolvConf, hostsFile string, namespace network.Namespace, mounts []executor.Mount, meta executor.Meta, details *containerState) (*specs.Spec, func(), error) { + var releasers []func() + releaseAll := func() { + for i := len(releasers) - 1; i >= 0; i-- { + releasers[i]() + } + } + + uid, gid, sgids, err := oci.GetUser(details.rootfsPath, meta.User) + if err != nil { + releaseAll() + return nil, nil, err + } + + opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)} + if meta.ReadonlyRootFS { + opts = append(opts, containerdoci.WithRootFSReadonly()) + } + + processMode := oci.ProcessSandbox // FIXME(AkihiroSuda) + spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.cgroupParent, processMode, nil, w.apparmorProfile, w.selinux, w.traceSocket, opts...) + if err != nil { + releaseAll() + return nil, nil, err + } + releasers = append(releasers, cleanup) + spec.Process.Terminal = meta.Tty + if w.rootless { + if err := rootlessspecconv.ToRootless(spec); err != nil { + releaseAll() + return nil, nil, err + } + } + return spec, releaseAll, nil +} + +func (d *containerState) getTaskOpts() ([]containerd.NewTaskOpts, error) { + rootfs := containerd.WithRootFS([]mount.Mount{{ + Source: d.rootfsPath, + Type: "bind", + Options: []string{"rbind"}, + }}) + if runtime.GOOS == "freebsd" { + rootfs = containerd.WithRootFS([]mount.Mount{{ + Source: d.rootfsPath, + Type: "nullfs", + Options: []string{}, + }}) + } + return []containerd.NewTaskOpts{rootfs}, nil +} + +func setArgs(spec *specs.Process, args []string) { + spec.Args = args +} diff --git a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_windows.go b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_windows.go new file mode 100644 index 0000000000000..1148b03885a8d --- /dev/null +++ b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor_windows.go @@ -0,0 +1,106 @@ +package containerdexecutor + +import ( + "context" + "os" + "strings" + + "github.com/containerd/containerd" + containerdoci "github.com/containerd/containerd/oci" + "github.com/containerd/continuity/fs" + "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/executor" + "github.com/moby/buildkit/executor/oci" + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/network" + "github.com/moby/buildkit/util/windows" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +func getUserSpec(user, rootfsPath string) (specs.User, error) { + return specs.User{ + Username: user, + }, nil +} + +func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount executor.Mount, mounts []executor.Mount, meta executor.Meta, details *containerState, netMode pb.NetMode) (string, string, func(), error) { + var releasers []func() error + releaseAll := func() { + for _, release := range releasers { + release() + } + } + + mountable, err := rootMount.Src.Mount(ctx, false) + if err != nil { + return "", "", releaseAll, err + } + + rootMounts, release, err := mountable.Mount() + if err != nil { + return "", "", releaseAll, err + } + details.rootMounts = rootMounts + releasers = append(releasers, release) + + return "", "", releaseAll, nil +} + +func (w *containerdExecutor) ensureCWD(ctx context.Context, details *containerState, meta executor.Meta) (err error) { + // TODO(gabriel-samfira): Use a snapshot? + identity, err := windows.ResolveUsernameToSID(ctx, w, details.rootMounts, meta.User) + if err != nil { + return errors.Wrap(err, "getting user SID") + } + + lm := snapshot.LocalMounterWithMounts(details.rootMounts) + rootfsPath, err := lm.Mount() + if err != nil { + return err + } + defer lm.Unmount() + + newp, err := fs.RootPath(rootfsPath, meta.Cwd) + if err != nil { + return errors.Wrapf(err, "working dir %s points to invalid target", newp) + } + + if _, err := os.Stat(newp); err != nil { + if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil { + return errors.Wrapf(err, "failed to create working directory %s", newp) + } + } + return nil +} + +func (w *containerdExecutor) createOCISpec(ctx context.Context, id, resolvConf, hostsFile string, namespace network.Namespace, mounts []executor.Mount, meta executor.Meta, details *containerState) (*specs.Spec, func(), error) { + var releasers []func() + releaseAll := func() { + for _, release := range releasers { + release() + } + } + + opts := []containerdoci.SpecOpts{ + containerdoci.WithUser(meta.User), + } + + processMode := oci.ProcessSandbox // FIXME(AkihiroSuda) + spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, "", "", namespace, "", processMode, nil, "", false, w.traceSocket, opts...) + if err != nil { + releaseAll() + return nil, nil, err + } + releasers = append(releasers, cleanup) + return spec, releaseAll, nil +} + +func (d *containerState) getTaskOpts() ([]containerd.NewTaskOpts, error) { + return []containerd.NewTaskOpts{containerd.WithRootFS(d.rootMounts)}, nil +} + +func setArgs(spec *specs.Process, args []string) { + spec.CommandLine = strings.Join(args, " ") +} diff --git a/vendor/github.com/moby/buildkit/executor/oci/mounts.go b/vendor/github.com/moby/buildkit/executor/oci/mounts.go index 50ed827497dbf..39e1da1537d1e 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/mounts.go +++ b/vendor/github.com/moby/buildkit/executor/oci/mounts.go @@ -24,30 +24,6 @@ func withRemovedMount(destination string) oci.SpecOpts { } } -func withROBind(src, dest string) oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Mounts = append(s.Mounts, specs.Mount{ - Destination: dest, - Type: "bind", - Source: src, - Options: []string{"nosuid", "noexec", "nodev", "rbind", "ro"}, - }) - return nil - } -} - -func withCGroup() oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Mounts = append(s.Mounts, specs.Mount{ - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Source: "cgroup", - Options: []string{"ro", "nosuid", "noexec", "nodev"}, - }) - return nil - } -} - func hasPrefix(p, prefixDir string) bool { prefixDir = filepath.Clean(prefixDir) if filepath.Base(prefixDir) == string(filepath.Separator) { @@ -57,49 +33,6 @@ func hasPrefix(p, prefixDir string) bool { return p == prefixDir || strings.HasPrefix(p, prefixDir+string(filepath.Separator)) } -func removeMountsWithPrefix(mounts []specs.Mount, prefixDir string) []specs.Mount { - var ret []specs.Mount - for _, m := range mounts { - if !hasPrefix(m.Destination, prefixDir) { - ret = append(ret, m) - } - } - return ret -} - -func withBoundProc() oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Mounts = removeMountsWithPrefix(s.Mounts, "/proc") - procMount := specs.Mount{ - Destination: "/proc", - Type: "bind", - Source: "/proc", - // NOTE: "rbind"+"ro" does not make /proc read-only recursively. - // So we keep maskedPath and readonlyPaths (although not mandatory for rootless mode) - Options: []string{"rbind"}, - } - s.Mounts = append([]specs.Mount{procMount}, s.Mounts...) - - var maskedPaths []string - for _, s := range s.Linux.MaskedPaths { - if !hasPrefix(s, "/proc") { - maskedPaths = append(maskedPaths, s) - } - } - s.Linux.MaskedPaths = maskedPaths - - var readonlyPaths []string - for _, s := range s.Linux.ReadonlyPaths { - if !hasPrefix(s, "/proc") { - readonlyPaths = append(readonlyPaths, s) - } - } - s.Linux.ReadonlyPaths = readonlyPaths - - return nil - } -} - func dedupMounts(mnts []specs.Mount) []specs.Mount { ret := make([]specs.Mount, 0, len(mnts)) visited := make(map[string]int) diff --git a/vendor/github.com/moby/buildkit/executor/oci/resolvconf.go b/vendor/github.com/moby/buildkit/executor/oci/resolvconf.go index 9db0b3dfaad6c..c52cd38bb4aa3 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/resolvconf.go +++ b/vendor/github.com/moby/buildkit/executor/oci/resolvconf.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/libnetwork/resolvconf" "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/flightcontrol" "github.com/pkg/errors" ) @@ -24,9 +25,13 @@ type DNSConfig struct { SearchDomains []string } -func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping, dns *DNSConfig) (string, error) { +func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping, dns *DNSConfig, netMode pb.NetMode) (string, error) { p := filepath.Join(stateDir, "resolv.conf") - _, err := g.Do(ctx, stateDir, func(ctx context.Context) (struct{}, error) { + if netMode == pb.NetMode_HOST { + p = filepath.Join(stateDir, "resolv-host.conf") + } + + _, err := g.Do(ctx, p, func(ctx context.Context) (struct{}, error) { generate := !notFirstRun notFirstRun = true @@ -65,7 +70,6 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity return struct{}{}, err } - var f *resolvconf.File tmpPath := p + ".tmp" if dns != nil { var ( @@ -83,19 +87,22 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity dnsOptions = resolvconf.GetOptions(dt) } - f, err = resolvconf.Build(tmpPath, dnsNameservers, dnsSearchDomains, dnsOptions) + f, err := resolvconf.Build(tmpPath, dnsNameservers, dnsSearchDomains, dnsOptions) if err != nil { return struct{}{}, err } dt = f.Content } - f, err = resolvconf.FilterResolvDNS(dt, true) - if err != nil { - return struct{}{}, err + if netMode != pb.NetMode_HOST || len(resolvconf.GetNameservers(dt, resolvconf.IP)) == 0 { + f, err := resolvconf.FilterResolvDNS(dt, true) + if err != nil { + return struct{}{}, err + } + dt = f.Content } - if err := os.WriteFile(tmpPath, f.Content, 0644); err != nil { + if err := os.WriteFile(tmpPath, dt, 0644); err != nil { return struct{}{}, err } diff --git a/vendor/github.com/moby/buildkit/executor/oci/spec.go b/vendor/github.com/moby/buildkit/executor/oci/spec.go index 544c68d9a96ac..ee62295eb1ffc 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/spec.go +++ b/vendor/github.com/moby/buildkit/executor/oci/spec.go @@ -4,6 +4,7 @@ import ( "context" "path" "path/filepath" + "runtime" "strings" "sync" @@ -124,7 +125,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou } opts = append(opts, - oci.WithProcessArgs(meta.Args...), + withProcessArgs(meta.Args...), oci.WithEnv(meta.Env), oci.WithProcessCwd(meta.Cwd), oci.WithNewPrivileges, @@ -196,7 +197,9 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou } if tracingSocket != "" { - s.Mounts = append(s.Mounts, getTracingSocketMount(tracingSocket)) + if mount := getTracingSocketMount(tracingSocket); mount != nil { + s.Mounts = append(s.Mounts, *mount) + } } s.Mounts = dedupMounts(s.Mounts) @@ -254,17 +257,24 @@ func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) return mount.Mount{}, err } - opts := []string{"rbind"} - for _, opt := range m.Options { - if opt == "ro" { - opts = append(opts, opt) - } + var mntType string + opts := []string{} + if m.ReadOnly() { + opts = append(opts, "ro") + } + + if runtime.GOOS != "windows" { + // Windows uses a mechanism similar to bind mounts, but will err out if we request + // a mount type it does not understand. Leaving the mount type empty on Windows will + // yield the same result. + mntType = "bind" + opts = append(opts, "rbind") } s.m[h] = mountRef{ mount: mount.Mount{ Source: mp, - Type: "bind", + Type: mntType, Options: opts, }, unmount: lm.Unmount, @@ -298,15 +308,3 @@ func (s *submounts) cleanup() { } wg.Wait() } - -func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping { - var ids []specs.LinuxIDMapping - for _, item := range s { - ids = append(ids, specs.LinuxIDMapping{ - HostID: uint32(item.HostID), - ContainerID: uint32(item.ContainerID), - Size: uint32(item.Size), - }) - } - return ids -} diff --git a/vendor/github.com/moby/buildkit/executor/oci/spec_freebsd.go b/vendor/github.com/moby/buildkit/executor/oci/spec_freebsd.go index 0810bc4288677..2623e25fc19e5 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/spec_freebsd.go +++ b/vendor/github.com/moby/buildkit/executor/oci/spec_freebsd.go @@ -2,9 +2,66 @@ package oci import ( "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/oci" "github.com/containerd/continuity/fs" + "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/solver/pb" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" ) +func withProcessArgs(args ...string) oci.SpecOpts { + return oci.WithProcessArgs(args...) +} + +func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) { + return nil, nil +} + +// generateSecurityOpts may affect mounts, so must be called after generateMountOpts +func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string, selinuxB bool) ([]oci.SpecOpts, error) { + if mode == pb.SecurityMode_INSECURE { + return nil, errors.New("no support for running in insecure mode on FreeBSD") + } + return nil, nil +} + +// generateProcessModeOpts may affect mounts, so must be called after generateMountOpts +func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) { + if mode == NoProcessSandbox { + return nil, errors.New("no support for NoProcessSandbox on FreeBSD") + } + return nil, nil +} + +func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) { + if idmap == nil { + return nil, nil + } + return nil, errors.New("no support for IdentityMapping on FreeBSD") +} + +func generateRlimitOpts(ulimits []*pb.Ulimit) ([]oci.SpecOpts, error) { + if len(ulimits) == 0 { + return nil, nil + } + return nil, errors.New("no support for POSIXRlimit on FreeBSD") +} + +// tracing is not implemented on FreeBSD +func getTracingSocketMount(socket string) *specs.Mount { + return nil +} + +// tracing is not implemented on FreeBSD +func getTracingSocket() string { + return "" +} + +func cgroupV2NamespaceSupported() bool { + return false +} + func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) { src, err := fs.RootPath(m.Source, subPath) if err != nil { diff --git a/vendor/github.com/moby/buildkit/executor/oci/spec_linux.go b/vendor/github.com/moby/buildkit/executor/oci/spec_linux.go index abbf0879d87ad..3860f5f5821b8 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/spec_linux.go +++ b/vendor/github.com/moby/buildkit/executor/oci/spec_linux.go @@ -1,19 +1,254 @@ -//go:build linux -// +build linux - package oci import ( + "context" + "fmt" "os" "strconv" + "strings" + "sync" + "github.com/containerd/containerd/containers" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/oci" + cdseccomp "github.com/containerd/containerd/pkg/seccomp" "github.com/containerd/continuity/fs" + "github.com/docker/docker/pkg/idtools" + "github.com/docker/docker/profiles/seccomp" "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/entitlements/security" + specs "github.com/opencontainers/runtime-spec/specs-go" + selinux "github.com/opencontainers/selinux/go-selinux" + "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" "golang.org/x/sys/unix" ) +var ( + cgroupNSOnce sync.Once + supportsCgroupNS bool +) + +const ( + tracingSocketPath = "/dev/otel-grpc.sock" +) + +func withProcessArgs(args ...string) oci.SpecOpts { + return oci.WithProcessArgs(args...) +} + +func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) { + return []oci.SpecOpts{ + // https://github.com/moby/buildkit/issues/429 + withRemovedMount("/run"), + withROBind(resolvConf, "/etc/resolv.conf"), + withROBind(hostsFile, "/etc/hosts"), + withCGroup(), + }, nil +} + +// generateSecurityOpts may affect mounts, so must be called after generateMountOpts +func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string, selinuxB bool) (opts []oci.SpecOpts, _ error) { + if selinuxB && !selinux.GetEnabled() { + return nil, errors.New("selinux is not available") + } + switch mode { + case pb.SecurityMode_INSECURE: + return []oci.SpecOpts{ + security.WithInsecureSpec(), + oci.WithWriteableCgroupfs, + oci.WithWriteableSysfs, + func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error { + var err error + if selinuxB { + s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels([]string{"disable"}) + } + return err + }, + }, nil + case pb.SecurityMode_SANDBOX: + if cdseccomp.IsEnabled() { + opts = append(opts, withDefaultProfile()) + } + if apparmorProfile != "" { + opts = append(opts, oci.WithApparmorProfile(apparmorProfile)) + } + opts = append(opts, func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error { + var err error + if selinuxB { + s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels(nil) + } + return err + }) + return opts, nil + } + return nil, nil +} + +// generateProcessModeOpts may affect mounts, so must be called after generateMountOpts +func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) { + if mode == NoProcessSandbox { + return []oci.SpecOpts{ + oci.WithHostNamespace(specs.PIDNamespace), + withBoundProc(), + }, nil + // TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly + } + return nil, nil +} + +func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) { + if idmap == nil { + return nil, nil + } + return []oci.SpecOpts{ + oci.WithUserNamespace(specMapping(idmap.UIDMaps), specMapping(idmap.GIDMaps)), + }, nil +} + +func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping { + var ids []specs.LinuxIDMapping + for _, item := range s { + ids = append(ids, specs.LinuxIDMapping{ + HostID: uint32(item.HostID), + ContainerID: uint32(item.ContainerID), + Size: uint32(item.Size), + }) + } + return ids +} + +func generateRlimitOpts(ulimits []*pb.Ulimit) ([]oci.SpecOpts, error) { + if len(ulimits) == 0 { + return nil, nil + } + var rlimits []specs.POSIXRlimit + for _, u := range ulimits { + if u == nil { + continue + } + rlimits = append(rlimits, specs.POSIXRlimit{ + Type: fmt.Sprintf("RLIMIT_%s", strings.ToUpper(u.Name)), + Hard: uint64(u.Hard), + Soft: uint64(u.Soft), + }) + } + return []oci.SpecOpts{ + func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Process.Rlimits = rlimits + return nil + }, + }, nil +} + +// withDefaultProfile sets the default seccomp profile to the spec. +// Note: must follow the setting of process capabilities +func withDefaultProfile() oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + var err error + s.Linux.Seccomp, err = seccomp.GetDefaultProfile(s) + return err + } +} + +func withROBind(src, dest string) oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Mounts = append(s.Mounts, specs.Mount{ + Destination: dest, + Type: "bind", + Source: src, + Options: []string{"nosuid", "noexec", "nodev", "rbind", "ro"}, + }) + return nil + } +} + +func withCGroup() oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Mounts = append(s.Mounts, specs.Mount{ + Destination: "/sys/fs/cgroup", + Type: "cgroup", + Source: "cgroup", + Options: []string{"ro", "nosuid", "noexec", "nodev"}, + }) + return nil + } +} + +func withBoundProc() oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Mounts = removeMountsWithPrefix(s.Mounts, "/proc") + procMount := specs.Mount{ + Destination: "/proc", + Type: "bind", + Source: "/proc", + // NOTE: "rbind"+"ro" does not make /proc read-only recursively. + // So we keep maskedPath and readonlyPaths (although not mandatory for rootless mode) + Options: []string{"rbind"}, + } + s.Mounts = append([]specs.Mount{procMount}, s.Mounts...) + + var maskedPaths []string + for _, s := range s.Linux.MaskedPaths { + if !hasPrefix(s, "/proc") { + maskedPaths = append(maskedPaths, s) + } + } + s.Linux.MaskedPaths = maskedPaths + + var readonlyPaths []string + for _, s := range s.Linux.ReadonlyPaths { + if !hasPrefix(s, "/proc") { + readonlyPaths = append(readonlyPaths, s) + } + } + s.Linux.ReadonlyPaths = readonlyPaths + + return nil + } +} + +func removeMountsWithPrefix(mounts []specs.Mount, prefixDir string) []specs.Mount { + var ret []specs.Mount + for _, m := range mounts { + if !hasPrefix(m.Destination, prefixDir) { + ret = append(ret, m) + } + } + return ret +} + +func getTracingSocketMount(socket string) *specs.Mount { + return &specs.Mount{ + Destination: tracingSocketPath, + Type: "bind", + Source: socket, + Options: []string{"ro", "rbind"}, + } +} + +func getTracingSocket() string { + return fmt.Sprintf("unix://%s", tracingSocketPath) +} + +func cgroupV2NamespaceSupported() bool { + // Check if cgroups v2 namespaces are supported. Trying to do cgroup + // namespaces with cgroups v1 results in EINVAL when we encounter a + // non-standard hierarchy. + // See https://github.com/moby/buildkit/issues/4108 + cgroupNSOnce.Do(func() { + if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + return + } + if _, err := os.Stat("/sys/fs/cgroup/cgroup.subtree_control"); os.IsNotExist(err) { + return + } + supportsCgroupNS = true + }) + return supportsCgroupNS +} + func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) { var retries = 10 root := m.Source diff --git a/vendor/github.com/moby/buildkit/executor/oci/spec_unix.go b/vendor/github.com/moby/buildkit/executor/oci/spec_unix.go deleted file mode 100644 index e38ef12caaac9..0000000000000 --- a/vendor/github.com/moby/buildkit/executor/oci/spec_unix.go +++ /dev/null @@ -1,165 +0,0 @@ -//go:build !windows -// +build !windows - -package oci - -import ( - "context" - "fmt" - "os" - "strings" - "sync" - - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" - cdseccomp "github.com/containerd/containerd/pkg/seccomp" - "github.com/docker/docker/pkg/idtools" - "github.com/docker/docker/profiles/seccomp" - "github.com/moby/buildkit/solver/pb" - "github.com/moby/buildkit/util/entitlements/security" - specs "github.com/opencontainers/runtime-spec/specs-go" - selinux "github.com/opencontainers/selinux/go-selinux" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" -) - -var ( - cgroupNSOnce sync.Once - supportsCgroupNS bool -) - -const ( - tracingSocketPath = "/dev/otel-grpc.sock" -) - -func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) { - return []oci.SpecOpts{ - // https://github.com/moby/buildkit/issues/429 - withRemovedMount("/run"), - withROBind(resolvConf, "/etc/resolv.conf"), - withROBind(hostsFile, "/etc/hosts"), - withCGroup(), - }, nil -} - -// generateSecurityOpts may affect mounts, so must be called after generateMountOpts -func generateSecurityOpts(mode pb.SecurityMode, apparmorProfile string, selinuxB bool) (opts []oci.SpecOpts, _ error) { - if selinuxB && !selinux.GetEnabled() { - return nil, errors.New("selinux is not available") - } - switch mode { - case pb.SecurityMode_INSECURE: - return []oci.SpecOpts{ - security.WithInsecureSpec(), - oci.WithWriteableCgroupfs, - oci.WithWriteableSysfs, - func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error { - var err error - if selinuxB { - s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels([]string{"disable"}) - } - return err - }, - }, nil - case pb.SecurityMode_SANDBOX: - if cdseccomp.IsEnabled() { - opts = append(opts, withDefaultProfile()) - } - if apparmorProfile != "" { - opts = append(opts, oci.WithApparmorProfile(apparmorProfile)) - } - opts = append(opts, func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error { - var err error - if selinuxB { - s.Process.SelinuxLabel, s.Linux.MountLabel, err = label.InitLabels(nil) - } - return err - }) - return opts, nil - } - return nil, nil -} - -// generateProcessModeOpts may affect mounts, so must be called after generateMountOpts -func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) { - if mode == NoProcessSandbox { - return []oci.SpecOpts{ - oci.WithHostNamespace(specs.PIDNamespace), - withBoundProc(), - }, nil - // TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly - } - return nil, nil -} - -func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) { - if idmap == nil { - return nil, nil - } - return []oci.SpecOpts{ - oci.WithUserNamespace(specMapping(idmap.UIDMaps), specMapping(idmap.GIDMaps)), - }, nil -} - -func generateRlimitOpts(ulimits []*pb.Ulimit) ([]oci.SpecOpts, error) { - if len(ulimits) == 0 { - return nil, nil - } - var rlimits []specs.POSIXRlimit - for _, u := range ulimits { - if u == nil { - continue - } - rlimits = append(rlimits, specs.POSIXRlimit{ - Type: fmt.Sprintf("RLIMIT_%s", strings.ToUpper(u.Name)), - Hard: uint64(u.Hard), - Soft: uint64(u.Soft), - }) - } - return []oci.SpecOpts{ - func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Process.Rlimits = rlimits - return nil - }, - }, nil -} - -// withDefaultProfile sets the default seccomp profile to the spec. -// Note: must follow the setting of process capabilities -func withDefaultProfile() oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - var err error - s.Linux.Seccomp, err = seccomp.GetDefaultProfile(s) - return err - } -} - -func getTracingSocketMount(socket string) specs.Mount { - return specs.Mount{ - Destination: tracingSocketPath, - Type: "bind", - Source: socket, - Options: []string{"ro", "rbind"}, - } -} - -func getTracingSocket() string { - return fmt.Sprintf("unix://%s", tracingSocketPath) -} - -func cgroupV2NamespaceSupported() bool { - // Check if cgroups v2 namespaces are supported. Trying to do cgroup - // namespaces with cgroups v1 results in EINVAL when we encounter a - // non-standard hierarchy. - // See https://github.com/moby/buildkit/issues/4108 - cgroupNSOnce.Do(func() { - if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { - return - } - if _, err := os.Stat("/sys/fs/cgroup/cgroup.subtree_control"); os.IsNotExist(err) { - return - } - supportsCgroupNS = true - }) - return supportsCgroupNS -} diff --git a/vendor/github.com/moby/buildkit/executor/oci/spec_windows.go b/vendor/github.com/moby/buildkit/executor/oci/spec_windows.go index 261bbb593084b..6f1436fd7776c 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/spec_windows.go +++ b/vendor/github.com/moby/buildkit/executor/oci/spec_windows.go @@ -4,9 +4,13 @@ package oci import ( + "context" "fmt" + "os" "path/filepath" + "strings" + "github.com/containerd/containerd/containers" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/oci" "github.com/containerd/continuity/fs" @@ -20,8 +24,37 @@ const ( tracingSocketPath = "//./pipe/otel-grpc" ) +func withProcessArgs(args ...string) oci.SpecOpts { + cmdLine := strings.Join(args, " ") + // This will set Args to nil and properly set the CommandLine option + // in the spec. On Windows we need to use CommandLine instead of Args. + return oci.WithProcessCommandLine(cmdLine) +} + +func withGetUserInfoMount() oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + execPath, err := os.Executable() + if err != nil { + return errors.Wrap(err, "getting executable path") + } + // The buildkit binary registers a re-exec function that is invoked when called with + // get-user-info as the name. We mount the binary as read-only inside the container. This + // spares us from having to ship a separate binary just for this purpose. The container does + // not share any state with the running buildkit daemon. In this scenario, we use the re-exec + // functionality to simulate a multi-call binary. + s.Mounts = append(s.Mounts, specs.Mount{ + Destination: "C:\\Windows\\System32\\get-user-info.exe", + Source: execPath, + Options: []string{"ro"}, + }) + return nil + } +} + func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) { - return nil, nil + return []oci.SpecOpts{ + withGetUserInfoMount(), + }, nil } // generateSecurityOpts may affect mounts, so must be called after generateMountOpts @@ -54,8 +87,8 @@ func generateRlimitOpts(ulimits []*pb.Ulimit) ([]oci.SpecOpts, error) { return nil, errors.New("no support for POSIXRlimit on Windows") } -func getTracingSocketMount(socket string) specs.Mount { - return specs.Mount{ +func getTracingSocketMount(socket string) *specs.Mount { + return &specs.Mount{ Destination: filepath.FromSlash(tracingSocketPath), Source: socket, Options: []string{"ro"}, diff --git a/vendor/github.com/moby/buildkit/executor/oci/user.go b/vendor/github.com/moby/buildkit/executor/oci/user.go index bb58e834f6346..9d0b81621a4e7 100644 --- a/vendor/github.com/moby/buildkit/executor/oci/user.go +++ b/vendor/github.com/moby/buildkit/executor/oci/user.go @@ -9,7 +9,7 @@ import ( "github.com/containerd/containerd/containers" containerdoci "github.com/containerd/containerd/oci" "github.com/containerd/continuity/fs" - "github.com/opencontainers/runc/libcontainer/user" + "github.com/moby/sys/user" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) diff --git a/vendor/github.com/moby/buildkit/executor/resources/monitor.go b/vendor/github.com/moby/buildkit/executor/resources/monitor.go index 95b954bcbe6f2..25a53f280671c 100644 --- a/vendor/github.com/moby/buildkit/executor/resources/monitor.go +++ b/vendor/github.com/moby/buildkit/executor/resources/monitor.go @@ -11,9 +11,9 @@ import ( "time" "github.com/moby/buildkit/executor/resources/types" + "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/network" "github.com/prometheus/procfs" - "github.com/sirupsen/logrus" ) const ( @@ -229,7 +229,7 @@ func NewMonitor() (*Monitor, error) { return } if err := prepareCgroupControllers(); err != nil { - logrus.Warnf("failed to prepare cgroup controllers: %+v", err) + bklog.L.Warnf("failed to prepare cgroup controllers: %+v", err) } }) @@ -280,7 +280,7 @@ func prepareCgroupControllers() error { } if err := os.WriteFile(filepath.Join(defaultMountpoint, cgroupSubtreeFile), []byte("+"+c), 0); err != nil { // ignore error - logrus.Warnf("failed to enable cgroup controller %q: %+v", c, err) + bklog.L.Warnf("failed to enable cgroup controller %q: %+v", c, err) } } return nil diff --git a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go index e804ee850b28f..b8662e51f6815 100644 --- a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go +++ b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go @@ -146,8 +146,6 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex } func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, mounts []executor.Mount, process executor.ProcessInfo, started chan<- struct{}) (rec resourcestypes.Recorder, err error) { - meta := process.Meta - startedOnce := sync.Once{} done := make(chan error, 1) w.mu.Lock() @@ -166,6 +164,11 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, } }() + meta := process.Meta + if meta.NetMode == pb.NetMode_HOST { + bklog.G(ctx).Info("enabling HostNetworking") + } + provider, ok := w.networkProviders[meta.NetMode] if !ok { return nil, errors.Errorf("unknown network mode %s", meta.NetMode) @@ -181,11 +184,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, } }() - if meta.NetMode == pb.NetMode_HOST { - bklog.G(ctx).Info("enabling HostNetworking") - } - - resolvConf, err := oci.GetResolvConf(ctx, w.root, w.idmap, w.dns) + resolvConf, err := oci.GetResolvConf(ctx, w.root, w.idmap, w.dns, meta.NetMode) if err != nil { return nil, err } @@ -369,7 +368,7 @@ func exitError(ctx context.Context, err error) error { ) select { case <-ctx.Done(): - exitErr.Err = errors.Wrapf(ctx.Err(), exitErr.Error()) + exitErr.Err = errors.Wrapf(context.Cause(ctx), exitErr.Error()) return exitErr default: return stack.Enable(exitErr) @@ -402,7 +401,7 @@ func (w *runcExecutor) Exec(ctx context.Context, id string, process executor.Pro } select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) case err, ok := <-done: if !ok || err == nil { return errors.Errorf("container %s has stopped", id) @@ -532,8 +531,9 @@ func (k procKiller) Kill(ctx context.Context) (err error) { // this timeout is generally a no-op, the Kill ctx should already have a // shorter timeout but here as a fail-safe for future refactoring. - ctx, timeout := context.WithTimeout(ctx, 10*time.Second) - defer timeout() + ctx, cancel := context.WithCancelCause(ctx) + ctx, _ = context.WithTimeoutCause(ctx, 10*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) if k.pidfile == "" { // for `runc run` process we use `runc kill` to terminate the process @@ -580,7 +580,7 @@ type procHandle struct { monitorProcess *os.Process ready chan struct{} ended chan struct{} - shutdown func() + shutdown func(error) // this this only used when the request context is canceled and we need // to kill the in-container process. killer procKiller @@ -594,7 +594,7 @@ type procHandle struct { // The goal is to allow for runc to gracefully shutdown when the request context // is cancelled. func runcProcessHandle(ctx context.Context, killer procKiller) (*procHandle, context.Context) { - runcCtx, cancel := context.WithCancel(context.Background()) + runcCtx, cancel := context.WithCancelCause(context.Background()) p := &procHandle{ ready: make(chan struct{}), ended: make(chan struct{}), @@ -615,17 +615,17 @@ func runcProcessHandle(ctx context.Context, killer procKiller) (*procHandle, con for { select { case <-ctx.Done(): - killCtx, timeout := context.WithTimeout(context.Background(), 7*time.Second) + killCtx, timeout := context.WithCancelCause(context.Background()) + killCtx, _ = context.WithTimeoutCause(killCtx, 7*time.Second, errors.WithStack(context.DeadlineExceeded)) if err := p.killer.Kill(killCtx); err != nil { select { case <-killCtx.Done(): - timeout() - cancel() + cancel(errors.WithStack(context.Cause(ctx))) return default: } } - timeout() + timeout(errors.WithStack(context.Canceled)) select { case <-time.After(50 * time.Millisecond): case <-p.ended: @@ -653,7 +653,7 @@ func (p *procHandle) Release() { // goroutines. func (p *procHandle) Shutdown() { if p.shutdown != nil { - p.shutdown() + p.shutdown(errors.WithStack(context.Canceled)) } } @@ -663,7 +663,7 @@ func (p *procHandle) Shutdown() { func (p *procHandle) WaitForReady(ctx context.Context) error { select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) case <-p.ready: return nil } @@ -673,10 +673,11 @@ func (p *procHandle) WaitForReady(ctx context.Context) error { // We wait for up to 10s for the runc pid to be reported. If the started // callback is non-nil it will be called after receiving the pid. func (p *procHandle) WaitForStart(ctx context.Context, startedCh <-chan int, started func()) error { - startedCtx, timeout := context.WithTimeout(ctx, 10*time.Second) - defer timeout() + ctx, cancel := context.WithCancelCause(ctx) + ctx, _ = context.WithTimeoutCause(ctx, 10*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) select { - case <-startedCtx.Done(): + case <-ctx.Done(): return errors.New("go-runc started message never received") case runcPid, ok := <-startedCh: if !ok { diff --git a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor_common.go b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor_common.go index 28955f9a45960..aa67e1e3f216c 100644 --- a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor_common.go +++ b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor_common.go @@ -14,13 +14,13 @@ import ( "golang.org/x/sync/errgroup" ) -var unsupportedConsoleError = errors.New("tty for runc is only supported on linux") +var errUnsupportedConsole = errors.New("tty for runc is only supported on linux") func updateRuncFieldsForHostOS(runtime *runc.Runc) {} func (w *runcExecutor) run(ctx context.Context, id, bundle string, process executor.ProcessInfo, started func(), keep bool) error { if process.Meta.Tty { - return unsupportedConsoleError + return errUnsupportedConsole } extraArgs := []string{} if keep { @@ -40,7 +40,7 @@ func (w *runcExecutor) run(ctx context.Context, id, bundle string, process execu func (w *runcExecutor) exec(ctx context.Context, id, bundle string, specsProcess *specs.Process, process executor.ProcessInfo, started func()) error { if process.Meta.Tty { - return unsupportedConsoleError + return errUnsupportedConsole } killer, err := newExecProcKiller(w.runc, id) diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/export.go b/vendor/github.com/moby/buildkit/exporter/containerimage/export.go index 2c2775ac7e4b8..b124f562bb35e 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/export.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/export.go @@ -12,6 +12,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/leases" "github.com/containerd/containerd/pkg/epoch" "github.com/containerd/containerd/platforms" @@ -63,9 +64,10 @@ func New(opt Opt) (exporter.Exporter, error) { return im, nil } -func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { +func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) { i := &imageExporterInstance{ imageExporter: e, + id: id, opts: ImageCommitOpts{ RefCfg: cacheconfig.RefConfig{ Compression: compression.New(compression.Default), @@ -166,6 +168,8 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp type imageExporterInstance struct { *imageExporter + id int + opts ImageCommitOpts push bool pushByDigest bool @@ -178,6 +182,10 @@ type imageExporterInstance struct { meta map[string][]byte } +func (e *imageExporterInstance) ID() int { + return e.id +} + func (e *imageExporterInstance) Name() string { return "exporting to image" } @@ -186,7 +194,8 @@ func (e *imageExporterInstance) Config() *exporter.Config { return exporter.NewConfigWithCompression(e.opts.RefCfg.Compression) } -func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) { +func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) { + src = src.Clone() if src.Metadata == nil { src.Metadata = make(map[string][]byte) } @@ -211,7 +220,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source } }() - desc, err := e.opt.ImageWriter.Commit(ctx, src, sessionID, &opts) + desc, err := e.opt.ImageWriter.Commit(ctx, src, sessionID, inlineCache, &opts) if err != nil { return nil, nil, err } @@ -273,6 +282,13 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source tagDone(nil) if e.unpack { + if opts.RewriteTimestamp { + // e.unpackImage cannot be used because src ref does not point to the rewritten image + /// + // TODO: change e.unpackImage so that it takes Result[Remote] as parameter. + // https://github.com/moby/buildkit/pull/4057#discussion_r1324106088 + return nil, nil, errors.New("exporter option \"rewrite-timestamp\" conflicts with \"unpack\"") + } if err := e.unpackImage(ctx, img, src, session.NewGroup(sessionID)); err != nil { return nil, nil, err } @@ -284,6 +300,9 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source refs = append(refs, src.Ref) } for _, ref := range src.Refs { + if ref == nil { + continue + } refs = append(refs, ref) } eg, ctx := errgroup.WithContext(ctx) @@ -309,7 +328,18 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source } } if e.push { - err := e.pushImage(ctx, src, sessionID, targetName, desc.Digest) + if opts.RewriteTimestamp { + annotations := map[digest.Digest]map[string]string{} + addAnnotations(annotations, *desc) + // e.pushImage cannot be used because src ref does not point to the rewritten image + // + // TODO: change e.pushImage so that it takes Result[Remote] as parameter. + // https://github.com/moby/buildkit/pull/4057#discussion_r1324106088 + err = push.Push(ctx, e.opt.SessionManager, sessionID, e.opt.ImageWriter.opt.ContentStore, e.opt.ImageWriter.ContentStore(), + desc.Digest, targetName, e.insecure, e.opt.RegistryHosts, e.pushByDigest, annotations) + } else { + err = e.pushImage(ctx, src, sessionID, targetName, desc.Digest) + } if err != nil { return nil, nil, errors.Wrapf(err, "failed to push %v", targetName) } @@ -339,6 +369,9 @@ func (e *imageExporterInstance) pushImage(ctx context.Context, src *exporter.Sou refs = append(refs, src.Ref) } for _, ref := range src.Refs { + if ref == nil { + continue + } refs = append(refs, ref) } @@ -454,7 +487,7 @@ func getLayers(ctx context.Context, descs []ocispecs.Descriptor, manifest ocispe for i, desc := range descs { layers[i].Diff = ocispecs.Descriptor{ MediaType: ocispecs.MediaTypeImageLayer, - Digest: digest.Digest(desc.Annotations["containerd.io/uncompressed"]), + Digest: digest.Digest(desc.Annotations[labels.LabelUncompressed]), } layers[i].Blob = manifest.Layers[i] } diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/keys.go b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/keys.go index c43221849911e..722f099cf0ce5 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/keys.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/keys.go @@ -72,4 +72,8 @@ var ( // Value: int (0-9) for gzip and estargz // Value: int (0-22) for zstd OptKeyCompressionLevel ImageExporterOptKey = "compression-level" + + // Rewrite timestamps in layers to match SOURCE_DATE_EPOCH + // Value: bool + OptKeyRewriteTimestamp ImageExporterOptKey = "rewrite-timestamp" ) diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/parse.go b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/parse.go index 6d01dc0f6e330..e8d9b7f0cb732 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/parse.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/parse.go @@ -60,10 +60,13 @@ func ParsePlatforms(meta map[string][]byte) (Platforms, error) { return ps, nil } -func ParseKey(meta map[string][]byte, key string, p Platform) []byte { - if v, ok := meta[fmt.Sprintf("%s/%s", key, p.ID)]; ok { - return v - } else if v, ok := meta[key]; ok { +func ParseKey(meta map[string][]byte, key string, p *Platform) []byte { + if p != nil { + if v, ok := meta[fmt.Sprintf("%s/%s", key, p.ID)]; ok { + return v + } + } + if v, ok := meta[key]; ok { return v } return nil diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go index c4d5721ea65dd..056485b66f126 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/exptypes/types.go @@ -1,6 +1,9 @@ package exptypes import ( + "context" + + "github.com/moby/buildkit/solver/result" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -10,7 +13,7 @@ const ( ExporterImageConfigKey = "containerimage.config" ExporterImageConfigDigestKey = "containerimage.config.digest" ExporterImageDescriptorKey = "containerimage.descriptor" - ExporterInlineCache = "containerimage.inlinecache" + ExporterImageBaseConfigKey = "containerimage.base.config" ExporterPlatformsKey = "refs.platforms" ) @@ -18,7 +21,7 @@ const ( // a platform to become platform specific var KnownRefMetadataKeys = []string{ ExporterImageConfigKey, - ExporterInlineCache, + ExporterImageBaseConfigKey, } type Platforms struct { @@ -29,3 +32,8 @@ type Platform struct { ID string Platform ocispecs.Platform } + +type InlineCacheEntry struct { + Data []byte +} +type InlineCache func(ctx context.Context) (*result.Result[*InlineCacheEntry], error) diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/image/docker_image.go b/vendor/github.com/moby/buildkit/exporter/containerimage/image/docker_image.go deleted file mode 100644 index 1af194b506dfb..0000000000000 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/image/docker_image.go +++ /dev/null @@ -1,52 +0,0 @@ -package image - -import ( - "time" - - "github.com/docker/docker/api/types/strslice" - ocispecs "github.com/opencontainers/image-spec/specs-go/v1" -) - -// HealthConfig holds configuration settings for the HEALTHCHECK feature. -type HealthConfig struct { - // Test is the test to perform to check that the container is healthy. - // An empty slice means to inherit the default. - // The options are: - // {} : inherit healthcheck - // {"NONE"} : disable healthcheck - // {"CMD", args...} : exec arguments directly - // {"CMD-SHELL", command} : run command with system's default shell - Test []string `json:",omitempty"` - - // Zero means to inherit. Durations are expressed as integer nanoseconds. - Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. - Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. - StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down. - StartInterval time.Duration `json:",omitempty"` // StartInterval is the time to wait between checks during the start period. - - // Retries is the number of consecutive failures needed to consider a container as unhealthy. - // Zero means inherit. - Retries int `json:",omitempty"` -} - -// ImageConfig is a docker compatible config for an image -type ImageConfig struct { - ocispecs.ImageConfig - - Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy - - // NetworkDisabled bool `json:",omitempty"` // Is network disabled - // MacAddress string `json:",omitempty"` // Mac Address of the container - OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile - StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container - Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT -} - -// Image is the JSON structure which describes some basic information about the image. -// This provides the `application/vnd.oci.image.config.v1+json` mediatype when marshalled to JSON. -type Image struct { - ocispecs.Image - - // Config defines the execution parameters which should be used as a base when running a container using the image. - Config ImageConfig `json:"config,omitempty"` -} diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/opts.go b/vendor/github.com/moby/buildkit/exporter/containerimage/opts.go index 791f268afda53..50ae5de311649 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/opts.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/opts.go @@ -21,6 +21,7 @@ type ImageCommitOpts struct { Epoch *time.Time ForceInlineAttestations bool // force inline attestations to be attached + RewriteTimestamp bool // rewrite timestamps in layers to match the epoch } func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[string]string, error) { @@ -52,6 +53,8 @@ func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[ err = parseBool(&c.ForceInlineAttestations, k, v) case exptypes.OptKeyPreferNondistLayers: err = parseBool(&c.RefCfg.PreferNonDistributable, k, v) + case exptypes.OptKeyRewriteTimestamp: + err = parseBool(&c.RewriteTimestamp, k, v) default: rest[k] = v } @@ -65,10 +68,6 @@ func (c *ImageCommitOpts) Load(ctx context.Context, opt map[string]string) (map[ c.EnableOCITypes(ctx, c.RefCfg.Compression.Type.String()) } - if c.RefCfg.Compression.Type.NeedsForceCompression() { - c.EnableForceCompression(ctx, c.RefCfg.Compression.Type.String()) - } - c.Annotations = c.Annotations.Merge(as) return rest, nil diff --git a/vendor/github.com/moby/buildkit/exporter/containerimage/writer.go b/vendor/github.com/moby/buildkit/exporter/containerimage/writer.go index c5575303810e0..822c250fc22bf 100644 --- a/vendor/github.com/moby/buildkit/exporter/containerimage/writer.go +++ b/vendor/github.com/moby/buildkit/exporter/containerimage/writer.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "reflect" "strconv" "strings" "time" @@ -12,6 +13,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/diff" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/platforms" intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/moby/buildkit/cache" @@ -27,10 +29,13 @@ import ( attestationTypes "github.com/moby/buildkit/util/attestation" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" + "github.com/moby/buildkit/util/contentutil" + "github.com/moby/buildkit/util/converter" "github.com/moby/buildkit/util/progress" "github.com/moby/buildkit/util/purl" "github.com/moby/buildkit/util/system" "github.com/moby/buildkit/util/tracing" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" digest "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -56,7 +61,7 @@ type ImageWriter struct { opt WriterOpt } -func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, sessionID string, opts *ImageCommitOpts) (*ocispecs.Descriptor, error) { +func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, sessionID string, inlineCache exptypes.InlineCache, opts *ImageCommitOpts) (*ocispecs.Descriptor, error) { if _, ok := inp.Metadata[exptypes.ExporterPlatformsKey]; len(inp.Refs) > 0 && !ok { return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping") } @@ -111,29 +116,59 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session } var ref cache.ImmutableRef - var p exptypes.Platform + var p *exptypes.Platform if len(ps.Platforms) > 0 { - p = ps.Platforms[0] + p = &ps.Platforms[0] if r, ok := inp.FindRef(p.ID); ok { ref = r } } else { ref = inp.Ref } + config := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageConfigKey, p) + baseImgConfig := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageBaseConfigKey, p) + var baseImg *dockerspec.DockerOCIImage + if len(baseImgConfig) > 0 { + var baseImgX dockerspec.DockerOCIImage + if err := json.Unmarshal(baseImgConfig, &baseImgX); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal base image config") + } + baseImg = &baseImgX + } remotes, err := ic.exportLayers(ctx, opts.RefCfg, session.NewGroup(sessionID), ref) if err != nil { return nil, err } + remote := &remotes[0] + if opts.RewriteTimestamp { + remote, err = ic.rewriteRemoteWithEpoch(ctx, opts, remote, baseImg) + if err != nil { + return nil, err + } + } annotations := opts.Annotations.Platform(nil) if len(annotations.Index) > 0 || len(annotations.IndexDescriptor) > 0 { return nil, errors.Errorf("index annotations not supported for single platform export") } - config := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageConfigKey, p) - inlineCache := exptypes.ParseKey(inp.Metadata, exptypes.ExporterInlineCache, p) - mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, opts, ref, config, &remotes[0], annotations, inlineCache, opts.Epoch, session.NewGroup(sessionID)) + var inlineCacheEntry *exptypes.InlineCacheEntry + if inlineCache != nil { + inlineCacheResult, err := inlineCache(ctx) + if err != nil { + return nil, err + } + if inlineCacheResult != nil { + if p != nil { + inlineCacheEntry, _ = inlineCacheResult.FindRef(p.ID) + } else { + inlineCacheEntry = inlineCacheResult.Ref + } + } + } + + mfstDesc, configDesc, err := ic.commitDistributionManifest(ctx, opts, ref, config, remote, annotations, inlineCacheEntry, opts.Epoch, session.NewGroup(sessionID), baseImg) if err != nil { return nil, err } @@ -168,6 +203,14 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session return nil, err } + var inlineCacheResult *result.Result[*exptypes.InlineCacheEntry] + if inlineCache != nil { + inlineCacheResult, err = inlineCache(ctx) + if err != nil { + return nil, err + } + } + idx := ocispecs.Index{ MediaType: ocispecs.MediaTypeImageIndex, Annotations: opts.Annotations.Platform(nil).Index, @@ -189,8 +232,16 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session if !ok { return nil, errors.Errorf("failed to find ref for ID %s", p.ID) } - config := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageConfigKey, p) - inlineCache := exptypes.ParseKey(inp.Metadata, exptypes.ExporterInlineCache, p) + config := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageConfigKey, &p) + baseImgConfig := exptypes.ParseKey(inp.Metadata, exptypes.ExporterImageBaseConfigKey, &p) + var baseImg *dockerspec.DockerOCIImage + if len(baseImgConfig) > 0 { + var baseImgX dockerspec.DockerOCIImage + if err := json.Unmarshal(baseImgConfig, &baseImgX); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal base image config") + } + baseImg = &baseImgX + } remote := &remotes[remotesMap[p.ID]] if remote == nil { @@ -198,8 +249,19 @@ func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, session Provider: ic.opt.ContentStore, } } + if opts.RewriteTimestamp { + remote, err = ic.rewriteRemoteWithEpoch(ctx, opts, remote, baseImg) + if err != nil { + return nil, err + } + } - desc, _, err := ic.commitDistributionManifest(ctx, opts, r, config, remote, opts.Annotations.Platform(&p.Platform), inlineCache, opts.Epoch, session.NewGroup(sessionID)) + var inlineCacheEntry *exptypes.InlineCacheEntry + if inlineCacheResult != nil { + inlineCacheEntry, _ = inlineCacheResult.FindRef(p.ID) + } + + desc, _, err := ic.commitDistributionManifest(ctx, opts, r, config, remote, opts.Annotations.Platform(&p.Platform), inlineCacheEntry, opts.Epoch, session.NewGroup(sessionID), baseImg) if err != nil { return nil, err } @@ -323,7 +385,74 @@ func (ic *ImageWriter) exportLayers(ctx context.Context, refCfg cacheconfig.RefC return out, err } -func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *ImageCommitOpts, ref cache.ImmutableRef, config []byte, remote *solver.Remote, annotations *Annotations, inlineCache []byte, epoch *time.Time, sg session.Group) (*ocispecs.Descriptor, *ocispecs.Descriptor, error) { +// rewriteImageLayerWithEpoch rewrites the file timestamps in the layer blob to match the epoch, and returns a new descriptor that points to +// the new blob. +// +// If no conversion is needed, this returns nil without error. +func rewriteImageLayerWithEpoch(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config, epoch *time.Time, immDiffID digest.Digest) (*ocispecs.Descriptor, error) { + var immDiffIDs map[digest.Digest]struct{} + if immDiffID != "" { + immDiffIDs = map[digest.Digest]struct{}{ + immDiffID: {}, + } + } + converterFn, err := converter.NewWithRewriteTimestamp(ctx, cs, desc, comp, epoch, immDiffIDs) + if err != nil { + return nil, err + } + if converterFn == nil { + return nil, nil + } + return converterFn(ctx, cs, desc) +} + +func (ic *ImageWriter) rewriteRemoteWithEpoch(ctx context.Context, opts *ImageCommitOpts, remote *solver.Remote, baseImg *dockerspec.DockerOCIImage) (*solver.Remote, error) { + if opts.Epoch == nil { + bklog.G(ctx).Warn("rewrite-timestamp is specified, but no source-date-epoch was found") + return remote, nil + } + remoteDescriptors := remote.Descriptors + cs := contentutil.NewStoreWithProvider(ic.opt.ContentStore, remote.Provider) + eg, ctx := errgroup.WithContext(ctx) + rewriteDone := progress.OneOff(ctx, + fmt.Sprintf("rewriting layers with source-date-epoch %d (%s)", opts.Epoch.Unix(), opts.Epoch.String())) + var divergedFromBase bool + for i, desc := range remoteDescriptors { + i, desc := i, desc + info, err := cs.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + diffID := digest.Digest(info.Labels[labels.LabelUncompressed]) // can be empty + var immDiffID digest.Digest + if !divergedFromBase && baseImg != nil && i < len(baseImg.RootFS.DiffIDs) { + immDiffID = baseImg.RootFS.DiffIDs[i] + if immDiffID == diffID { + bklog.G(ctx).WithField("blob", desc).Debugf("Not rewriting to apply epoch (immutable diffID %q)", diffID) + continue + } + divergedFromBase = true + } + eg.Go(func() error { + if rewrittenDesc, err := rewriteImageLayerWithEpoch(ctx, cs, desc, opts.RefCfg.Compression, opts.Epoch, immDiffID); err != nil { + bklog.G(ctx).WithError(err).Warnf("failed to rewrite layer %d/%d to match source-date-epoch %d (%s)", + i+1, len(remoteDescriptors), opts.Epoch.Unix(), opts.Epoch.String()) + } else if rewrittenDesc != nil { + remoteDescriptors[i] = *rewrittenDesc + } + return nil + }) + } + if err := rewriteDone(eg.Wait()); err != nil { + return nil, err + } + return &solver.Remote{ + Provider: cs, + Descriptors: remoteDescriptors, + }, nil +} + +func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *ImageCommitOpts, ref cache.ImmutableRef, config []byte, remote *solver.Remote, annotations *Annotations, inlineCache *exptypes.InlineCacheEntry, epoch *time.Time, sg session.Group, baseImg *dockerspec.DockerOCIImage) (*ocispecs.Descriptor, *ocispecs.Descriptor, error) { if len(config) == 0 { var err error config, err = defaultImageConfig() @@ -342,7 +471,7 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, opts *Ima return nil, nil, err } - config, err = patchImageConfig(config, remote.Descriptors, history, inlineCache, epoch) + config, err = patchImageConfig(config, remote.Descriptors, history, inlineCache, epoch, baseImg) if err != nil { return nil, nil, err } @@ -443,8 +572,8 @@ func (ic *ImageWriter) commitAttestationsManifest(ctx context.Context, opts *Ima Digest: digest, Size: int64(len(data)), Annotations: map[string]string{ - "containerd.io/uncompressed": digest.String(), - "in-toto.io/predicate-type": statement.PredicateType, + labels.LabelUncompressed: digest.String(), + "in-toto.io/predicate-type": statement.PredicateType, }, } @@ -535,6 +664,8 @@ func defaultImageConfig() ([]byte, error) { img := ocispecs.Image{} img.Architecture = pl.Architecture img.OS = pl.OS + img.OSVersion = pl.OSVersion + img.OSFeatures = pl.OSFeatures img.Variant = pl.Variant img.RootFS.Type = "layers" img.Config.WorkingDir = "/" @@ -552,7 +683,7 @@ func attestationsConfig(layers []ocispecs.Descriptor) ([]byte, error) { img.Variant = intotoPlatform.Variant img.RootFS.Type = "layers" for _, layer := range layers { - img.RootFS.DiffIDs = append(img.RootFS.DiffIDs, digest.Digest(layer.Annotations["containerd.io/uncompressed"])) + img.RootFS.DiffIDs = append(img.RootFS.DiffIDs, digest.Digest(layer.Annotations[labels.LabelUncompressed])) } dt, err := json.Marshal(img) return dt, errors.Wrap(err, "failed to create attestations image config") @@ -568,7 +699,7 @@ func parseHistoryFromConfig(dt []byte) ([]ocispecs.History, error) { return config.History, nil } -func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs.History, cache []byte, epoch *time.Time) ([]byte, error) { +func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs.History, cache *exptypes.InlineCacheEntry, epoch *time.Time, baseImg *dockerspec.DockerOCIImage) ([]byte, error) { var img ocispecs.Image if err := json.Unmarshal(dt, &img); err != nil { return nil, errors.Wrap(err, "invalid image config for export") @@ -593,7 +724,7 @@ func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs var rootFS ocispecs.RootFS rootFS.Type = "layers" for _, desc := range descs { - rootFS.DiffIDs = append(rootFS.DiffIDs, digest.Digest(desc.Annotations["containerd.io/uncompressed"])) + rootFS.DiffIDs = append(rootFS.DiffIDs, digest.Digest(desc.Annotations[labels.LabelUncompressed])) } dt, err := json.Marshal(rootFS) if err != nil { @@ -602,7 +733,14 @@ func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs m["rootfs"] = dt if epoch != nil { + var divergedFromBase bool for i, h := range history { + if !divergedFromBase && baseImg != nil && i < len(baseImg.History) && reflect.DeepEqual(h, baseImg.History[i]) { + // Retain the timestamp for the base image layers + // https://github.com/moby/buildkit/issues/4614 + continue + } + divergedFromBase = true if h.Created == nil || h.Created.After(*epoch) { history[i].Created = epoch } @@ -645,7 +783,7 @@ func patchImageConfig(dt []byte, descs []ocispecs.Descriptor, history []ocispecs } if cache != nil { - dt, err := json.Marshal(cache) + dt, err := json.Marshal(cache.Data) if err != nil { return nil, err } @@ -751,7 +889,7 @@ func RemoveInternalLayerAnnotations(in map[string]string, oci bool) map[string]s for k, v := range in { // oci supports annotations but don't export internal annotations switch k { - case "containerd.io/uncompressed", "buildkit/createdat": + case labels.LabelUncompressed, "buildkit/createdat": continue default: if strings.HasPrefix(k, "containerd.io/distribution.source.") { diff --git a/vendor/github.com/moby/buildkit/exporter/exporter.go b/vendor/github.com/moby/buildkit/exporter/exporter.go index 0e7d8d14f280f..bbaf4b8a49a0b 100644 --- a/vendor/github.com/moby/buildkit/exporter/exporter.go +++ b/vendor/github.com/moby/buildkit/exporter/exporter.go @@ -4,6 +4,7 @@ import ( "context" "github.com/moby/buildkit/cache" + "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/solver/result" "github.com/moby/buildkit/util/compression" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -14,13 +15,14 @@ type Source = result.Result[cache.ImmutableRef] type Attestation = result.Attestation[cache.ImmutableRef] type Exporter interface { - Resolve(context.Context, map[string]string) (ExporterInstance, error) + Resolve(context.Context, int, map[string]string) (ExporterInstance, error) } type ExporterInstance interface { + ID() int Name() string Config() *Config - Export(ctx context.Context, src *Source, sessionID string) (map[string]string, DescriptorReference, error) + Export(ctx context.Context, src *Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, DescriptorReference, error) } type DescriptorReference interface { diff --git a/vendor/github.com/moby/buildkit/exporter/local/export.go b/vendor/github.com/moby/buildkit/exporter/local/export.go index 771b7aaf22526..b6fa6866cb968 100644 --- a/vendor/github.com/moby/buildkit/exporter/local/export.go +++ b/vendor/github.com/moby/buildkit/exporter/local/export.go @@ -35,8 +35,9 @@ func New(opt Opt) (exporter.Exporter, error) { return le, nil } -func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { +func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) { i := &localExporterInstance{ + id: id, localExporter: e, } _, err := i.opts.Load(opt) @@ -49,9 +50,15 @@ func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exp type localExporterInstance struct { *localExporter + id int + opts CreateFSOpts } +func (e *localExporterInstance) ID() int { + return e.id +} + func (e *localExporterInstance) Name() string { return "exporting to client directory" } @@ -60,9 +67,10 @@ func (e *localExporter) Config() *exporter.Config { return exporter.NewConfig() } -func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, exporter.DescriptorReference, error) { - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() +func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, _ exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) { + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) if e.opts.Epoch == nil { if tm, ok, err := epoch.ParseSource(inp); err != nil { @@ -108,8 +116,8 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source if !e.opts.PlatformSplit { // check for duplicate paths - err = outputFS.Walk(ctx, func(p string, fi os.FileInfo, err error) error { - if fi.IsDir() { + err = outputFS.Walk(ctx, "", func(p string, entry os.DirEntry, err error) error { + if entry.IsDir() { return nil } if err != nil && !errors.Is(err, os.ErrNotExist) { @@ -147,7 +155,7 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source } progress := NewProgressHandler(ctx, lbl) - if err := filesync.CopyToCaller(ctx, outputFS, caller, progress); err != nil { + if err := filesync.CopyToCaller(ctx, outputFS, e.id, caller, progress); err != nil { return err } return nil diff --git a/vendor/github.com/moby/buildkit/exporter/local/fs.go b/vendor/github.com/moby/buildkit/exporter/local/fs.go index d8e4703ac1462..b24d6aacda7a7 100644 --- a/vendor/github.com/moby/buildkit/exporter/local/fs.go +++ b/vendor/github.com/moby/buildkit/exporter/local/fs.go @@ -98,9 +98,14 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab cleanup = lm.Unmount } - walkOpt := &fsutil.WalkOpt{} - var idMapFunc func(p string, st *fstypes.Stat) fsutil.MapResult + outputFS, err := fsutil.NewFS(src) + if err != nil { + return nil, nil, err + } + // wrap the output filesystem, applying appropriate filters + filterOpt := &fsutil.FilterOpt{} + var idMapFunc func(p string, st *fstypes.Stat) fsutil.MapResult if idmap != nil { idMapFunc = func(p string, st *fstypes.Stat) fsutil.MapResult { uid, gid, err := idmap.ToContainer(idtools.Identity{ @@ -115,19 +120,23 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab return fsutil.MapResultKeep } } - - walkOpt.Map = func(p string, st *fstypes.Stat) fsutil.MapResult { + filterOpt.Map = func(p string, st *fstypes.Stat) fsutil.MapResult { res := fsutil.MapResultKeep if idMapFunc != nil { + // apply host uid/gid res = idMapFunc(p, st) } if opt.Epoch != nil { + // apply used-specified epoch time st.ModTime = opt.Epoch.UnixNano() } return res } + outputFS, err = fsutil.NewFilterFS(outputFS, filterOpt) + if err != nil { + return nil, nil, err + } - outputFS := fsutil.NewFS(src, walkOpt) attestations = attestation.Filter(attestations, nil, map[string][]byte{ result.AttestationInlineOnlyKey: []byte(strconv.FormatBool(true)), }) @@ -137,11 +146,11 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab } if len(attestations) > 0 { subjects := []intoto.Subject{} - err = outputFS.Walk(ctx, func(path string, info fs.FileInfo, err error) error { + err = outputFS.Walk(ctx, "", func(path string, entry fs.DirEntry, err error) error { if err != nil { return err } - if !info.Mode().IsRegular() { + if !entry.Type().IsRegular() { return nil } f, err := outputFS.Open(path) diff --git a/vendor/github.com/moby/buildkit/exporter/oci/export.go b/vendor/github.com/moby/buildkit/exporter/oci/export.go index 81ac7857deb80..3748f536caa4c 100644 --- a/vendor/github.com/moby/buildkit/exporter/oci/export.go +++ b/vendor/github.com/moby/buildkit/exporter/oci/export.go @@ -11,7 +11,7 @@ import ( archiveexporter "github.com/containerd/containerd/images/archive" "github.com/containerd/containerd/leases" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/moby/buildkit/cache" cacheconfig "github.com/moby/buildkit/cache/config" "github.com/moby/buildkit/exporter" @@ -58,9 +58,10 @@ func New(opt Opt) (exporter.Exporter, error) { return im, nil } -func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { +func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) { i := &imageExporterInstance{ imageExporter: e, + id: id, tar: true, opts: containerimage.ImageCommitOpts{ RefCfg: cacheconfig.RefConfig{ @@ -99,11 +100,17 @@ func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exp type imageExporterInstance struct { *imageExporter + id int + opts containerimage.ImageCommitOpts tar bool meta map[string][]byte } +func (e *imageExporterInstance) ID() int { + return e.id +} + func (e *imageExporterInstance) Name() string { return fmt.Sprintf("exporting to %s image format", e.opt.Variant) } @@ -112,11 +119,12 @@ func (e *imageExporterInstance) Config() *exporter.Config { return exporter.NewConfigWithCompression(e.opts.RefCfg.Compression) } -func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) { +func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (_ map[string]string, descref exporter.DescriptorReference, err error) { if e.opt.Variant == VariantDocker && len(src.Refs) > 0 { return nil, nil, errors.Errorf("docker exporter does not currently support exporting manifest lists") } + src = src.Clone() if src.Metadata == nil { src.Metadata = make(map[string][]byte) } @@ -141,7 +149,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source } }() - desc, err := e.opt.ImageWriter.Commit(ctx, src, sessionID, &opts) + desc, err := e.opt.ImageWriter.Commit(ctx, src, sessionID, inlineCache, &opts) if err != nil { return nil, nil, err } @@ -198,8 +206,9 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source return nil, nil, errors.Errorf("invalid variant %q", e.opt.Variant) } - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) caller, err := e.opt.SessionManager.Get(timeoutCtx, sessionID, false) if err != nil { @@ -239,7 +248,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source } if e.tar { - w, err := filesync.CopyFileWriter(ctx, resp, caller) + w, err := filesync.CopyFileWriter(ctx, resp, e.id, caller) if err != nil { return nil, nil, err } diff --git a/vendor/github.com/moby/buildkit/exporter/tar/export.go b/vendor/github.com/moby/buildkit/exporter/tar/export.go index 7259f6b24a9ab..4f6afbd24f24b 100644 --- a/vendor/github.com/moby/buildkit/exporter/tar/export.go +++ b/vendor/github.com/moby/buildkit/exporter/tar/export.go @@ -33,8 +33,11 @@ func New(opt Opt) (exporter.Exporter, error) { return le, nil } -func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) { - li := &localExporterInstance{localExporter: e} +func (e *localExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) { + li := &localExporterInstance{ + localExporter: e, + id: id, + } _, err := li.opts.Load(opt) if err != nil { return nil, err @@ -46,9 +49,15 @@ func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exp type localExporterInstance struct { *localExporter + id int + opts local.CreateFSOpts } +func (e *localExporterInstance) ID() int { + return e.id +} + func (e *localExporterInstance) Name() string { return "exporting to client tarball" } @@ -57,7 +66,7 @@ func (e *localExporterInstance) Config() *exporter.Config { return exporter.NewConfig() } -func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, exporter.DescriptorReference, error) { +func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source, _ exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) { var defers []func() error defer func() { @@ -143,15 +152,16 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source fs = d.FS } - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) caller, err := e.opt.SessionManager.Get(timeoutCtx, sessionID, false) if err != nil { return nil, nil, err } - w, err := filesync.CopyFileWriter(ctx, nil, caller) + w, err := filesync.CopyFileWriter(ctx, nil, e.id, caller) if err != nil { return nil, nil, err } diff --git a/vendor/github.com/moby/buildkit/frontend/attestations/sbom/sbom.go b/vendor/github.com/moby/buildkit/frontend/attestations/sbom/sbom.go index c52229c2843cd..6e90cfdd280c9 100644 --- a/vendor/github.com/moby/buildkit/frontend/attestations/sbom/sbom.go +++ b/vendor/github.com/moby/buildkit/frontend/attestations/sbom/sbom.go @@ -9,6 +9,7 @@ import ( intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" gatewaypb "github.com/moby/buildkit/frontend/gateway/pb" "github.com/moby/buildkit/solver/result" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -33,12 +34,13 @@ const ( // attestation. type Scanner func(ctx context.Context, name string, ref llb.State, extras map[string]llb.State, opts ...llb.ConstraintsOpt) (result.Attestation[*llb.State], error) -func CreateSBOMScanner(ctx context.Context, resolver llb.ImageMetaResolver, scanner string, resolveOpt llb.ResolveImageConfigOpt) (Scanner, error) { +func CreateSBOMScanner(ctx context.Context, resolver sourceresolver.MetaResolver, scanner string, resolveOpt sourceresolver.Opt) (Scanner, error) { if scanner == "" { return nil, nil } - scanner, _, dt, err := resolver.ResolveImageConfig(ctx, scanner, resolveOpt) + imr := sourceresolver.NewImageMetaResolver(resolver) + scanner, _, dt, err := imr.ResolveImageConfig(ctx, scanner, resolveOpt) if err != nil { return nil, err } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go index 40ab3de2c08f8..fc6c29efb7930 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go @@ -7,7 +7,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/moby/buildkit/client/llb" - "github.com/moby/buildkit/exporter/containerimage/image" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/frontend" "github.com/moby/buildkit/frontend/attestations/sbom" "github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb" @@ -20,6 +20,7 @@ import ( "github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/result" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -93,14 +94,19 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { defer func() { var el *parser.ErrorLocation if errors.As(err, &el) { - err = wrapSource(err, src.SourceMap, el.Location) + for _, l := range el.Locations { + err = wrapSource(err, src.SourceMap, l) + } } }() var scanner sbom.Scanner if bc.SBOM != nil { - scanner, err = sbom.CreateSBOMScanner(ctx, c, bc.SBOM.Generator, llb.ResolveImageConfigOpt{ - ResolveMode: opts["image-resolve-mode"], + // TODO: scanner should pass policy + scanner, err = sbom.CreateSBOMScanner(ctx, c, bc.SBOM.Generator, sourceresolver.Opt{ + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: opts["image-resolve-mode"], + }, }) if err != nil { return nil, err @@ -109,21 +115,21 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { scanTargets := sync.Map{} - rb, err := bc.Build(ctx, func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *image.Image, error) { + rb, err := bc.Build(ctx, func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *dockerspec.DockerOCIImage, *dockerspec.DockerOCIImage, error) { opt := convertOpt opt.TargetPlatform = platform if idx != 0 { opt.Warn = nil } - st, img, scanTarget, err := dockerfile2llb.Dockerfile2LLB(ctx, src.Data, opt) + st, img, baseImg, scanTarget, err := dockerfile2llb.Dockerfile2LLB(ctx, src.Data, opt) if err != nil { - return nil, nil, err + return nil, nil, nil, err } def, err := st.Marshal(ctx) if err != nil { - return nil, nil, errors.Wrapf(err, "failed to marshal LLB definition") + return nil, nil, nil, errors.Wrapf(err, "failed to marshal LLB definition") } r, err := c.Solve(ctx, client.SolveRequest{ @@ -131,12 +137,12 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { CacheImports: bc.CacheImports, }) if err != nil { - return nil, nil, err + return nil, nil, nil, err } ref, err := r.SingleRef() if err != nil { - return nil, nil, err + return nil, nil, nil, err } p := platforms.DefaultSpec() @@ -145,7 +151,7 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { } scanTargets.Store(platforms.Format(platforms.Normalize(p)), scanTarget) - return ref, img, nil + return ref, img, baseImg, nil }) if err != nil { return nil, err diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go index 738ebf7d05acd..531aa09484bd7 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go @@ -16,11 +16,11 @@ import ( "time" "github.com/containerd/containerd/platforms" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/docker/go-connections/nat" "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb/imagemetaresolver" - "github.com/moby/buildkit/exporter/containerimage/image" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/moby/buildkit/frontend/dockerfile/shell" @@ -33,6 +33,7 @@ import ( "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/suggest" "github.com/moby/buildkit/util/system" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" "github.com/moby/sys/signal" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -56,6 +57,7 @@ var nonEnvArgs = map[string]struct{}{ type ConvertOpt struct { dockerui.Config Client *dockerui.Client + MainContext *llb.State SourceMap *llb.SourceMap TargetPlatform *ocispecs.Platform MetaResolver llb.ImageMetaResolver @@ -70,13 +72,13 @@ type SBOMTargets struct { IgnoreCache bool } -func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *image.Image, *SBOMTargets, error) { +func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (st *llb.State, img, baseImg *dockerspec.DockerOCIImage, sbom *SBOMTargets, err error) { ds, err := toDispatchState(ctx, dt, opt) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } - sbom := SBOMTargets{ + sbom = &SBOMTargets{ Core: ds.state, Extras: map[string]llb.State{}, } @@ -95,7 +97,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, } } - return &ds.state, &ds.image, &sbom, nil + return &ds.state, &ds.image, ds.baseImg, sbom, nil } func Dockefile2Outline(ctx context.Context, dt []byte, opt ConvertOpt) (*outline.Outline, error) { @@ -140,7 +142,11 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS return nil, errors.Errorf("the Dockerfile cannot be empty") } - namedContext := func(ctx context.Context, name string, copt dockerui.ContextOpt) (*llb.State, *image.Image, error) { + if opt.Client != nil && opt.MainContext != nil { + return nil, errors.Errorf("Client and MainContext cannot both be provided") + } + + namedContext := func(ctx context.Context, name string, copt dockerui.ContextOpt) (*llb.State, *dockerspec.DockerOCIImage, error) { if opt.Client == nil { return nil, nil, nil } @@ -148,11 +154,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS if copt.Platform == nil { copt.Platform = opt.TargetPlatform } - st, img, err := opt.Client.NamedContext(ctx, name, copt) - if err != nil { - return nil, nil, err - } - return st, img, nil + return opt.Client.NamedContext(ctx, name, copt) } return nil, nil, nil } @@ -230,8 +232,9 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS ds := &dispatchState{ stage: st, - deps: make(map[*dispatchState]struct{}), + deps: make(map[*dispatchState]instructions.Command), ctxPaths: make(map[string]struct{}), + paths: make(map[string]struct{}), stageName: st.Name, prefixPlatform: opt.MultiPlatformRequested, outline: outline.clone(), @@ -255,7 +258,11 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS } if st.Name != "" { - s, img, err := namedContext(ctx, st.Name, dockerui.ContextOpt{Platform: ds.platform, ResolveMode: opt.ImageResolveMode.String()}) + s, img, err := namedContext(ctx, st.Name, dockerui.ContextOpt{ + Platform: ds.platform, + ResolveMode: opt.ImageResolveMode.String(), + AsyncLocalOpts: ds.asyncLocalOpts, + }) if err != nil { return nil, err } @@ -263,12 +270,18 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS ds.noinit = true ds.state = *s if img != nil { - ds.image = clampTimes(*img, opt.Epoch) + // timestamps are inherited as-is, regardless to SOURCE_DATE_EPOCH + // https://github.com/moby/buildkit/issues/4614 + ds.image = *img if img.Architecture != "" && img.OS != "" { ds.platform = &ocispecs.Platform{ OS: img.OS, Architecture: img.Architecture, Variant: img.Variant, + OSVersion: img.OSVersion, + } + if img.OSFeatures != nil { + ds.platform.OSFeatures = append([]string{}, img.OSFeatures...) } } } @@ -312,7 +325,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS var ok bool target, ok = allDispatchStates.findStateByName(opt.Target) if !ok { - return nil, errors.Errorf("target stage %s could not be found", opt.Target) + return nil, errors.Errorf("target stage %q could not be found", opt.Target) } } @@ -327,7 +340,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS d.commands[i] = newCmd for _, src := range newCmd.sources { if src != nil { - d.deps[src] = struct{}{} + d.deps[src] = cmd if src.unregistered { allDispatchStates.addState(src) } @@ -336,8 +349,8 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS } } - if has, state := hasCircularDependency(allDispatchStates.states); has { - return nil, errors.Errorf("circular dependency detected on stage: %s", state.stageName) + if err := validateCircularDependency(allDispatchStates.states); err != nil { + return nil, err } if len(allDispatchStates.states) == 1 { @@ -361,6 +374,9 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS d.state = llb.Scratch() d.image = emptyImage(platformOpt.targetPlatform) d.platform = &platformOpt.targetPlatform + if d.unregistered { + d.noinit = true + } continue } func(i int, d *dispatchState) { @@ -369,6 +385,10 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS if err != nil { err = parser.WithLocation(err, d.stage.Location) } + if d.unregistered { + // implicit stages don't need further dispatch + d.noinit = true + } }() origName := d.stage.BaseName ref, err := reference.ParseNormalizedNamed(d.stage.BaseName) @@ -382,7 +402,11 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS d.stage.BaseName = reference.TagNameOnly(ref).String() var isScratch bool - st, img, err := namedContext(ctx, d.stage.BaseName, dockerui.ContextOpt{ResolveMode: opt.ImageResolveMode.String(), Platform: platform}) + st, img, err := namedContext(ctx, d.stage.BaseName, dockerui.ContextOpt{ + ResolveMode: opt.ImageResolveMode.String(), + Platform: platform, + AsyncLocalOpts: d.asyncLocalOpts, + }) if err != nil { return err } @@ -402,12 +426,12 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS prefix += platforms.Format(*platform) + " " } prefix += "internal]" - mutRef, dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, llb.ResolveImageConfigOpt{ - Platform: platform, - ResolveMode: opt.ImageResolveMode.String(), - LogName: fmt.Sprintf("%s load metadata for %s", prefix, d.stage.BaseName), - ResolverType: llb.ResolverTypeRegistry, - SourcePolicies: nil, + mutRef, dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, sourceresolver.Opt{ + LogName: fmt.Sprintf("%s load metadata for %s", prefix, d.stage.BaseName), + Platform: platform, + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: opt.ImageResolveMode.String(), + }, }) if err != nil { return suggest.WrapError(errors.Wrap(err, origName), origName, append(allStageNames, commonImageNames()...), true) @@ -419,10 +443,11 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS return errors.Wrapf(err, "failed to parse ref %q", mutRef) } } - var img image.Image + var img dockerspec.DockerOCIImage if err := json.Unmarshal(dt, &img); err != nil { return errors.Wrap(err, "failed to parse image config") } + d.baseImg = cloneX(&img) // immutable img.Created = nil // if there is no explicit target platform, try to match based on image config if d.platform == nil && platformOpt.implicitTarget { @@ -478,16 +503,31 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS if !isReachable(target, d) || d.noinit { continue } + // mark as initialized, used to determine states that have not been dispatched yet + d.noinit = true if d.base != nil { d.state = d.base.state d.platform = d.base.platform d.image = clone(d.base.image) + d.baseImg = cloneX(d.base.baseImg) + // Utilize the same path index as our base image so we propagate + // the paths we use back to the base image. + d.paths = d.base.paths + } + + // Ensure platform is set. + if d.platform == nil { + d.platform = &d.opt.targetPlatform } // make sure that PATH is always set if _, ok := shell.BuildEnvs(d.image.Config.Env)["PATH"]; !ok { - d.image.Config.Env = append(d.image.Config.Env, "PATH="+system.DefaultPathEnv(d.platform.OS)) + var osName string + if d.platform != nil { + osName = d.platform.OS + } + d.image.Config.Env = append(d.image.Config.Env, "PATH="+system.DefaultPathEnv(osName)) } // initialize base metadata from image conf @@ -556,6 +596,11 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS } } + // Ensure the entirety of the target state is marked as used. + // This is done after we've already evaluated every stage to ensure + // the paths attribute is set correctly. + target.paths["/"] = struct{}{} + if len(opt.Labels) != 0 && target.image.Config.Labels == nil { target.image.Config.Labels = make(map[string]string, len(opt.Labels)) } @@ -563,17 +608,17 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS target.image.Config.Labels[k] = v } - opts := []llb.LocalOption{} - if includePatterns := normalizeContextPaths(ctxPaths); includePatterns != nil { - opts = append(opts, llb.FollowPaths(includePatterns)) - } + opts := filterPaths(ctxPaths) + bctx := opt.MainContext if opt.Client != nil { - bctx, err := opt.Client.MainContext(ctx, opts...) + bctx, err = opt.Client.MainContext(ctx, opts...) if err != nil { return nil, err } - buildContext.Output = bctx.Output() + } else if bctx == nil { + bctx = dockerui.DefaultMainContext(opts...) } + buildContext.Output = bctx.Output() defaults := []llb.ConstraintsOpt{ llb.Platform(platformOpt.targetPlatform), @@ -587,6 +632,10 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS target.image.OS = platformOpt.targetPlatform.OS target.image.Architecture = platformOpt.targetPlatform.Architecture target.image.Variant = platformOpt.targetPlatform.Variant + target.image.OSVersion = platformOpt.targetPlatform.OSVersion + if platformOpt.targetPlatform.OSFeatures != nil { + target.image.OSFeatures = append([]string{}, platformOpt.targetPlatform.OSFeatures...) + } } return target, nil @@ -613,7 +662,8 @@ func toCommand(ic instructions.Command, allDispatchStates *dispatchStates) (comm if !ok { stn = &dispatchState{ stage: instructions.Stage{BaseName: c.From, Location: ic.Location()}, - deps: make(map[*dispatchState]struct{}), + deps: make(map[*dispatchState]instructions.Command), + paths: make(map[string]struct{}), unregistered: true, } } @@ -698,17 +748,18 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error { } if err == nil { err = dispatchCopy(d, copyConfig{ - params: c.SourcesAndDest, - source: opt.buildContext, - isAddCommand: true, - cmdToPrint: c, - chown: c.Chown, - chmod: c.Chmod, - link: c.Link, - keepGitDir: c.KeepGitDir, - checksum: checksum, - location: c.Location(), - opt: opt, + params: c.SourcesAndDest, + excludePatterns: c.ExcludePatterns, + source: opt.buildContext, + isAddCommand: true, + cmdToPrint: c, + chown: c.Chown, + chmod: c.Chmod, + link: c.Link, + keepGitDir: c.KeepGitDir, + checksum: checksum, + location: c.Location(), + opt: opt, }) } if err == nil { @@ -743,22 +794,38 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error { case *instructions.CopyCommand: l := opt.buildContext if len(cmd.sources) != 0 { - l = cmd.sources[0].state + src := cmd.sources[0] + if !src.noinit { + return errors.Errorf("cannot copy from stage %q, it needs to be defined before current stage %q", c.From, d.stageName) + } + l = src.state } err = dispatchCopy(d, copyConfig{ - params: c.SourcesAndDest, - source: l, - isAddCommand: false, - cmdToPrint: c, - chown: c.Chown, - chmod: c.Chmod, - link: c.Link, - location: c.Location(), - opt: opt, + params: c.SourcesAndDest, + excludePatterns: c.ExcludePatterns, + source: l, + isAddCommand: false, + cmdToPrint: c, + chown: c.Chown, + chmod: c.Chmod, + link: c.Link, + parents: c.Parents, + location: c.Location(), + opt: opt, }) - if err == nil && len(cmd.sources) == 0 { - for _, src := range c.SourcePaths { - d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{} + if err == nil { + if len(cmd.sources) == 0 { + for _, src := range c.SourcePaths { + d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{} + } + } else { + source := cmd.sources[0] + if source.paths == nil { + source.paths = make(map[string]struct{}) + } + for _, src := range c.SourcePaths { + source.paths[path.Join("/", filepath.ToSlash(src))] = struct{}{} + } } } default: @@ -767,17 +834,21 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error { } type dispatchState struct { - opt dispatchOpt - state llb.State - image image.Image - platform *ocispecs.Platform - stage instructions.Stage - base *dispatchState - noinit bool - deps map[*dispatchState]struct{} - buildArgs []instructions.KeyValuePairOptional - commands []command - ctxPaths map[string]struct{} + opt dispatchOpt + state llb.State + image dockerspec.DockerOCIImage + platform *ocispecs.Platform + stage instructions.Stage + base *dispatchState + baseImg *dockerspec.DockerOCIImage // immutable, unlike image + noinit bool + deps map[*dispatchState]instructions.Command + buildArgs []instructions.KeyValuePairOptional + commands []command + // ctxPaths marks the paths this dispatchState uses from the build context. + ctxPaths map[string]struct{} + // paths marks the paths that are used by this dispatchState. + paths map[string]struct{} ignoreCache bool cmdSet bool unregistered bool @@ -791,6 +862,10 @@ type dispatchState struct { scanContext bool } +func (ds *dispatchState) asyncLocalOpts() []llb.LocalOption { + return filterPaths(ds.paths) +} + type dispatchStates struct { states []*dispatchState statesByName map[string]*dispatchState @@ -873,6 +948,9 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE customname := c.String() + // Run command can potentially access any file. Mark the full filesystem as used. + d.paths["/"] = struct{}{} + var args []string = c.CmdLine if len(c.Files) > 0 { if len(args) != 1 || !c.PrependShell { @@ -1057,6 +1135,13 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { copyOpt = append(copyOpt, llb.WithUser(cfg.chown)) } + if len(cfg.excludePatterns) > 0 { + // in theory we don't need to check whether there are any exclude patterns, + // as an empty list is a no-op. However, performing the check makes + // the code easier to understand and costs virtually nothing. + copyOpt = append(copyOpt, llb.WithExcludePatterns(cfg.excludePatterns)) + } + var mode *os.FileMode if cfg.chmod != "" { p, err := strconv.ParseUint(cfg.chmod, 8, 32) @@ -1085,6 +1170,29 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { commitMessage.WriteString("COPY") } + if cfg.parents { + commitMessage.WriteString(" " + "--parents") + } + if cfg.chown != "" { + commitMessage.WriteString(" " + "--chown=" + cfg.chown) + } + if cfg.chmod != "" { + commitMessage.WriteString(" " + "--chmod=" + cfg.chmod) + } + + platform := cfg.opt.targetPlatform + if d.platform != nil { + platform = *d.platform + } + + env, err := d.state.Env(context.TODO()) + if err != nil { + return err + } + + name := uppercaseCmd(processCmdEnv(cfg.opt.shlex, cfg.cmdToPrint.String(), env)) + pgName := prefixCommand(d, name, d.prefixPlatform, &platform, env) + var a *llb.FileAction for _, src := range cfg.params.SourcePaths { @@ -1099,7 +1207,7 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { if gitRef.SubDir != "" { commit += ":" + gitRef.SubDir } - var gitOptions []llb.GitOption + gitOptions := []llb.GitOption{llb.WithCustomName(pgName)} if cfg.keepGitDir { gitOptions = append(gitOptions, llb.KeepGitDir()) } @@ -1131,7 +1239,7 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { } } - st := llb.HTTP(src, llb.Filename(f), llb.Checksum(cfg.checksum), dfCmd(cfg.params)) + st := llb.HTTP(src, llb.Filename(f), llb.WithCustomName(pgName), llb.Checksum(cfg.checksum), dfCmd(cfg.params)) opts := append([]llb.CopyOption{&llb.CopyInfo{ Mode: mode, @@ -1149,10 +1257,18 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { return errors.Wrap(err, "removing drive letter") } + var patterns []string + if cfg.parents { + path := strings.TrimPrefix(src, "/") + patterns = []string{path} + src = "/" + } + opts := append([]llb.CopyOption{&llb.CopyInfo{ Mode: mode, FollowSymlinks: true, CopyDirContentsOnly: true, + IncludePatterns: patterns, AttemptUnpack: cfg.isAddCommand, CreateDestPath: true, AllowWildcard: true, @@ -1195,19 +1311,8 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { commitMessage.WriteString(" " + cfg.params.DestPath) - platform := cfg.opt.targetPlatform - if d.platform != nil { - platform = *d.platform - } - - env, err := d.state.Env(context.TODO()) - if err != nil { - return err - } - - name := uppercaseCmd(processCmdEnv(cfg.opt.shlex, cfg.cmdToPrint.String(), env)) fileOpt := []llb.ConstraintsOpt{ - llb.WithCustomName(prefixCommand(d, name, d.prefixPlatform, &platform, env)), + llb.WithCustomName(pgName), location(cfg.opt.sourceMap, cfg.location), } if d.ignoreCache { @@ -1240,17 +1345,19 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error { } type copyConfig struct { - params instructions.SourcesAndDest - source llb.State - isAddCommand bool - cmdToPrint fmt.Stringer - chown string - chmod string - link bool - keepGitDir bool - checksum digest.Digest - location []parser.Range - opt dispatchOpt + params instructions.SourcesAndDest + excludePatterns []string + source llb.State + isAddCommand bool + cmdToPrint fmt.Stringer + chown string + chmod string + link bool + keepGitDir bool + checksum digest.Digest + parents bool + location []parser.Range + opt dispatchOpt } func dispatchMaintainer(d *dispatchState, c *instructions.MaintainerCommand) error { @@ -1299,7 +1406,7 @@ func dispatchEntrypoint(d *dispatchState, c *instructions.EntrypointCommand) err } func dispatchHealthcheck(d *dispatchState, c *instructions.HealthCheckCommand) error { - d.image.Config.Healthcheck = &image.HealthConfig{ + d.image.Config.Healthcheck = &dockerspec.HealthcheckConfig{ Test: c.Health.Test, Interval: c.Health.Interval, Timeout: c.Health.Timeout, @@ -1498,7 +1605,7 @@ func runCommandString(args []string, buildArgs []instructions.KeyValuePairOption return strings.Join(append(tmpBuildEnv, args...), " ") } -func commitToHistory(img *image.Image, msg string, withLayer bool, st *llb.State, tm *time.Time) error { +func commitToHistory(img *dockerspec.DockerOCIImage, msg string, withLayer bool, st *llb.State, tm *time.Time) error { if st != nil { msg += " # buildkit" } @@ -1541,42 +1648,51 @@ func findReachable(from *dispatchState) (ret []*dispatchState) { return ret } -func hasCircularDependency(states []*dispatchState) (bool, *dispatchState) { - var visit func(state *dispatchState) bool +func validateCircularDependency(states []*dispatchState) error { + var visit func(*dispatchState, []instructions.Command) []instructions.Command if states == nil { - return false, nil + return nil } visited := make(map[*dispatchState]struct{}) path := make(map[*dispatchState]struct{}) - visit = func(state *dispatchState) bool { + visit = func(state *dispatchState, current []instructions.Command) []instructions.Command { _, ok := visited[state] if ok { - return false + return nil } visited[state] = struct{}{} path[state] = struct{}{} - for dep := range state.deps { - _, ok = path[dep] - if ok { - return true + for dep, c := range state.deps { + next := append(current, c) + if _, ok := path[dep]; ok { + return next } - if visit(dep) { - return true + if c := visit(dep, next); c != nil { + return c } } delete(path, state) - return false + return nil } for _, state := range states { - if visit(state) { - return true, state + if cmds := visit(state, nil); cmds != nil { + err := errors.Errorf("circular dependency detected on stage: %s", state.stageName) + for _, c := range cmds { + err = parser.WithLocation(err, c.Location()) + } + return err } } - return false, nil + return nil } func normalizeContextPaths(paths map[string]struct{}) []string { + // Avoid a useless allocation if the set of paths is empty. + if len(paths) == 0 { + return nil + } + pathSlice := make([]string, 0, len(paths)) for p := range paths { if p == "/" { @@ -1591,6 +1707,15 @@ func normalizeContextPaths(paths map[string]struct{}) []string { return pathSlice } +// filterPaths returns the local options required to filter an llb.Local +// to only the required paths. +func filterPaths(paths map[string]struct{}) []llb.LocalOption { + if includePaths := normalizeContextPaths(paths); len(includePaths) > 0 { + return []llb.LocalOption{llb.FollowPaths(includePaths)} + } + return nil +} + func proxyEnvFromBuildArgs(args map[string]string) *llb.ProxyEnv { pe := &llb.ProxyEnv{} isNil := true @@ -1626,7 +1751,7 @@ type mutableOutput struct { llb.Output } -func withShell(img image.Image, args []string) []string { +func withShell(img dockerspec.DockerOCIImage, args []string) []string { var shell []string if len(img.Config.Shell) > 0 { shell = append([]string{}, img.Config.Shell...) @@ -1636,7 +1761,7 @@ func withShell(img image.Image, args []string) []string { return append(shell, strings.Join(args, " ")) } -func autoDetectPlatform(img image.Image, target ocispecs.Platform, supported []ocispecs.Platform) ocispecs.Platform { +func autoDetectPlatform(img dockerspec.DockerOCIImage, target ocispecs.Platform, supported []ocispecs.Platform) ocispecs.Platform { os := img.OS arch := img.Architecture if target.OS == os && target.Architecture == arch { @@ -1774,21 +1899,6 @@ func commonImageNames() []string { return out } -func clampTimes(img image.Image, tm *time.Time) image.Image { - if tm == nil { - return img - } - for i, h := range img.History { - if h.Created == nil || h.Created.After(*tm) { - img.History[i].Created = tm - } - } - if img.Created != nil && img.Created.After(*tm) { - img.Created = tm - } - return img -} - func isHTTPSource(src string) bool { return strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go index 7485357babcd9..ce59770384d36 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go @@ -30,7 +30,8 @@ func detectRunMount(cmd *command, allDispatchStates *dispatchStates) bool { if !ok { stn = &dispatchState{ stage: instructions.Stage{BaseName: from}, - deps: make(map[*dispatchState]struct{}), + deps: make(map[*dispatchState]instructions.Command), + paths: make(map[string]struct{}), unregistered: true, } } @@ -69,7 +70,11 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []* } st := opt.buildContext if mount.From != "" { - st = sources[i].state + src := sources[i] + st = src.state + if !src.noinit { + return nil, errors.Errorf("cannot mount from stage %q to %q, stage needs to be defined before current command", mount.From, mount.Target) + } } var mountOpts []llb.MountOption if mount.Type == instructions.MountTypeTmpfs { @@ -136,6 +141,9 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []* if mount.From == "" { d.ctxPaths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{} + } else { + source := sources[i] + source.paths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{} } } return out, nil diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go index 70d81262bcf2b..b6b589e77654c 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go @@ -1,12 +1,12 @@ package dockerfile2llb import ( - "github.com/moby/buildkit/exporter/containerimage/image" "github.com/moby/buildkit/util/system" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ) -func clone(src image.Image) image.Image { +func clone(src dockerspec.DockerOCIImage) dockerspec.DockerOCIImage { img := src img.Config = src.Config img.Config.Env = append([]string{}, src.Config.Env...) @@ -15,10 +15,22 @@ func clone(src image.Image) image.Image { return img } -func emptyImage(platform ocispecs.Platform) image.Image { - img := image.Image{} +func cloneX(src *dockerspec.DockerOCIImage) *dockerspec.DockerOCIImage { + if src == nil { + return nil + } + img := clone(*src) + return &img +} + +func emptyImage(platform ocispecs.Platform) dockerspec.DockerOCIImage { + img := dockerspec.DockerOCIImage{} img.Architecture = platform.Architecture img.OS = platform.OS + img.OSVersion = platform.OSVersion + if platform.OSFeatures != nil { + img.OSFeatures = append([]string{}, platform.OSFeatures...) + } img.Variant = platform.Variant img.RootFS.Type = "layers" img.Config.WorkingDir = "/" diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go deleted file mode 100644 index e7f29ae8df68f..0000000000000 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go +++ /dev/null @@ -1,65 +0,0 @@ -package dockerignore - -import ( - "bufio" - "bytes" - "io" - "path/filepath" - "strings" - - "github.com/pkg/errors" -) - -// ReadAll reads a .dockerignore file and returns the list of file patterns -// to ignore. Note this will trim whitespace from each line as well -// as use GO's "clean" func to get the shortest/cleanest path for each. -func ReadAll(reader io.Reader) ([]string, error) { - if reader == nil { - return nil, nil - } - - scanner := bufio.NewScanner(reader) - var excludes []string - currentLine := 0 - - utf8bom := []byte{0xEF, 0xBB, 0xBF} - for scanner.Scan() { - scannedBytes := scanner.Bytes() - // We trim UTF8 BOM - if currentLine == 0 { - scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) - } - pattern := string(scannedBytes) - currentLine++ - // Lines starting with # (comments) are ignored before processing - if strings.HasPrefix(pattern, "#") { - continue - } - pattern = strings.TrimSpace(pattern) - if pattern == "" { - continue - } - // normalize absolute paths to paths relative to the context - // (taking care of '!' prefix) - invert := pattern[0] == '!' - if invert { - pattern = strings.TrimSpace(pattern[1:]) - } - if len(pattern) > 0 { - pattern = filepath.Clean(pattern) - pattern = filepath.ToSlash(pattern) - if len(pattern) > 1 && pattern[0] == '/' { - pattern = pattern[1:] - } - } - if invert { - pattern = "!" + pattern - } - - excludes = append(excludes, pattern) - } - if err := scanner.Err(); err != nil { - return nil, errors.Wrap(err, "error reading .dockerignore") - } - return excludes, nil -} diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go index 9ffbd457ab3f7..87252f9f17ddb 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go @@ -239,11 +239,12 @@ func (s *SourcesAndDest) ExpandRaw(expander SingleWordExpander) error { type AddCommand struct { withNameAndCode SourcesAndDest - Chown string - Chmod string - Link bool - KeepGitDir bool // whether to keep .git dir, only meaningful for git sources - Checksum string + Chown string + Chmod string + Link bool + ExcludePatterns []string + KeepGitDir bool // whether to keep .git dir, only meaningful for git sources + Checksum string } func (c *AddCommand) Expand(expander SingleWordExpander) error { @@ -270,10 +271,12 @@ func (c *AddCommand) Expand(expander SingleWordExpander) error { type CopyCommand struct { withNameAndCode SourcesAndDest - From string - Chown string - Chmod string - Link bool + From string + Chown string + Chmod string + Link bool + ExcludePatterns []string + Parents bool // parents preserves directory structure } func (c *CopyCommand) Expand(expander SingleWordExpander) error { diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/exclude_pattern_feature.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/exclude_pattern_feature.go new file mode 100644 index 0000000000000..0c1421b40d47f --- /dev/null +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/exclude_pattern_feature.go @@ -0,0 +1,8 @@ +//go:build dfexcludepatterns +// +build dfexcludepatterns + +package instructions + +func init() { + excludePatternsEnabled = true +} diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go index 5e03f84243fab..1d41d9f2c224b 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go @@ -20,6 +20,8 @@ import ( "github.com/pkg/errors" ) +var excludePatternsEnabled = false + type parseRequest struct { command string args []string @@ -34,6 +36,8 @@ type parseRequest struct { var parseRunPreHooks []func(*RunCommand, parseRequest) error var parseRunPostHooks []func(*RunCommand, parseRequest) error +var parentsEnabled = false + func nodeArgs(node *parser.Node) []string { result := []string{} for ; node.Next != nil; node = node.Next { @@ -278,10 +282,26 @@ func parseSourcesAndDest(req parseRequest, command string) (*SourcesAndDest, err }, nil } +func stringValuesFromFlagIfPossible(f *Flag) []string { + if f == nil { + return nil + } + + return f.StringValues +} + func parseAdd(req parseRequest) (*AddCommand, error) { if len(req.args) < 2 { return nil, errNoDestinationArgument("ADD") } + + var flExcludes *Flag + + // silently ignore if not -labs + if excludePatternsEnabled { + flExcludes = req.flags.AddStrings("exclude") + } + flChown := req.flags.AddString("chown", "") flChmod := req.flags.AddString("chmod", "") flLink := req.flags.AddBool("link", false) @@ -304,6 +324,7 @@ func parseAdd(req parseRequest) (*AddCommand, error) { Link: flLink.Value == "true", KeepGitDir: flKeepGitDir.Value == "true", Checksum: flChecksum.Value, + ExcludePatterns: stringValuesFromFlagIfPossible(flExcludes), }, nil } @@ -311,10 +332,19 @@ func parseCopy(req parseRequest) (*CopyCommand, error) { if len(req.args) < 2 { return nil, errNoDestinationArgument("COPY") } + + var flExcludes *Flag + + // silently ignore if not -labs + if excludePatternsEnabled { + flExcludes = req.flags.AddStrings("exclude") + } + flChown := req.flags.AddString("chown", "") flFrom := req.flags.AddString("from", "") flChmod := req.flags.AddString("chmod", "") flLink := req.flags.AddBool("link", false) + flParents := req.flags.AddBool("parents", false) if err := req.flags.Parse(); err != nil { return nil, err } @@ -331,6 +361,8 @@ func parseCopy(req parseRequest) (*CopyCommand, error) { Chown: flChown.Value, Chmod: flChmod.Value, Link: flLink.Value == "true", + Parents: (flParents.Value == "true") && parentsEnabled, // silently ignore if not -labs + ExcludePatterns: stringValuesFromFlagIfPossible(flExcludes), }, nil } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse_parents.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse_parents.go new file mode 100644 index 0000000000000..0995d35654bcf --- /dev/null +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse_parents.go @@ -0,0 +1,8 @@ +//go:build dfparents +// +build dfparents + +package instructions + +func init() { + parentsEnabled = true +} diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/errors.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/errors.go index 9f28a5a2e15fe..10d749a437eb2 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/errors.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/errors.go @@ -7,7 +7,7 @@ import ( // ErrorLocation gives a location in source code that caused the error type ErrorLocation struct { - Location []Range + Locations [][]Range error } @@ -39,11 +39,12 @@ func WithLocation(err error, location []Range) error { } var el *ErrorLocation if errors.As(err, &el) { + el.Locations = append(el.Locations, location) return err } return stack.Enable(&ErrorLocation{ - error: err, - Location: location, + error: err, + Locations: [][]Range{location}, }) } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/lex.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/lex.go index 80806f8ba7780..7f6934a913566 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/lex.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/lex.go @@ -3,6 +3,7 @@ package shell import ( "bytes" "fmt" + "regexp" "strings" "text/scanner" "unicode" @@ -100,7 +101,7 @@ type shellWord struct { } func (sw *shellWord) process(source string) (string, []string, error) { - word, words, err := sw.processStopOn(scanner.EOF) + word, words, err := sw.processStopOn(scanner.EOF, sw.rawEscapes) if err != nil { err = errors.Wrapf(err, "failed to process %q", source) } @@ -154,7 +155,7 @@ func (w *wordsStruct) getWords() []string { // Process the word, starting at 'pos', and stop when we get to the // end of the word or the 'stopChar' character -func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) { +func (sw *shellWord) processStopOn(stopChar rune, rawEscapes bool) (string, []string, error) { var result bytes.Buffer var words wordsStruct @@ -166,6 +167,14 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) { charFuncMapping['"'] = sw.processDoubleQuote } + // temporarily set sw.rawEscapes if needed + if rawEscapes != sw.rawEscapes { + sw.rawEscapes = rawEscapes + defer func() { + sw.rawEscapes = !rawEscapes + }() + } + for sw.scanner.Peek() != scanner.EOF { ch := sw.scanner.Peek() @@ -351,8 +360,9 @@ func (sw *shellWord) processDollar() (string, error) { ch = sw.scanner.Next() chs += string(ch) fallthrough - case '+', '-', '?': - word, _, err := sw.processStopOn('}') + case '+', '-', '?', '#', '%': + rawEscapes := ch == '#' || ch == '%' + word, _, err := sw.processStopOn('}', rawEscapes) if err != nil { if sw.scanner.Peek() == scanner.EOF { return "", errors.New("syntax error: missing '}'") @@ -394,9 +404,60 @@ func (sw *shellWord) processDollar() (string, error) { return "", errors.Errorf("%s: %s", name, message) } return value, nil + case '%', '#': + // %/# matches the shortest pattern expansion, %%/## the longest + greedy := false + if word[0] == byte(ch) { + greedy = true + word = word[1:] + } + + if ch == '%' { + return trimSuffix(word, value, greedy) + } + return trimPrefix(word, value, greedy) default: return "", errors.Errorf("unsupported modifier (%s) in substitution", chs) } + case '/': + replaceAll := sw.scanner.Peek() == '/' + if replaceAll { + sw.scanner.Next() + } + + pattern, _, err := sw.processStopOn('/', true) + if err != nil { + if sw.scanner.Peek() == scanner.EOF { + return "", errors.New("syntax error: missing '/' in ${}") + } + return "", err + } + + replacement, _, err := sw.processStopOn('}', true) + if err != nil { + if sw.scanner.Peek() == scanner.EOF { + return "", errors.New("syntax error: missing '}'") + } + return "", err + } + + value, set := sw.getEnv(name) + if sw.skipUnsetEnv && !set { + return fmt.Sprintf("${%s/%s/%s}", name, pattern, replacement), nil + } + + re, err := convertShellPatternToRegex(pattern, true, false) + if err != nil { + return "", errors.Errorf("invalid pattern (%s) in substitution: %s", pattern, err) + } + if replaceAll { + value = re.ReplaceAllString(value, replacement) + } else { + if idx := re.FindStringIndex(value); idx != nil { + value = value[0:idx[0]] + replacement + value[idx[1]:] + } + } + return value, nil default: return "", errors.Errorf("unsupported modifier (%s) in substitution", chs) } @@ -472,3 +533,113 @@ func BuildEnvs(env []string) map[string]string { return envs } + +// convertShellPatternToRegex converts a shell-like wildcard pattern +// (? is a single char, * either the shortest or longest (greedy) string) +// to an equivalent regular expression. +// +// Based on +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 +// but without the bracket expressions (`[]`) +func convertShellPatternToRegex(pattern string, greedy bool, anchored bool) (*regexp.Regexp, error) { + var s scanner.Scanner + s.Init(strings.NewReader(pattern)) + var out strings.Builder + out.Grow(len(pattern) + 4) + + // match only at the beginning of the string + if anchored { + out.WriteByte('^') + } + + // default: non-greedy wildcards + starPattern := ".*?" + if greedy { + starPattern = ".*" + } + + for tok := s.Next(); tok != scanner.EOF; tok = s.Next() { + switch tok { + case '*': + out.WriteString(starPattern) + continue + case '?': + out.WriteByte('.') + continue + case '\\': + // } and / as part of ${} need to be escaped, but the escape isn't part + // of the pattern + if s.Peek() == '}' || s.Peek() == '/' { + continue + } + out.WriteRune('\\') + tok = s.Next() + if tok != '*' && tok != '?' && tok != '\\' { + return nil, errors.Errorf("invalid escape '\\%c'", tok) + } + // regex characters that need to be escaped + // escaping closing is optional, but done for consistency + case '[', ']', '{', '}', '.', '+', '(', ')', '|', '^', '$': + out.WriteByte('\\') + } + out.WriteRune(tok) + } + return regexp.Compile(out.String()) +} + +func trimPrefix(word, value string, greedy bool) (string, error) { + re, err := convertShellPatternToRegex(word, greedy, true) + if err != nil { + return "", errors.Errorf("invalid pattern (%s) in substitution: %s", word, err) + } + + if idx := re.FindStringIndex(value); idx != nil { + value = value[idx[1]:] + } + return value, nil +} + +// reverse without avoid reversing escapes, i.e. a\*c -> c\*a +func reversePattern(pattern string) string { + patternRunes := []rune(pattern) + out := make([]rune, len(patternRunes)) + lastIdx := len(patternRunes) - 1 + for i := 0; i <= lastIdx; { + tok := patternRunes[i] + outIdx := lastIdx - i + if tok == '\\' && i != lastIdx { + out[outIdx-1] = tok + // the pattern is taken from a ${var#pattern}, so the last + // character can't be an escape character + out[outIdx] = patternRunes[i+1] + i += 2 + } else { + out[outIdx] = tok + i++ + } + } + return string(out) +} + +func reverseString(str string) string { + out := []rune(str) + outIdx := len(out) - 1 + for i := 0; i < outIdx; i++ { + out[i], out[outIdx] = out[outIdx], out[i] + outIdx-- + } + return string(out) +} + +func trimSuffix(pattern, word string, greedy bool) (string, error) { + // regular expressions can't handle finding the shortest rightmost + // string so we reverse both search space and pattern to convert it + // to a leftmost search in both cases + pattern = reversePattern(pattern) + word = reverseString(word) + str, err := trimPrefix(pattern, word, greedy) + if err != nil { + return "", err + } + return reverseString(str), nil +} diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/build.go b/vendor/github.com/moby/buildkit/frontend/dockerui/build.go index 8fc9bbbff11ea..c25640912067a 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/build.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/build.go @@ -7,14 +7,14 @@ import ( "github.com/containerd/containerd/platforms" "github.com/moby/buildkit/exporter/containerimage/exptypes" - "github.com/moby/buildkit/exporter/containerimage/image" "github.com/moby/buildkit/frontend/gateway/client" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" ) -type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *image.Image, error) +type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (r client.Reference, img, baseImg *dockerspec.DockerOCIImage, err error) func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, error) { res := client.NewResult() @@ -36,7 +36,7 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro for i, tp := range targets { i, tp := i, tp eg.Go(func() error { - ref, img, err := fn(ctx, tp, i) + ref, img, baseImg, err := fn(ctx, tp, i) if err != nil { return err } @@ -46,6 +46,14 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro return errors.Wrapf(err, "failed to marshal image config") } + var baseConfig []byte + if baseImg != nil { + baseConfig, err = json.Marshal(baseImg) + if err != nil { + return errors.Wrapf(err, "failed to marshal source image config") + } + } + p := platforms.DefaultSpec() if tp != nil { p = *tp @@ -57,7 +65,7 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro p.OSVersion = img.OSVersion } if p.OSFeatures == nil && len(img.OSFeatures) > 0 { - p.OSFeatures = img.OSFeatures + p.OSFeatures = append([]string{}, img.OSFeatures...) } } @@ -67,9 +75,15 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro if bc.MultiPlatformRequested { res.AddRef(k, ref) res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k), config) + if len(baseConfig) > 0 { + res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageBaseConfigKey, k), baseConfig) + } } else { res.SetRef(ref) res.AddMeta(exptypes.ExporterImageConfigKey, config) + if len(baseConfig) > 0 { + res.AddMeta(exptypes.ExporterImageBaseConfigKey, baseConfig) + } } expPlatforms.Platforms[i] = exptypes.Platform{ ID: k, diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/config.go b/vendor/github.com/moby/buildkit/frontend/dockerui/config.go index 12ec2c6880e0a..476c9faf69e4b 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/config.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/config.go @@ -10,15 +10,15 @@ import ( "time" "github.com/containerd/containerd/platforms" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" controlapi "github.com/moby/buildkit/api/services/control" "github.com/moby/buildkit/client/llb" - "github.com/moby/buildkit/exporter/containerimage/image" "github.com/moby/buildkit/frontend/attestations" - "github.com/moby/buildkit/frontend/dockerfile/dockerignore" "github.com/moby/buildkit/frontend/gateway/client" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/flightcontrol" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" + "github.com/moby/patternmatcher/ignorefile" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -80,7 +80,8 @@ type Client struct { g flightcontrol.Group[*buildContext] bopts client.BuildOpts - dockerignore []byte + dockerignore []byte + dockerignoreName string } type SBOM struct { @@ -94,7 +95,7 @@ type Source struct { type ContextOpt struct { NoDockerignore bool - LocalOpts []llb.LocalOption + AsyncLocalOpts func() []llb.LocalOption Platform *ocispecs.Platform ResolveMode string CaptureDigest *digest.Digest @@ -375,6 +376,7 @@ func (bc *Client) ReadEntrypoint(ctx context.Context, lang string, opts ...llb.L }) if err == nil { bc.dockerignore = dt + bc.dockerignoreName = bctx.filename + ".dockerignore" } return &Source{ @@ -435,13 +437,14 @@ func (bc *Client) MainContext(ctx context.Context, opts ...llb.LocalOption) (*ll dt = []byte{} } bc.dockerignore = dt + bc.dockerignoreName = DefaultDockerignoreName } var excludes []string if len(bc.dockerignore) != 0 { - excludes, err = dockerignore.ReadAll(bytes.NewBuffer(bc.dockerignore)) + excludes, err = ignorefile.ReadAll(bytes.NewBuffer(bc.dockerignore)) if err != nil { - return nil, errors.Wrap(err, "failed to parse dockerignore") + return nil, errors.Wrapf(err, "failed parsing %s", bc.dockerignoreName) } } @@ -457,7 +460,7 @@ func (bc *Client) MainContext(ctx context.Context, opts ...llb.LocalOption) (*ll return &st, nil } -func (bc *Client) NamedContext(ctx context.Context, name string, opt ContextOpt) (*llb.State, *image.Image, error) { +func (bc *Client) NamedContext(ctx context.Context, name string, opt ContextOpt) (*llb.State, *dockerspec.DockerOCIImage, error) { named, err := reference.ParseNormalizedNamed(name) if err != nil { return nil, nil, errors.Wrapf(err, "invalid context name %s", name) @@ -470,11 +473,8 @@ func (bc *Client) NamedContext(ctx context.Context, name string, opt ContextOpt) } pname := name + "::" + platforms.Format(platforms.Normalize(pp)) st, img, err := bc.namedContext(ctx, name, pname, opt) - if err != nil { - return nil, nil, err - } - if st != nil { - return st, img, nil + if err != nil || st != nil { + return st, img, err } return bc.namedContext(ctx, name, name, opt) } @@ -491,6 +491,15 @@ func (bc *Client) IsNoCache(name string) bool { return false } +func DefaultMainContext(opts ...llb.LocalOption) *llb.State { + opts = append([]llb.LocalOption{ + llb.SharedKeyHint(DefaultLocalNameContext), + WithInternalName("load build context"), + }, opts...) + st := llb.Local(DefaultLocalNameContext, opts...) + return &st +} + func WithInternalName(name string) llb.ConstraintsOpt { return llb.WithCustomName("[internal] " + name) } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go b/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go index 6a441c50822e5..2a7a558780584 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go @@ -6,14 +6,17 @@ import ( "encoding/json" "fmt" "strings" + "sync" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/exporter/containerimage/exptypes" - "github.com/moby/buildkit/exporter/containerimage/image" - "github.com/moby/buildkit/frontend/dockerfile/dockerignore" "github.com/moby/buildkit/frontend/gateway/client" + "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/imageutil" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" + "github.com/moby/patternmatcher/ignorefile" "github.com/pkg/errors" ) @@ -23,13 +26,14 @@ const ( maxContextRecursion = 10 ) -func (bc *Client) namedContext(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt) (*llb.State, *image.Image, error) { +func (bc *Client) namedContext(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt) (*llb.State, *dockerspec.DockerOCIImage, error) { return bc.namedContextRecursive(ctx, name, nameWithPlatform, opt, 0) } -func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt, count int) (*llb.State, *image.Image, error) { +func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWithPlatform string, opt ContextOpt, count int) (*llb.State, *dockerspec.DockerOCIImage, error) { opts := bc.bopts.Opts - v, ok := opts[contextPrefix+nameWithPlatform] + contextKey := contextPrefix + nameWithPlatform + v, ok := opts[contextKey] if !ok { return nil, nil, nil } @@ -69,21 +73,28 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi named = reference.TagNameOnly(named) - ref, dgst, data, err := bc.client.ResolveImageConfig(ctx, named.String(), llb.ResolveImageConfigOpt{ - Platform: opt.Platform, - ResolveMode: opt.ResolveMode, - LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, ref), - ResolverType: llb.ResolverTypeRegistry, + ref, dgst, data, err := bc.client.ResolveImageConfig(ctx, named.String(), sourceresolver.Opt{ + LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, ref), + Platform: opt.Platform, + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: opt.ResolveMode, + }, }) if err != nil { e := &imageutil.ResolveToNonImageError{} if errors.As(err, &e) { - return bc.namedContextRecursive(ctx, e.Updated, name, opt, count+1) + before, after, ok := strings.Cut(e.Updated, "://") + if !ok { + return nil, nil, errors.Errorf("could not parse ref: %s", e.Updated) + } + + bc.bopts.Opts[contextKey] = before + ":" + after + return bc.namedContextRecursive(ctx, name, nameWithPlatform, opt, count+1) } return nil, nil, err } - var img image.Image + var img dockerspec.DockerOCIImage if err := json.Unmarshal(data, &img); err != nil { return nil, nil, err } @@ -137,22 +148,21 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi return nil, nil, errors.Wrapf(err, "could not wrap %q with digest", name) } - // TODO: How should source policy be handled here with a dummy ref? - _, dgst, data, err := bc.client.ResolveImageConfig(ctx, dummyRef.String(), llb.ResolveImageConfigOpt{ - Platform: opt.Platform, - ResolveMode: opt.ResolveMode, - LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, dummyRef.String()), - ResolverType: llb.ResolverTypeOCILayout, - Store: llb.ResolveImageConfigOptStore{ - SessionID: bc.bopts.SessionID, - StoreID: named.Name(), + _, dgst, data, err := bc.client.ResolveImageConfig(ctx, dummyRef.String(), sourceresolver.Opt{ + LogName: fmt.Sprintf("[context %s] load metadata for %s", nameWithPlatform, dummyRef.String()), + Platform: opt.Platform, + OCILayoutOpt: &sourceresolver.ResolveOCILayoutOpt{ + Store: sourceresolver.ResolveImageConfigOptStore{ + SessionID: bc.bopts.SessionID, + StoreID: named.Name(), + }, }, }) if err != nil { return nil, nil, err } - var img image.Image + var img dockerspec.DockerOCIImage if err := json.Unmarshal(data, &img); err != nil { return nil, nil, errors.Wrap(err, "could not parse oci-layout image config") } @@ -206,18 +216,21 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi }) // error ignored if len(dt) != 0 { - excludes, err = dockerignore.ReadAll(bytes.NewBuffer(dt)) + excludes, err = ignorefile.ReadAll(bytes.NewBuffer(dt)) if err != nil { - return nil, nil, err + return nil, nil, errors.Wrapf(err, "failed parsing %s", DefaultDockerignoreName) } } } - st = llb.Local(vv[1], - llb.WithCustomName("[context "+nameWithPlatform+"] load from client"), - llb.SessionID(bc.bopts.SessionID), - llb.SharedKeyHint("context:"+nameWithPlatform), - llb.ExcludePatterns(excludes), - ) + + localOutput := &asyncLocalOutput{ + name: vv[1], + nameWithPlatform: nameWithPlatform, + sessionID: bc.bopts.SessionID, + excludes: excludes, + extraOpts: opt.AsyncLocalOpts, + } + st = llb.NewState(localOutput) return &st, nil, nil case "input": inputs, err := bc.client.Inputs(ctx) @@ -234,7 +247,7 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi if err := json.Unmarshal([]byte(md), &m); err != nil { return nil, nil, errors.Wrapf(err, "failed to parse input metadata %s", md) } - var img *image.Image + var img *dockerspec.DockerOCIImage if dtic, ok := m[exptypes.ExporterImageConfigKey]; ok { st, err = st.WithImageConfig(dtic) if err != nil { @@ -251,3 +264,41 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi return nil, nil, errors.Errorf("unsupported context source %s for %s", vv[0], nameWithPlatform) } } + +// asyncLocalOutput is an llb.Output that computes an llb.Local +// on-demand instead of at the time of initialization. +type asyncLocalOutput struct { + llb.Output + name string + nameWithPlatform string + sessionID string + excludes []string + extraOpts func() []llb.LocalOption + once sync.Once +} + +func (a *asyncLocalOutput) ToInput(ctx context.Context, constraints *llb.Constraints) (*pb.Input, error) { + a.once.Do(a.do) + return a.Output.ToInput(ctx, constraints) +} + +func (a *asyncLocalOutput) Vertex(ctx context.Context, constraints *llb.Constraints) llb.Vertex { + a.once.Do(a.do) + return a.Output.Vertex(ctx, constraints) +} + +func (a *asyncLocalOutput) do() { + var extraOpts []llb.LocalOption + if a.extraOpts != nil { + extraOpts = a.extraOpts() + } + opts := append([]llb.LocalOption{ + llb.WithCustomName("[context " + a.nameWithPlatform + "] load from client"), + llb.SessionID(a.sessionID), + llb.SharedKeyHint("context:" + a.nameWithPlatform), + llb.ExcludePatterns(a.excludes), + }, extraOpts...) + + st := llb.Local(a.name, opts...) + a.Output = st.Output() +} diff --git a/vendor/github.com/moby/buildkit/frontend/frontend.go b/vendor/github.com/moby/buildkit/frontend/frontend.go index 6152ee36b9c12..897600d3da93b 100644 --- a/vendor/github.com/moby/buildkit/frontend/frontend.go +++ b/vendor/github.com/moby/buildkit/frontend/frontend.go @@ -3,7 +3,7 @@ package frontend import ( "context" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" gw "github.com/moby/buildkit/frontend/gateway/client" "github.com/moby/buildkit/session" @@ -22,8 +22,8 @@ type Frontend interface { } type FrontendLLBBridge interface { + sourceresolver.MetaResolver Solve(ctx context.Context, req SolveRequest, sid string) (*Result, error) - ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (string, digest.Digest, []byte, error) Warn(ctx context.Context, dgst digest.Digest, msg string, opts WarnOpts) error } diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go b/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go index 23585de9078ea..042d66c9c4a55 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go @@ -6,6 +6,7 @@ import ( "syscall" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/result" spb "github.com/moby/buildkit/sourcepolicy/pb" @@ -26,8 +27,9 @@ func NewResult() *Result { } type Client interface { + sourceresolver.MetaResolver Solve(ctx context.Context, req SolveRequest) (*Result, error) - ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (string, digest.Digest, []byte, error) + ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) BuildOpts() BuildOpts Inputs(ctx context.Context) (map[string]llb.State, error) NewContainer(ctx context.Context, req NewContainerRequest) (Container, error) diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/container/container.go b/vendor/github.com/moby/buildkit/frontend/gateway/container/container.go index 155d9f4fead07..f34f67c1ca00e 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/container/container.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/container/container.go @@ -48,7 +48,7 @@ type Mount struct { } func NewContainer(ctx context.Context, cm cache.Manager, exec executor.Executor, sm *session.Manager, g session.Group, req NewContainerRequest) (client.Container, error) { - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) eg, ctx := errgroup.WithContext(ctx) platform := opspb.Platform{ OS: runtime.GOOS, @@ -299,7 +299,7 @@ type gatewayContainer struct { mu sync.Mutex cleanup []func() error ctx context.Context - cancel func() + cancel func(error) } func (gwCtr *gatewayContainer) Start(ctx context.Context, req client.StartRequest) (client.ContainerProcess, error) { @@ -407,7 +407,7 @@ func (gwCtr *gatewayContainer) loadSecretEnv(ctx context.Context, secretEnv []*p func (gwCtr *gatewayContainer) Release(ctx context.Context) error { gwCtr.mu.Lock() defer gwCtr.mu.Unlock() - gwCtr.cancel() + gwCtr.cancel(errors.WithStack(context.Canceled)) err1 := gwCtr.errGroup.Wait() var err2 error diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go b/vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go index cc8201c74feb4..eeb984fb3edd3 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/forwarder/forward.go @@ -6,6 +6,7 @@ import ( cacheutil "github.com/moby/buildkit/cache/util" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/frontend" "github.com/moby/buildkit/frontend/gateway/client" @@ -94,6 +95,12 @@ func (c *BridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*cli return cRes, nil } + +func (c *BridgeClient) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) { + imr := sourceresolver.NewImageMetaResolver(c) + return imr.ResolveImageConfig(ctx, ref, opt) +} + func (c *BridgeClient) loadBuildOpts() client.BuildOpts { wis := c.workers.WorkerInfos() workers := make([]client.WorkerInfo, len(wis)) diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go b/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go index 9112736325ed8..370fc9efe1e60 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go @@ -15,7 +15,7 @@ import ( "time" "github.com/containerd/containerd/mount" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/docker/docker/pkg/idtools" "github.com/gogo/googleapis/google/rpc" gogotypes "github.com/gogo/protobuf/types" @@ -25,9 +25,9 @@ import ( cacheutil "github.com/moby/buildkit/cache/util" "github.com/moby/buildkit/client" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/exporter/containerimage/exptypes" - "github.com/moby/buildkit/exporter/containerimage/image" "github.com/moby/buildkit/frontend" "github.com/moby/buildkit/frontend/dockerui" gwclient "github.com/moby/buildkit/frontend/gateway/client" @@ -47,6 +47,7 @@ import ( "github.com/moby/buildkit/util/stack" "github.com/moby/buildkit/util/tracing" "github.com/moby/buildkit/worker" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" "github.com/moby/sys/signal" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -93,7 +94,7 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten } _, isDevel := opts[keyDevel] - var img image.Image + var img dockerspec.DockerOCIImage var mfstDigest digest.Digest var rootFS cache.MutableRef var readonly bool // TODO: try to switch to read-only by default. @@ -164,7 +165,8 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten return nil, err } - ref, dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), llb.ResolveImageConfigOpt{}) + imr := sourceresolver.NewImageMetaResolver(llbBridge) + ref, dgst, config, err := imr.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), sourceresolver.Opt{}) if err != nil { return nil, err } @@ -452,7 +454,7 @@ func newBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridg } func serveLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, exec executor.Executor, workers worker.Infos, inputs map[string]*opspb.Definition, sid string, sm *session.Manager) (*llbBridgeForwarder, context.Context, error) { - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) lbf := newBridgeForwarder(ctx, llbBridge, exec, workers, inputs, sid, sm) server := grpc.NewServer(grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor), grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor)) grpc_health_v1.RegisterHealthServer(server, health.NewServer()) @@ -465,7 +467,7 @@ func serveLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLB default: lbf.isErrServerClosed = true } - cancel() + cancel(errors.WithStack(context.Canceled)) }() return lbf, ctx, nil @@ -554,6 +556,48 @@ type llbBridgeForwarder struct { ctrsMu sync.Mutex } +func (lbf *llbBridgeForwarder) ResolveSourceMeta(ctx context.Context, req *pb.ResolveSourceMetaRequest) (*pb.ResolveSourceMetaResponse, error) { + if req.Source == nil { + return nil, status.Error(codes.InvalidArgument, "source is required") + } + + ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx) + var platform *ocispecs.Platform + if p := req.Platform; p != nil { + platform = &ocispecs.Platform{ + OS: p.OS, + Architecture: p.Architecture, + Variant: p.Variant, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, + } + } + resolveopt := sourceresolver.Opt{ + LogName: req.LogName, + SourcePolicies: req.SourcePolicies, + Platform: platform, + } + resolveopt.ImageOpt = &sourceresolver.ResolveImageOpt{ + ResolveMode: req.ResolveMode, + } + resp, err := lbf.llbBridge.ResolveSourceMetadata(ctx, req.Source, resolveopt) + if err != nil { + return nil, err + } + + r := &pb.ResolveSourceMetaResponse{ + Source: resp.Op, + } + + if resp.Image != nil { + r.Image = &pb.ResolveSourceImageResponse{ + Digest: resp.Image.Digest, + Config: resp.Image.Config, + } + } + return r, nil +} + func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.ResolveImageConfigRequest) (*pb.ResolveImageConfigResponse, error) { ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx) var platform *ocispecs.Platform @@ -566,17 +610,26 @@ func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.R OSFeatures: p.OSFeatures, } } - ref, dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref, llb.ResolveImageConfigOpt{ - ResolverType: llb.ResolverType(req.ResolverType), - Platform: platform, - ResolveMode: req.ResolveMode, - LogName: req.LogName, - Store: llb.ResolveImageConfigOptStore{ - SessionID: req.SessionID, - StoreID: req.StoreID, - }, + imr := sourceresolver.NewImageMetaResolver(lbf.llbBridge) + resolveopt := sourceresolver.Opt{ + LogName: req.LogName, SourcePolicies: req.SourcePolicies, - }) + Platform: platform, + } + if sourceresolver.ResolverType(req.ResolverType) == sourceresolver.ResolverTypeRegistry { + resolveopt.ImageOpt = &sourceresolver.ResolveImageOpt{ + ResolveMode: req.ResolveMode, + } + } else if sourceresolver.ResolverType(req.ResolverType) == sourceresolver.ResolverTypeOCILayout { + resolveopt.OCILayoutOpt = &sourceresolver.ResolveOCILayoutOpt{ + Store: sourceresolver.ResolveImageConfigOptStore{ + SessionID: req.SessionID, + StoreID: req.StoreID, + }, + } + } + + ref, dgst, dt, err := imr.ResolveImageConfig(ctx, req.Ref, resolveopt) if err != nil { return nil, err } @@ -688,14 +741,15 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) ids := make(map[string]string, len(res.Refs)) defs := make(map[string]*opspb.Definition, len(res.Refs)) for k, ref := range res.Refs { - id := identity.NewID() - if ref == nil { - id = "" - } else { + var id string + var def *opspb.Definition + if ref != nil { + id = identity.NewID() + def = ref.Definition() lbf.refs[id] = ref } ids[k] = id - defs[k] = ref.Definition() + defs[k] = def } if req.AllowResultArrayRef { @@ -709,12 +763,10 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) } } else { ref := res.Ref - id := identity.NewID() - + var id string var def *opspb.Definition - if ref == nil { - id = "" - } else { + if ref != nil { + id = identity.NewID() def = ref.Definition() lbf.refs[id] = ref } @@ -1167,6 +1219,17 @@ func (pio *processIO) Close() (err error) { return err } +func (pio *processIO) Discard() { + pio.mu.Lock() + defer pio.mu.Unlock() + pio.processReaders = nil + pio.processWriters = nil + pio.serverReaders = nil + pio.serverWriters = nil + pio.Done() +} + +// hold lock before calling func (pio *processIO) Done() { stillOpen := len(pio.processReaders) + len(pio.processWriters) + len(pio.serverReaders) + len(pio.serverWriters) if stillOpen == 0 { @@ -1276,6 +1339,7 @@ func (lbf *llbBridgeForwarder) ExecProcess(srv pb.LLBBridge_ExecProcessServer) e defer func() { for _, pio := range pios { pio.Close() + pio.Discard() } }() @@ -1334,8 +1398,8 @@ func (lbf *llbBridgeForwarder) ExecProcess(srv pb.LLBBridge_ExecProcessServer) e return stack.Enable(status.Errorf(codes.NotFound, "container %q previously released or not created", id)) } - initCtx, initCancel := context.WithCancel(context.Background()) - defer initCancel() + initCtx, initCancel := context.WithCancelCause(context.Background()) + defer initCancel(errors.WithStack(context.Canceled)) pio := newProcessIO(pid, init.Fds) pios[pid] = pio diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go b/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go index 524b3ba2a966b..f5e8207707803 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/grpcclient/client.go @@ -12,10 +12,12 @@ import ( "syscall" "time" + distreference "github.com/distribution/reference" "github.com/gogo/googleapis/google/rpc" gogotypes "github.com/gogo/protobuf/types" "github.com/golang/protobuf/ptypes/any" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/frontend/gateway/client" pb "github.com/moby/buildkit/frontend/gateway/pb" "github.com/moby/buildkit/identity" @@ -23,6 +25,7 @@ import ( "github.com/moby/buildkit/util/apicaps" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/grpcerrors" + "github.com/moby/buildkit/util/imageutil" "github.com/moby/sys/signal" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -43,8 +46,9 @@ type GrpcClient interface { } func New(ctx context.Context, opts map[string]string, session, product string, c pb.LLBBridgeClient, w []client.WorkerInfo) (GrpcClient, error) { - pingCtx, pingCancel := context.WithTimeout(ctx, 15*time.Second) - defer pingCancel() + pingCtx, pingCancel := context.WithCancelCause(ctx) + pingCtx, _ = context.WithTimeoutCause(pingCtx, 15*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer pingCancel(errors.WithStack(context.Canceled)) resp, err := c.Ping(pingCtx, &pb.PingRequest{}) if err != nil { return nil, err @@ -478,7 +482,35 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (res * return res, nil } -func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (string, digest.Digest, []byte, error) { +func (c *grpcClient) ResolveSourceMetadata(ctx context.Context, op *opspb.SourceOp, opt sourceresolver.Opt) (*sourceresolver.MetaResponse, error) { + if c.caps.Supports(pb.CapSourceMetaResolver) != nil { + var ref string + if v, ok := strings.CutPrefix(op.Identifier, "docker-image://"); ok { + ref = v + } else if v, ok := strings.CutPrefix(op.Identifier, "oci-layout://"); ok { + ref = v + } else { + return &sourceresolver.MetaResponse{Op: op}, nil + } + retRef, dgst, config, err := c.ResolveImageConfig(ctx, ref, opt) + if err != nil { + return nil, err + } + if strings.HasPrefix(op.Identifier, "docker-image://") { + op.Identifier = "docker-image://" + retRef + } else if strings.HasPrefix(op.Identifier, "oci-layout://") { + op.Identifier = "oci-layout://" + retRef + } + + return &sourceresolver.MetaResponse{ + Op: op, + Image: &sourceresolver.ResolveImageResponse{ + Digest: dgst, + Config: config, + }, + }, nil + } + var p *opspb.Platform if platform := opt.Platform; platform != nil { p = &opspb.Platform{ @@ -490,16 +522,97 @@ func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt llb } } - resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{ - ResolverType: int32(opt.ResolverType), - Ref: ref, + req := &pb.ResolveSourceMetaRequest{ + Source: op, Platform: p, - ResolveMode: opt.ResolveMode, LogName: opt.LogName, - SessionID: opt.Store.SessionID, - StoreID: opt.Store.StoreID, SourcePolicies: opt.SourcePolicies, - }) + } + resp, err := c.client.ResolveSourceMeta(ctx, req) + if err != nil { + return nil, err + } + + r := &sourceresolver.MetaResponse{ + Op: resp.Source, + } + if resp.Image != nil { + r.Image = &sourceresolver.ResolveImageResponse{ + Digest: resp.Image.Digest, + Config: resp.Image.Config, + } + } + return r, nil +} + +func (c *grpcClient) resolveImageConfigViaSourceMetadata(ctx context.Context, ref string, opt sourceresolver.Opt, p *opspb.Platform) (string, digest.Digest, []byte, error) { + op := &opspb.SourceOp{ + Identifier: "docker-image://" + ref, + } + if opt.OCILayoutOpt != nil { + named, err := distreference.ParseNormalizedNamed(ref) + if err != nil { + return "", "", nil, err + } + op.Identifier = "oci-layout://" + named.String() + op.Attrs = map[string]string{ + opspb.AttrOCILayoutSessionID: opt.OCILayoutOpt.Store.SessionID, + opspb.AttrOCILayoutStoreID: opt.OCILayoutOpt.Store.StoreID, + } + } + + req := &pb.ResolveSourceMetaRequest{ + Source: op, + Platform: p, + LogName: opt.LogName, + SourcePolicies: opt.SourcePolicies, + } + resp, err := c.client.ResolveSourceMeta(ctx, req) + if err != nil { + return "", "", nil, err + } + if resp.Image == nil { + return "", "", nil, &imageutil.ResolveToNonImageError{Ref: ref, Updated: resp.Source.Identifier} + } + ref = strings.TrimPrefix(resp.Source.Identifier, "docker-image://") + ref = strings.TrimPrefix(ref, "oci-layout://") + return ref, resp.Image.Digest, resp.Image.Config, nil +} + +func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) { + var p *opspb.Platform + if platform := opt.Platform; platform != nil { + p = &opspb.Platform{ + OS: platform.OS, + Architecture: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + } + } + + if c.caps.Supports(pb.CapSourceMetaResolver) == nil { + return c.resolveImageConfigViaSourceMetadata(ctx, ref, opt, p) + } + + req := &pb.ResolveImageConfigRequest{ + Ref: ref, + LogName: opt.LogName, + SourcePolicies: opt.SourcePolicies, + Platform: p, + } + if iopt := opt.ImageOpt; iopt != nil { + req.ResolveMode = iopt.ResolveMode + req.ResolverType = int32(sourceresolver.ResolverTypeRegistry) + } + + if iopt := opt.OCILayoutOpt; iopt != nil { + req.ResolverType = int32(sourceresolver.ResolverTypeOCILayout) + req.StoreID = iopt.Store.StoreID + req.SessionID = iopt.Store.SessionID + } + + resp, err := c.client.ResolveImageConfig(ctx, req) if err != nil { return "", "", nil, err } @@ -616,7 +729,7 @@ func (b *procMessageForwarder) Close() { type messageForwarder struct { client pb.LLBBridgeClient ctx context.Context - cancel func() + cancel func(error) eg *errgroup.Group mu sync.Mutex pids map[string]*procMessageForwarder @@ -630,7 +743,7 @@ type messageForwarder struct { } func newMessageForwarder(ctx context.Context, client pb.LLBBridgeClient) *messageForwarder { - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) eg, ctx := errgroup.WithContext(ctx) return &messageForwarder{ client: client, @@ -719,7 +832,7 @@ func (m *messageForwarder) Send(msg *pb.ExecMessage) error { } func (m *messageForwarder) Release() error { - m.cancel() + m.cancel(errors.WithStack(context.Canceled)) return m.eg.Wait() } @@ -949,7 +1062,7 @@ func (ctr *container) Start(ctx context.Context, req client.StartRequest) (clien closeDoneOnce.Do(func() { close(done) }) - return ctx.Err() + return context.Cause(ctx) } if file := msg.GetFile(); file != nil { @@ -1145,7 +1258,7 @@ func grpcClientConn(ctx context.Context) (context.Context, *grpc.ClientConn, err return nil, nil, errors.Wrap(err, "failed to create grpc client") } - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) _ = cancel // go monitorHealth(ctx, cc, cancel) diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go b/vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go index 14c6c71ab0f3c..006aeee2ec240 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/pb/caps.go @@ -68,6 +68,10 @@ const ( // CapAttestations is the capability to indicate that attestation // references will be attached to results CapAttestations apicaps.CapID = "reference.attestations" + + // CapSourceMetaResolver is the capability to indicates support for ResolveSourceMetadata + // function in gateway API + CapSourceMetaResolver apicaps.CapID = "source.metaresolver" ) func init() { @@ -231,4 +235,11 @@ func init() { Enabled: true, Status: apicaps.CapStatusExperimental, }) + + Caps.Init(apicaps.Cap{ + ID: CapSourceMetaResolver, + Name: "source meta resolver", + Enabled: true, + Status: apicaps.CapStatusExperimental, + }) } diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go index 4849adeea9d32..7e759b019acaa 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go +++ b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go @@ -894,6 +894,188 @@ func (m *ResolveImageConfigResponse) GetRef() string { return "" } +type ResolveSourceMetaRequest struct { + Source *pb.SourceOp `protobuf:"bytes,1,opt,name=Source,proto3" json:"Source,omitempty"` + Platform *pb.Platform `protobuf:"bytes,2,opt,name=Platform,proto3" json:"Platform,omitempty"` + LogName string `protobuf:"bytes,3,opt,name=LogName,proto3" json:"LogName,omitempty"` + ResolveMode string `protobuf:"bytes,4,opt,name=ResolveMode,proto3" json:"ResolveMode,omitempty"` + SourcePolicies []*pb1.Policy `protobuf:"bytes,8,rep,name=SourcePolicies,proto3" json:"SourcePolicies,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResolveSourceMetaRequest) Reset() { *m = ResolveSourceMetaRequest{} } +func (m *ResolveSourceMetaRequest) String() string { return proto.CompactTextString(m) } +func (*ResolveSourceMetaRequest) ProtoMessage() {} +func (*ResolveSourceMetaRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{13} +} +func (m *ResolveSourceMetaRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResolveSourceMetaRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResolveSourceMetaRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResolveSourceMetaRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveSourceMetaRequest.Merge(m, src) +} +func (m *ResolveSourceMetaRequest) XXX_Size() int { + return m.Size() +} +func (m *ResolveSourceMetaRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveSourceMetaRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ResolveSourceMetaRequest proto.InternalMessageInfo + +func (m *ResolveSourceMetaRequest) GetSource() *pb.SourceOp { + if m != nil { + return m.Source + } + return nil +} + +func (m *ResolveSourceMetaRequest) GetPlatform() *pb.Platform { + if m != nil { + return m.Platform + } + return nil +} + +func (m *ResolveSourceMetaRequest) GetLogName() string { + if m != nil { + return m.LogName + } + return "" +} + +func (m *ResolveSourceMetaRequest) GetResolveMode() string { + if m != nil { + return m.ResolveMode + } + return "" +} + +func (m *ResolveSourceMetaRequest) GetSourcePolicies() []*pb1.Policy { + if m != nil { + return m.SourcePolicies + } + return nil +} + +type ResolveSourceMetaResponse struct { + Source *pb.SourceOp `protobuf:"bytes,1,opt,name=Source,proto3" json:"Source,omitempty"` + Image *ResolveSourceImageResponse `protobuf:"bytes,2,opt,name=Image,proto3" json:"Image,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResolveSourceMetaResponse) Reset() { *m = ResolveSourceMetaResponse{} } +func (m *ResolveSourceMetaResponse) String() string { return proto.CompactTextString(m) } +func (*ResolveSourceMetaResponse) ProtoMessage() {} +func (*ResolveSourceMetaResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{14} +} +func (m *ResolveSourceMetaResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResolveSourceMetaResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResolveSourceMetaResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResolveSourceMetaResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveSourceMetaResponse.Merge(m, src) +} +func (m *ResolveSourceMetaResponse) XXX_Size() int { + return m.Size() +} +func (m *ResolveSourceMetaResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveSourceMetaResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ResolveSourceMetaResponse proto.InternalMessageInfo + +func (m *ResolveSourceMetaResponse) GetSource() *pb.SourceOp { + if m != nil { + return m.Source + } + return nil +} + +func (m *ResolveSourceMetaResponse) GetImage() *ResolveSourceImageResponse { + if m != nil { + return m.Image + } + return nil +} + +type ResolveSourceImageResponse struct { + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=Digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"Digest"` + Config []byte `protobuf:"bytes,2,opt,name=Config,proto3" json:"Config,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResolveSourceImageResponse) Reset() { *m = ResolveSourceImageResponse{} } +func (m *ResolveSourceImageResponse) String() string { return proto.CompactTextString(m) } +func (*ResolveSourceImageResponse) ProtoMessage() {} +func (*ResolveSourceImageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{15} +} +func (m *ResolveSourceImageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResolveSourceImageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResolveSourceImageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResolveSourceImageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveSourceImageResponse.Merge(m, src) +} +func (m *ResolveSourceImageResponse) XXX_Size() int { + return m.Size() +} +func (m *ResolveSourceImageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveSourceImageResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ResolveSourceImageResponse proto.InternalMessageInfo + +func (m *ResolveSourceImageResponse) GetConfig() []byte { + if m != nil { + return m.Config + } + return nil +} + type SolveRequest struct { Definition *pb.Definition `protobuf:"bytes,1,opt,name=Definition,proto3" json:"Definition,omitempty"` Frontend string `protobuf:"bytes,2,opt,name=Frontend,proto3" json:"Frontend,omitempty"` @@ -920,7 +1102,7 @@ func (m *SolveRequest) Reset() { *m = SolveRequest{} } func (m *SolveRequest) String() string { return proto.CompactTextString(m) } func (*SolveRequest) ProtoMessage() {} func (*SolveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{13} + return fileDescriptor_f1a937782ebbded5, []int{16} } func (m *SolveRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1039,7 +1221,7 @@ func (m *CacheOptionsEntry) Reset() { *m = CacheOptionsEntry{} } func (m *CacheOptionsEntry) String() string { return proto.CompactTextString(m) } func (*CacheOptionsEntry) ProtoMessage() {} func (*CacheOptionsEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{14} + return fileDescriptor_f1a937782ebbded5, []int{17} } func (m *CacheOptionsEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1096,7 +1278,7 @@ func (m *SolveResponse) Reset() { *m = SolveResponse{} } func (m *SolveResponse) String() string { return proto.CompactTextString(m) } func (*SolveResponse) ProtoMessage() {} func (*SolveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{15} + return fileDescriptor_f1a937782ebbded5, []int{18} } func (m *SolveResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1152,7 +1334,7 @@ func (m *ReadFileRequest) Reset() { *m = ReadFileRequest{} } func (m *ReadFileRequest) String() string { return proto.CompactTextString(m) } func (*ReadFileRequest) ProtoMessage() {} func (*ReadFileRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{16} + return fileDescriptor_f1a937782ebbded5, []int{19} } func (m *ReadFileRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1214,7 +1396,7 @@ func (m *FileRange) Reset() { *m = FileRange{} } func (m *FileRange) String() string { return proto.CompactTextString(m) } func (*FileRange) ProtoMessage() {} func (*FileRange) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{17} + return fileDescriptor_f1a937782ebbded5, []int{20} } func (m *FileRange) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1268,7 +1450,7 @@ func (m *ReadFileResponse) Reset() { *m = ReadFileResponse{} } func (m *ReadFileResponse) String() string { return proto.CompactTextString(m) } func (*ReadFileResponse) ProtoMessage() {} func (*ReadFileResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{18} + return fileDescriptor_f1a937782ebbded5, []int{21} } func (m *ReadFileResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1317,7 +1499,7 @@ func (m *ReadDirRequest) Reset() { *m = ReadDirRequest{} } func (m *ReadDirRequest) String() string { return proto.CompactTextString(m) } func (*ReadDirRequest) ProtoMessage() {} func (*ReadDirRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{19} + return fileDescriptor_f1a937782ebbded5, []int{22} } func (m *ReadDirRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1378,7 +1560,7 @@ func (m *ReadDirResponse) Reset() { *m = ReadDirResponse{} } func (m *ReadDirResponse) String() string { return proto.CompactTextString(m) } func (*ReadDirResponse) ProtoMessage() {} func (*ReadDirResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{20} + return fileDescriptor_f1a937782ebbded5, []int{23} } func (m *ReadDirResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1426,7 +1608,7 @@ func (m *StatFileRequest) Reset() { *m = StatFileRequest{} } func (m *StatFileRequest) String() string { return proto.CompactTextString(m) } func (*StatFileRequest) ProtoMessage() {} func (*StatFileRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{21} + return fileDescriptor_f1a937782ebbded5, []int{24} } func (m *StatFileRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1480,7 +1662,7 @@ func (m *StatFileResponse) Reset() { *m = StatFileResponse{} } func (m *StatFileResponse) String() string { return proto.CompactTextString(m) } func (*StatFileResponse) ProtoMessage() {} func (*StatFileResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{22} + return fileDescriptor_f1a937782ebbded5, []int{25} } func (m *StatFileResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1527,7 +1709,7 @@ func (m *EvaluateRequest) Reset() { *m = EvaluateRequest{} } func (m *EvaluateRequest) String() string { return proto.CompactTextString(m) } func (*EvaluateRequest) ProtoMessage() {} func (*EvaluateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{23} + return fileDescriptor_f1a937782ebbded5, []int{26} } func (m *EvaluateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1573,7 +1755,7 @@ func (m *EvaluateResponse) Reset() { *m = EvaluateResponse{} } func (m *EvaluateResponse) String() string { return proto.CompactTextString(m) } func (*EvaluateResponse) ProtoMessage() {} func (*EvaluateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{24} + return fileDescriptor_f1a937782ebbded5, []int{27} } func (m *EvaluateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1612,7 +1794,7 @@ func (m *PingRequest) Reset() { *m = PingRequest{} } func (m *PingRequest) String() string { return proto.CompactTextString(m) } func (*PingRequest) ProtoMessage() {} func (*PingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{25} + return fileDescriptor_f1a937782ebbded5, []int{28} } func (m *PingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1654,7 +1836,7 @@ func (m *PongResponse) Reset() { *m = PongResponse{} } func (m *PongResponse) String() string { return proto.CompactTextString(m) } func (*PongResponse) ProtoMessage() {} func (*PongResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{26} + return fileDescriptor_f1a937782ebbded5, []int{29} } func (m *PongResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1721,7 +1903,7 @@ func (m *WarnRequest) Reset() { *m = WarnRequest{} } func (m *WarnRequest) String() string { return proto.CompactTextString(m) } func (*WarnRequest) ProtoMessage() {} func (*WarnRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{27} + return fileDescriptor_f1a937782ebbded5, []int{30} } func (m *WarnRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1802,7 +1984,7 @@ func (m *WarnResponse) Reset() { *m = WarnResponse{} } func (m *WarnResponse) String() string { return proto.CompactTextString(m) } func (*WarnResponse) ProtoMessage() {} func (*WarnResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{28} + return fileDescriptor_f1a937782ebbded5, []int{31} } func (m *WarnResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1849,7 +2031,7 @@ func (m *NewContainerRequest) Reset() { *m = NewContainerRequest{} } func (m *NewContainerRequest) String() string { return proto.CompactTextString(m) } func (*NewContainerRequest) ProtoMessage() {} func (*NewContainerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{29} + return fileDescriptor_f1a937782ebbded5, []int{32} } func (m *NewContainerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1937,7 +2119,7 @@ func (m *NewContainerResponse) Reset() { *m = NewContainerResponse{} } func (m *NewContainerResponse) String() string { return proto.CompactTextString(m) } func (*NewContainerResponse) ProtoMessage() {} func (*NewContainerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{30} + return fileDescriptor_f1a937782ebbded5, []int{33} } func (m *NewContainerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1977,7 +2159,7 @@ func (m *ReleaseContainerRequest) Reset() { *m = ReleaseContainerRequest func (m *ReleaseContainerRequest) String() string { return proto.CompactTextString(m) } func (*ReleaseContainerRequest) ProtoMessage() {} func (*ReleaseContainerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{31} + return fileDescriptor_f1a937782ebbded5, []int{34} } func (m *ReleaseContainerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2023,7 +2205,7 @@ func (m *ReleaseContainerResponse) Reset() { *m = ReleaseContainerRespon func (m *ReleaseContainerResponse) String() string { return proto.CompactTextString(m) } func (*ReleaseContainerResponse) ProtoMessage() {} func (*ReleaseContainerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{32} + return fileDescriptor_f1a937782ebbded5, []int{35} } func (m *ReleaseContainerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2255,7 @@ func (m *ExecMessage) Reset() { *m = ExecMessage{} } func (m *ExecMessage) String() string { return proto.CompactTextString(m) } func (*ExecMessage) ProtoMessage() {} func (*ExecMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{33} + return fileDescriptor_f1a937782ebbded5, []int{36} } func (m *ExecMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2230,7 +2412,7 @@ func (m *InitMessage) Reset() { *m = InitMessage{} } func (m *InitMessage) String() string { return proto.CompactTextString(m) } func (*InitMessage) ProtoMessage() {} func (*InitMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{34} + return fileDescriptor_f1a937782ebbded5, []int{37} } func (m *InitMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2313,7 +2495,7 @@ func (m *ExitMessage) Reset() { *m = ExitMessage{} } func (m *ExitMessage) String() string { return proto.CompactTextString(m) } func (*ExitMessage) ProtoMessage() {} func (*ExitMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{35} + return fileDescriptor_f1a937782ebbded5, []int{38} } func (m *ExitMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2366,7 +2548,7 @@ func (m *StartedMessage) Reset() { *m = StartedMessage{} } func (m *StartedMessage) String() string { return proto.CompactTextString(m) } func (*StartedMessage) ProtoMessage() {} func (*StartedMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{36} + return fileDescriptor_f1a937782ebbded5, []int{39} } func (m *StartedMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2405,7 +2587,7 @@ func (m *DoneMessage) Reset() { *m = DoneMessage{} } func (m *DoneMessage) String() string { return proto.CompactTextString(m) } func (*DoneMessage) ProtoMessage() {} func (*DoneMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{37} + return fileDescriptor_f1a937782ebbded5, []int{40} } func (m *DoneMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2447,7 +2629,7 @@ func (m *FdMessage) Reset() { *m = FdMessage{} } func (m *FdMessage) String() string { return proto.CompactTextString(m) } func (*FdMessage) ProtoMessage() {} func (*FdMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{38} + return fileDescriptor_f1a937782ebbded5, []int{41} } func (m *FdMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2509,7 +2691,7 @@ func (m *ResizeMessage) Reset() { *m = ResizeMessage{} } func (m *ResizeMessage) String() string { return proto.CompactTextString(m) } func (*ResizeMessage) ProtoMessage() {} func (*ResizeMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{39} + return fileDescriptor_f1a937782ebbded5, []int{42} } func (m *ResizeMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2565,7 +2747,7 @@ func (m *SignalMessage) Reset() { *m = SignalMessage{} } func (m *SignalMessage) String() string { return proto.CompactTextString(m) } func (*SignalMessage) ProtoMessage() {} func (*SignalMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_f1a937782ebbded5, []int{40} + return fileDescriptor_f1a937782ebbded5, []int{43} } func (m *SignalMessage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2623,6 +2805,9 @@ func init() { proto.RegisterMapType((map[string]*pb.Definition)(nil), "moby.buildkit.v1.frontend.InputsResponse.DefinitionsEntry") proto.RegisterType((*ResolveImageConfigRequest)(nil), "moby.buildkit.v1.frontend.ResolveImageConfigRequest") proto.RegisterType((*ResolveImageConfigResponse)(nil), "moby.buildkit.v1.frontend.ResolveImageConfigResponse") + proto.RegisterType((*ResolveSourceMetaRequest)(nil), "moby.buildkit.v1.frontend.ResolveSourceMetaRequest") + proto.RegisterType((*ResolveSourceMetaResponse)(nil), "moby.buildkit.v1.frontend.ResolveSourceMetaResponse") + proto.RegisterType((*ResolveSourceImageResponse)(nil), "moby.buildkit.v1.frontend.ResolveSourceImageResponse") proto.RegisterType((*SolveRequest)(nil), "moby.buildkit.v1.frontend.SolveRequest") proto.RegisterMapType((map[string]*pb.Definition)(nil), "moby.buildkit.v1.frontend.SolveRequest.FrontendInputsEntry") proto.RegisterMapType((map[string]string)(nil), "moby.buildkit.v1.frontend.SolveRequest.FrontendOptEntry") @@ -2659,164 +2844,170 @@ func init() { func init() { proto.RegisterFile("gateway.proto", fileDescriptor_f1a937782ebbded5) } var fileDescriptor_f1a937782ebbded5 = []byte{ - // 2497 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, - 0xf5, 0xd7, 0x8a, 0x14, 0x45, 0x3e, 0xfe, 0x10, 0x3d, 0x71, 0xf2, 0xa5, 0x17, 0x81, 0x23, 0xaf, - 0x63, 0x45, 0x96, 0x1d, 0xd2, 0x5f, 0xd9, 0x86, 0x5c, 0xbb, 0x75, 0x62, 0xfd, 0x82, 0x14, 0x4b, - 0x36, 0x3b, 0x72, 0xe1, 0x22, 0x48, 0x81, 0xae, 0xb8, 0x43, 0x6a, 0xeb, 0xd5, 0xee, 0x76, 0x77, - 0x28, 0x59, 0xc9, 0xa9, 0x87, 0x02, 0x45, 0x8e, 0x3d, 0xf4, 0x96, 0x4b, 0x0b, 0xf4, 0xd4, 0x43, - 0xfb, 0x07, 0x34, 0xe7, 0x00, 0xed, 0xa1, 0xe7, 0x1e, 0x82, 0xc2, 0x7f, 0x44, 0x81, 0xde, 0x8a, - 0x37, 0x33, 0x4b, 0x0e, 0x7f, 0x68, 0x45, 0xd6, 0x27, 0xce, 0xbc, 0x79, 0x3f, 0xe6, 0xbd, 0x37, - 0xef, 0xcd, 0x67, 0x96, 0x50, 0xee, 0xd8, 0x9c, 0x9d, 0xda, 0x67, 0xf5, 0x30, 0x0a, 0x78, 0x40, - 0xae, 0x1c, 0x07, 0x87, 0x67, 0xf5, 0xc3, 0xae, 0xeb, 0x39, 0xaf, 0x5c, 0x5e, 0x3f, 0xf9, 0xff, - 0x7a, 0x3b, 0x0a, 0x7c, 0xce, 0x7c, 0xc7, 0xfc, 0xb8, 0xe3, 0xf2, 0xa3, 0xee, 0x61, 0xbd, 0x15, - 0x1c, 0x37, 0x3a, 0x41, 0x27, 0x68, 0x08, 0x89, 0xc3, 0x6e, 0x5b, 0xcc, 0xc4, 0x44, 0x8c, 0xa4, - 0x26, 0x73, 0x75, 0x98, 0xbd, 0x13, 0x04, 0x1d, 0x8f, 0xd9, 0xa1, 0x1b, 0xab, 0x61, 0x23, 0x0a, - 0x5b, 0x8d, 0x98, 0xdb, 0xbc, 0x1b, 0x2b, 0x99, 0xdb, 0x9a, 0x0c, 0x6e, 0xa4, 0x91, 0x6c, 0xa4, - 0x11, 0x07, 0xde, 0x09, 0x8b, 0x1a, 0xe1, 0x61, 0x23, 0x08, 0x13, 0xee, 0xc6, 0xb9, 0xdc, 0x76, - 0xe8, 0x36, 0xf8, 0x59, 0xc8, 0xe2, 0xc6, 0x69, 0x10, 0xbd, 0x62, 0x91, 0x12, 0xb8, 0x7b, 0xae, - 0x40, 0x97, 0xbb, 0x1e, 0x4a, 0xb5, 0xec, 0x30, 0x46, 0x23, 0xf8, 0xab, 0x84, 0x74, 0xb7, 0x79, - 0xe0, 0xbb, 0x31, 0x77, 0xdd, 0x8e, 0xdb, 0x68, 0xc7, 0x42, 0x46, 0x5a, 0x41, 0x27, 0x14, 0xfb, - 0xfd, 0x14, 0x17, 0xba, 0x51, 0x8b, 0x85, 0x81, 0xe7, 0xb6, 0xce, 0xd0, 0x86, 0x1c, 0x49, 0x31, - 0xeb, 0x6f, 0x59, 0xc8, 0x51, 0x16, 0x77, 0x3d, 0x4e, 0x96, 0xa0, 0x1c, 0xb1, 0xf6, 0x26, 0x0b, - 0x23, 0xd6, 0xb2, 0x39, 0x73, 0x6a, 0xc6, 0xa2, 0xb1, 0x5c, 0xd8, 0x99, 0xa1, 0x83, 0x64, 0xf2, - 0x13, 0xa8, 0x44, 0xac, 0x1d, 0x6b, 0x8c, 0xb3, 0x8b, 0xc6, 0x72, 0x71, 0xf5, 0x56, 0xfd, 0xdc, - 0x1c, 0xd6, 0x29, 0x6b, 0xef, 0xdb, 0x61, 0x5f, 0x64, 0x67, 0x86, 0x0e, 0x29, 0x21, 0xab, 0x90, - 0x89, 0x58, 0xbb, 0x96, 0x11, 0xba, 0xae, 0xa6, 0xeb, 0xda, 0x99, 0xa1, 0xc8, 0x4c, 0xd6, 0x20, - 0x8b, 0x5a, 0x6a, 0x59, 0x21, 0x74, 0xed, 0xc2, 0x0d, 0xec, 0xcc, 0x50, 0x21, 0x40, 0x9e, 0x42, - 0xfe, 0x98, 0x71, 0xdb, 0xb1, 0xb9, 0x5d, 0x83, 0xc5, 0xcc, 0x72, 0x71, 0xb5, 0x91, 0x2a, 0x8c, - 0x01, 0xaa, 0xef, 0x2b, 0x89, 0x2d, 0x9f, 0x47, 0x67, 0xb4, 0xa7, 0x80, 0xbc, 0x84, 0x92, 0xcd, - 0x39, 0xc3, 0x64, 0xb8, 0x81, 0x1f, 0xd7, 0x4a, 0x42, 0xe1, 0xdd, 0x8b, 0x15, 0x3e, 0xd1, 0xa4, - 0xa4, 0xd2, 0x01, 0x45, 0xe6, 0x23, 0x28, 0x0f, 0xd8, 0x24, 0x55, 0xc8, 0xbc, 0x62, 0x67, 0x32, - 0x31, 0x14, 0x87, 0xe4, 0x32, 0xcc, 0x9d, 0xd8, 0x5e, 0x97, 0x89, 0x1c, 0x94, 0xa8, 0x9c, 0x3c, - 0x9c, 0x7d, 0x60, 0x98, 0x47, 0x70, 0x69, 0x44, 0xff, 0x18, 0x05, 0x3f, 0xd2, 0x15, 0x14, 0x57, - 0x3f, 0x4a, 0xd9, 0xb5, 0xae, 0x4e, 0xb3, 0xb4, 0x9e, 0x87, 0x5c, 0x24, 0x1c, 0xb2, 0x7e, 0x67, - 0x40, 0x75, 0x38, 0xd5, 0x64, 0x57, 0x25, 0xc9, 0x10, 0x61, 0xb9, 0x3f, 0xc5, 0x29, 0x41, 0x82, - 0x0a, 0x8c, 0x50, 0x61, 0xae, 0x41, 0xa1, 0x47, 0xba, 0x28, 0x18, 0x05, 0x6d, 0x8b, 0xd6, 0x1a, - 0x64, 0x28, 0x6b, 0x93, 0x0a, 0xcc, 0xba, 0xea, 0x5c, 0xd3, 0x59, 0xd7, 0x21, 0x8b, 0x90, 0x71, - 0x58, 0x5b, 0xb9, 0x5e, 0xa9, 0x87, 0x87, 0xf5, 0x4d, 0xd6, 0x76, 0x7d, 0x17, 0x5d, 0xa4, 0xb8, - 0x64, 0xfd, 0xde, 0xc0, 0xfa, 0xc0, 0x6d, 0x91, 0x4f, 0x06, 0xfc, 0xb8, 0xf8, 0xb4, 0x8f, 0xec, - 0xfe, 0x65, 0xfa, 0xee, 0xef, 0x0d, 0x66, 0xe2, 0x82, 0x12, 0xd0, 0xbd, 0xfb, 0x29, 0x94, 0xf4, - 0xdc, 0x90, 0x1d, 0x28, 0x6a, 0xe7, 0x48, 0x6d, 0x78, 0x69, 0xb2, 0xcc, 0x52, 0x5d, 0xd4, 0xfa, - 0x63, 0x06, 0x8a, 0xda, 0x22, 0x79, 0x0c, 0xd9, 0x57, 0xae, 0x2f, 0x43, 0x58, 0x59, 0x5d, 0x99, - 0x4c, 0xe5, 0x53, 0xd7, 0x77, 0xa8, 0x90, 0x23, 0x4d, 0xad, 0xee, 0x66, 0xc5, 0xb6, 0xee, 0x4d, - 0xa6, 0xe3, 0xdc, 0xe2, 0xbb, 0x33, 0x45, 0xdb, 0x90, 0x4d, 0x83, 0x40, 0x36, 0xb4, 0xf9, 0x91, - 0x68, 0x1a, 0x05, 0x2a, 0xc6, 0xe4, 0x0e, 0xbc, 0xe3, 0xfa, 0x2f, 0x02, 0x1e, 0x34, 0x23, 0xe6, - 0xb8, 0x78, 0xf8, 0x5e, 0x9c, 0x85, 0xac, 0x36, 0x27, 0x58, 0xc6, 0x2d, 0x91, 0x26, 0x54, 0x24, - 0xf9, 0xa0, 0x7b, 0xf8, 0x0b, 0xd6, 0xe2, 0x71, 0x2d, 0x27, 0xfc, 0x59, 0x4e, 0xd9, 0xc2, 0xae, - 0x2e, 0x40, 0x87, 0xe4, 0xdf, 0xaa, 0xda, 0xad, 0xbf, 0x18, 0x50, 0x1e, 0x50, 0x4f, 0x3e, 0x1d, - 0x48, 0xd5, 0xed, 0x49, 0xb7, 0xa5, 0x25, 0xeb, 0x33, 0xc8, 0x39, 0x6e, 0x87, 0xc5, 0x5c, 0xa4, - 0xaa, 0xb0, 0xbe, 0xfa, 0xdd, 0xf7, 0x1f, 0xcc, 0xfc, 0xf3, 0xfb, 0x0f, 0x56, 0xb4, 0xab, 0x26, - 0x08, 0x99, 0xdf, 0x0a, 0x7c, 0x6e, 0xbb, 0x3e, 0x8b, 0xf0, 0x82, 0xfd, 0x58, 0x8a, 0xd4, 0x37, - 0xc5, 0x0f, 0x55, 0x1a, 0x30, 0xe8, 0xbe, 0x7d, 0xcc, 0x44, 0x9e, 0x0a, 0x54, 0x8c, 0x2d, 0x0e, - 0x65, 0xca, 0x78, 0x37, 0xf2, 0x29, 0xfb, 0x65, 0x17, 0x99, 0x7e, 0x90, 0x34, 0x12, 0xb1, 0xe9, - 0x8b, 0x1a, 0x3a, 0x32, 0x52, 0x25, 0x40, 0x96, 0x61, 0x8e, 0x45, 0x51, 0x10, 0xa9, 0xe2, 0x21, - 0x75, 0x79, 0xd5, 0xd7, 0xa3, 0xb0, 0x55, 0x3f, 0x10, 0x57, 0x3d, 0x95, 0x0c, 0x56, 0x15, 0x2a, - 0x89, 0xd5, 0x38, 0x0c, 0xfc, 0x98, 0x59, 0x0b, 0x18, 0xba, 0xb0, 0xcb, 0x63, 0xb5, 0x0f, 0xeb, - 0x5b, 0x03, 0x2a, 0x09, 0x45, 0xf2, 0x90, 0x2f, 0xa0, 0xd8, 0x6f, 0x0d, 0x49, 0x0f, 0x78, 0x98, - 0x1a, 0x54, 0x5d, 0x5e, 0xeb, 0x2b, 0xaa, 0x25, 0xe8, 0xea, 0xcc, 0x67, 0x50, 0x1d, 0x66, 0x18, - 0x93, 0xfd, 0x0f, 0x07, 0x1b, 0xc4, 0x70, 0xbf, 0xd2, 0x4e, 0xc3, 0xb7, 0xb3, 0x70, 0x85, 0x32, - 0x81, 0x5d, 0x76, 0x8f, 0xed, 0x0e, 0xdb, 0x08, 0xfc, 0xb6, 0xdb, 0x49, 0xc2, 0x5c, 0x15, 0xcd, - 0x30, 0xd1, 0x8c, 0x7d, 0x71, 0x19, 0xf2, 0x4d, 0xcf, 0xe6, 0xed, 0x20, 0x3a, 0x56, 0xca, 0x4b, - 0xa8, 0x3c, 0xa1, 0xd1, 0xde, 0x2a, 0x59, 0x84, 0xa2, 0x52, 0xbc, 0x1f, 0x38, 0x49, 0x3a, 0x75, - 0x12, 0xa9, 0xc1, 0xfc, 0x5e, 0xd0, 0x79, 0x86, 0xc9, 0x96, 0x15, 0x96, 0x4c, 0x89, 0x05, 0x25, - 0xc5, 0x18, 0xf5, 0xaa, 0x6b, 0x8e, 0x0e, 0xd0, 0xc8, 0xfb, 0x50, 0x38, 0x60, 0x71, 0xec, 0x06, - 0xfe, 0xee, 0x66, 0x2d, 0x27, 0xe4, 0xfb, 0x04, 0xd4, 0x7d, 0xc0, 0x83, 0x88, 0xed, 0x6e, 0xd6, - 0xe6, 0xa5, 0x6e, 0x35, 0x25, 0xfb, 0x50, 0x39, 0x10, 0x38, 0xa7, 0x89, 0xe8, 0xc6, 0x65, 0x71, - 0x2d, 0x2f, 0x52, 0x74, 0x63, 0x34, 0x45, 0x3a, 0x1e, 0xaa, 0x0b, 0xf6, 0x33, 0x3a, 0x24, 0x6c, - 0xfd, 0xd6, 0x00, 0x73, 0x5c, 0x00, 0xd5, 0x69, 0xf8, 0x0c, 0x72, 0xf2, 0x7c, 0xcb, 0x20, 0xfe, - 0x6f, 0x95, 0x21, 0x7f, 0xc9, 0x7b, 0x90, 0x93, 0xda, 0x55, 0x51, 0xab, 0x59, 0x92, 0xa5, 0x4c, - 0x2f, 0x4b, 0xd6, 0xaf, 0x73, 0x50, 0x3a, 0xc0, 0x2d, 0x25, 0x89, 0xac, 0x03, 0xf4, 0xf3, 0xaf, - 0x6a, 0x66, 0xf8, 0x54, 0x68, 0x1c, 0xc4, 0x84, 0xfc, 0xb6, 0x3a, 0x9f, 0xea, 0x8a, 0xec, 0xcd, - 0xc9, 0xe7, 0x50, 0x4c, 0xc6, 0xcf, 0x43, 0x5e, 0xcb, 0x88, 0xe8, 0x3d, 0x48, 0x39, 0xe0, 0xfa, - 0x4e, 0xea, 0x9a, 0xa8, 0x3a, 0xde, 0x1a, 0x85, 0xdc, 0x86, 0x4b, 0xb6, 0xe7, 0x05, 0xa7, 0xaa, - 0x66, 0x45, 0xf5, 0x89, 0xec, 0xe7, 0xe9, 0xe8, 0x02, 0xf6, 0x62, 0x8d, 0xf8, 0x24, 0x8a, 0xec, - 0x33, 0x0c, 0x44, 0x4e, 0xf0, 0x8f, 0x5b, 0xc2, 0xb6, 0xb8, 0xed, 0xfa, 0xb6, 0x57, 0x03, 0xc1, - 0x23, 0x27, 0x78, 0xdc, 0xb6, 0x5e, 0x87, 0x41, 0xc4, 0x59, 0xf4, 0x84, 0xf3, 0xa8, 0x56, 0x14, - 0xe1, 0x1d, 0xa0, 0x91, 0x26, 0x94, 0x36, 0xec, 0xd6, 0x11, 0xdb, 0x3d, 0x46, 0x62, 0x02, 0xdd, - 0xd2, 0x9a, 0xa5, 0x60, 0x7f, 0x1e, 0xea, 0x98, 0x4d, 0xd7, 0x40, 0x5a, 0x50, 0x49, 0x5c, 0x97, - 0x2d, 0xa0, 0x56, 0x16, 0x3a, 0x1f, 0x4d, 0x1b, 0x4a, 0x29, 0x2d, 0x4d, 0x0c, 0xa9, 0xc4, 0x44, - 0x6e, 0x61, 0xb5, 0xdb, 0x9c, 0xd5, 0x2a, 0xc2, 0xe7, 0xde, 0x7c, 0x4c, 0x25, 0x2c, 0xbc, 0x45, - 0x25, 0x98, 0x8f, 0xa1, 0x3a, 0x9c, 0xdc, 0x69, 0x90, 0x97, 0xf9, 0x63, 0x78, 0x67, 0x8c, 0x47, - 0x6f, 0xd5, 0xdd, 0xfe, 0x6c, 0xc0, 0xa5, 0x91, 0x34, 0xe0, 0x0d, 0x23, 0xba, 0x8a, 0x54, 0x29, - 0xc6, 0x64, 0x1f, 0xe6, 0x30, 0xcd, 0xb1, 0xc2, 0x1a, 0x6b, 0xd3, 0xe4, 0xb5, 0x2e, 0x24, 0x65, - 0xfc, 0xa5, 0x16, 0xf3, 0x01, 0x40, 0x9f, 0x38, 0x15, 0xfe, 0xfc, 0x02, 0xca, 0x2a, 0xc9, 0xaa, - 0x83, 0x54, 0x25, 0x6c, 0x51, 0xc2, 0x08, 0x4b, 0xfa, 0x97, 0x5f, 0x66, 0xca, 0xcb, 0xcf, 0xfa, - 0x0a, 0x16, 0x28, 0xb3, 0x9d, 0x6d, 0xd7, 0x63, 0xe7, 0xf7, 0x78, 0x2c, 0x7e, 0xd7, 0x63, 0x4d, - 0x84, 0x3e, 0x49, 0xf1, 0xab, 0x39, 0x79, 0x08, 0x73, 0xd4, 0xf6, 0x3b, 0x4c, 0x99, 0xfe, 0x30, - 0xc5, 0xb4, 0x30, 0x82, 0xbc, 0x54, 0x8a, 0x58, 0x8f, 0xa0, 0xd0, 0xa3, 0x61, 0x33, 0x7b, 0xde, - 0x6e, 0xc7, 0x4c, 0x36, 0xc6, 0x0c, 0x55, 0x33, 0xa4, 0xef, 0x31, 0xbf, 0xa3, 0x4c, 0x67, 0xa8, - 0x9a, 0x59, 0x4b, 0xf8, 0x5e, 0x48, 0x76, 0xae, 0x42, 0x43, 0x20, 0xbb, 0x89, 0xf8, 0xd0, 0x10, - 0xf5, 0x2a, 0xc6, 0x96, 0x83, 0x97, 0xb6, 0xed, 0x6c, 0xba, 0xd1, 0xf9, 0x0e, 0xd6, 0x60, 0x7e, - 0xd3, 0x8d, 0x34, 0xff, 0x92, 0x29, 0x59, 0xc2, 0xeb, 0xbc, 0xe5, 0x75, 0x1d, 0xf4, 0x96, 0xb3, - 0xc8, 0x57, 0x5d, 0x75, 0x88, 0x6a, 0x7d, 0x22, 0xe3, 0x28, 0xac, 0xa8, 0xcd, 0xdc, 0x86, 0x79, - 0xe6, 0xf3, 0x08, 0xcb, 0x48, 0xde, 0xf9, 0xa4, 0x2e, 0x5f, 0xe0, 0x75, 0xf1, 0x02, 0x17, 0xd8, - 0x82, 0x26, 0x2c, 0xd6, 0x1a, 0x2c, 0x20, 0x21, 0x3d, 0x11, 0x04, 0xb2, 0xda, 0x26, 0xc5, 0xd8, - 0x7a, 0x08, 0xd5, 0xbe, 0xa0, 0x32, 0xbd, 0x04, 0x59, 0x04, 0xbf, 0xaa, 0xaf, 0x8f, 0xb3, 0x2b, - 0xd6, 0xad, 0xeb, 0xb0, 0x90, 0x14, 0xff, 0xb9, 0x46, 0x2d, 0x02, 0xd5, 0x3e, 0x93, 0xc2, 0x3d, - 0x65, 0x28, 0x36, 0x5d, 0x3f, 0x81, 0x05, 0xd6, 0x1b, 0x03, 0x4a, 0xcd, 0xc0, 0xef, 0xdf, 0x72, - 0x4d, 0x58, 0x48, 0x4a, 0xf7, 0x49, 0x73, 0x77, 0xc3, 0x0e, 0x93, 0x18, 0x2c, 0x8e, 0x9e, 0x0f, - 0xf5, 0x0d, 0xa3, 0x2e, 0x19, 0xd7, 0xb3, 0x78, 0x21, 0xd2, 0x61, 0x71, 0xf2, 0x29, 0xcc, 0xef, - 0xed, 0xad, 0x0b, 0x4d, 0xb3, 0x53, 0x69, 0x4a, 0xc4, 0xc8, 0x63, 0x98, 0x7f, 0x29, 0x3e, 0xad, - 0xc4, 0xea, 0x8a, 0x1a, 0x73, 0x56, 0x65, 0x84, 0x24, 0x1b, 0x65, 0xad, 0x20, 0x72, 0x68, 0x22, - 0x64, 0xfd, 0xdb, 0x80, 0xe2, 0x4b, 0xbb, 0x0f, 0x39, 0xfb, 0x18, 0xf7, 0x2d, 0x6e, 0x72, 0x85, - 0x71, 0x2f, 0xc3, 0x9c, 0xc7, 0x4e, 0x98, 0xa7, 0xce, 0xb8, 0x9c, 0x20, 0x35, 0x3e, 0x0a, 0x22, - 0x59, 0xd6, 0x25, 0x2a, 0x27, 0x58, 0x10, 0x0e, 0xe3, 0xb6, 0xeb, 0xd5, 0xb2, 0x8b, 0x19, 0xbc, - 0xf5, 0xe5, 0x0c, 0x33, 0xd7, 0x8d, 0x3c, 0xf5, 0xf0, 0xc0, 0x21, 0xb1, 0x20, 0xeb, 0xfa, 0xed, - 0x40, 0xdc, 0x7f, 0xaa, 0x2d, 0xca, 0x16, 0xbd, 0xeb, 0xb7, 0x03, 0x2a, 0xd6, 0xc8, 0x35, 0xc8, - 0x45, 0x58, 0x7f, 0x71, 0x6d, 0x5e, 0x04, 0xa5, 0x80, 0x5c, 0xb2, 0x4a, 0xd5, 0x82, 0x55, 0x81, - 0x92, 0xf4, 0x5b, 0x25, 0xff, 0x4f, 0xb3, 0xf0, 0xce, 0x33, 0x76, 0xba, 0x91, 0xf8, 0x95, 0x04, - 0x64, 0x11, 0x8a, 0x3d, 0xda, 0xee, 0xa6, 0x3a, 0x42, 0x3a, 0x09, 0x8d, 0xed, 0x07, 0x5d, 0x9f, - 0x27, 0x39, 0x14, 0xc6, 0x04, 0x85, 0xaa, 0x05, 0x72, 0x03, 0xe6, 0x9f, 0x31, 0x7e, 0x1a, 0x44, - 0xaf, 0x84, 0xd7, 0x95, 0xd5, 0x22, 0xf2, 0x3c, 0x63, 0x1c, 0x11, 0x22, 0x4d, 0xd6, 0x10, 0x76, - 0x86, 0x09, 0xec, 0xcc, 0x8e, 0x83, 0x9d, 0xc9, 0x2a, 0x59, 0x83, 0x62, 0x2b, 0xf0, 0x63, 0x1e, - 0xd9, 0x2e, 0x1a, 0x9e, 0x13, 0xcc, 0xef, 0x22, 0xb3, 0x4c, 0xec, 0x46, 0x7f, 0x91, 0xea, 0x9c, - 0x64, 0x05, 0x80, 0xbd, 0xe6, 0x91, 0xbd, 0x13, 0xc4, 0xbd, 0x27, 0x1a, 0xa0, 0x1c, 0x12, 0x76, - 0x9b, 0x54, 0x5b, 0xc5, 0x0e, 0x79, 0x14, 0xc4, 0x5c, 0xbc, 0x53, 0x24, 0xbc, 0xec, 0xcd, 0xad, - 0xf7, 0xe0, 0xf2, 0x60, 0xb4, 0x54, 0x18, 0x1f, 0xc1, 0xff, 0x51, 0xe6, 0x31, 0x3b, 0x66, 0xd3, - 0x47, 0xd2, 0x32, 0xa1, 0x36, 0x2a, 0xac, 0x14, 0xff, 0x27, 0x03, 0xc5, 0xad, 0xd7, 0xac, 0xb5, - 0xcf, 0xe2, 0xd8, 0xee, 0x08, 0x60, 0xdc, 0x8c, 0x82, 0x16, 0x8b, 0xe3, 0x9e, 0xae, 0x3e, 0x81, - 0xfc, 0x10, 0xb2, 0xbb, 0xbe, 0xcb, 0xd5, 0xdd, 0xb9, 0x94, 0xfa, 0x2e, 0x71, 0xb9, 0xd2, 0xb9, - 0x33, 0x43, 0x85, 0x14, 0x79, 0x08, 0x59, 0xec, 0x3c, 0x93, 0x74, 0x7f, 0x47, 0x93, 0x45, 0x19, - 0xb2, 0x2e, 0xbe, 0x1f, 0xba, 0x5f, 0x32, 0x95, 0xc1, 0xe5, 0xf4, 0x6b, 0xcb, 0xfd, 0x92, 0xf5, - 0x35, 0x28, 0x49, 0xb2, 0x85, 0xb0, 0xde, 0x8e, 0x38, 0x73, 0x54, 0x66, 0x6f, 0xa6, 0x81, 0x25, - 0xc9, 0xd9, 0xd7, 0x92, 0xc8, 0x62, 0x10, 0xb6, 0x5e, 0xbb, 0x5c, 0x55, 0x4a, 0x5a, 0x10, 0x90, - 0x4d, 0x73, 0x04, 0xa7, 0x28, 0xbd, 0x19, 0xf8, 0x32, 0xf3, 0xe9, 0xd2, 0xc8, 0xa6, 0x49, 0xe3, - 0x14, 0xc3, 0x70, 0xe0, 0x76, 0x10, 0x83, 0xe6, 0x2f, 0x0c, 0x83, 0x64, 0xd4, 0xc2, 0x20, 0x09, - 0xeb, 0xf3, 0x30, 0x27, 0x20, 0x92, 0xf5, 0x77, 0x03, 0x8a, 0x5a, 0x9e, 0x26, 0xa8, 0xc9, 0xf7, - 0x21, 0xbb, 0xcf, 0xc4, 0x37, 0x15, 0x34, 0x9e, 0x17, 0x15, 0xc9, 0xb8, 0x4d, 0x05, 0x15, 0x9b, - 0xca, 0xb6, 0x23, 0x1b, 0x66, 0x99, 0xe2, 0x10, 0x29, 0x2f, 0xf8, 0x99, 0x48, 0x59, 0x9e, 0xe2, - 0x90, 0xdc, 0x86, 0xfc, 0x01, 0x6b, 0x75, 0x23, 0x97, 0x9f, 0x89, 0x24, 0x54, 0x56, 0xab, 0xa2, - 0xd5, 0x28, 0x9a, 0x28, 0xdc, 0x1e, 0x07, 0xb9, 0x05, 0x85, 0x98, 0xb5, 0x22, 0xc6, 0x99, 0x7f, - 0xa2, 0xaa, 0xaa, 0xac, 0xd8, 0x23, 0xc6, 0xb7, 0xfc, 0x13, 0xda, 0x5f, 0xb7, 0x9e, 0xe2, 0x49, - 0xee, 0x7b, 0x43, 0x20, 0xbb, 0x81, 0x6f, 0x47, 0x74, 0xa3, 0x4c, 0xc5, 0x18, 0x9f, 0xef, 0x5b, - 0x17, 0x3d, 0xdf, 0xb7, 0x92, 0xe7, 0xfb, 0xe0, 0x09, 0xc0, 0x6b, 0x4c, 0xcb, 0x88, 0xf5, 0x04, - 0x0a, 0xbd, 0x53, 0x4a, 0x2a, 0x30, 0xbb, 0xed, 0x28, 0x4b, 0xb3, 0xdb, 0x0e, 0xfa, 0xbd, 0xf5, - 0x7c, 0x5b, 0x58, 0xc9, 0x53, 0x1c, 0xf6, 0xd0, 0x46, 0x46, 0x43, 0x1b, 0x6b, 0x50, 0x1e, 0x38, - 0xaa, 0xc8, 0x44, 0x83, 0xd3, 0x38, 0xd9, 0x32, 0x8e, 0xa5, 0x1b, 0x5e, 0x2c, 0x74, 0x09, 0x37, - 0xbc, 0xd8, 0xba, 0x0e, 0xe5, 0x81, 0xe4, 0x22, 0x93, 0x78, 0x09, 0x2b, 0x50, 0x8a, 0xe3, 0x15, - 0x06, 0x0b, 0x43, 0x1f, 0xc7, 0xc8, 0x0d, 0xc8, 0xc9, 0x8f, 0x30, 0xd5, 0x19, 0xf3, 0xca, 0xd7, - 0xdf, 0x2c, 0xbe, 0x3b, 0xc4, 0x20, 0x17, 0x91, 0x6d, 0xbd, 0xeb, 0x3b, 0x1e, 0xab, 0x1a, 0x63, - 0xd9, 0xe4, 0xa2, 0x99, 0xfd, 0xcd, 0x1f, 0xae, 0xce, 0xac, 0xd8, 0x70, 0x69, 0xe4, 0xc3, 0x0e, - 0xb9, 0x0e, 0xd9, 0x03, 0xe6, 0xb5, 0x13, 0x33, 0x23, 0x0c, 0xb8, 0x48, 0xae, 0x41, 0x86, 0xda, - 0xa7, 0x55, 0xc3, 0xac, 0x7d, 0xfd, 0xcd, 0xe2, 0xe5, 0xd1, 0xaf, 0x43, 0xf6, 0xa9, 0x34, 0xb1, - 0xfa, 0x57, 0x80, 0xc2, 0xde, 0xde, 0xfa, 0x7a, 0xe4, 0x3a, 0x1d, 0x46, 0x7e, 0x65, 0x00, 0x19, - 0x7d, 0x33, 0x93, 0x7b, 0xe9, 0x0d, 0x61, 0xfc, 0x37, 0x0a, 0xf3, 0xfe, 0x94, 0x52, 0x0a, 0xb2, - 0x7c, 0x0e, 0x73, 0x02, 0x67, 0x93, 0x8f, 0x26, 0x7c, 0x6e, 0x99, 0xcb, 0x17, 0x33, 0x2a, 0xdd, - 0x2d, 0xc8, 0x27, 0x58, 0x95, 0xac, 0xa4, 0x6e, 0x6f, 0x00, 0x8a, 0x9b, 0xb7, 0x26, 0xe2, 0x55, - 0x46, 0x7e, 0x0e, 0xf3, 0x0a, 0x82, 0x92, 0x9b, 0x17, 0xc8, 0xf5, 0xc1, 0xb0, 0xb9, 0x32, 0x09, - 0x6b, 0xdf, 0x8d, 0x04, 0x6a, 0xa6, 0xba, 0x31, 0x04, 0x64, 0x53, 0xdd, 0x18, 0xc1, 0xae, 0xad, - 0xfe, 0x03, 0x35, 0xd5, 0xc8, 0x10, 0x70, 0x4d, 0x35, 0x32, 0x8c, 0x5f, 0xc9, 0x4b, 0xc8, 0x22, - 0x7e, 0x25, 0x69, 0xbd, 0x5a, 0x03, 0xb8, 0x66, 0xda, 0x99, 0x18, 0x00, 0xbe, 0x3f, 0xc3, 0x3b, - 0x4d, 0x7c, 0x8b, 0x48, 0xbf, 0xcd, 0xb4, 0x6f, 0x97, 0xe6, 0xcd, 0x09, 0x38, 0xfb, 0xea, 0xd5, - 0x3b, 0x7e, 0x79, 0x82, 0x0f, 0x88, 0x17, 0xab, 0x1f, 0xfa, 0x54, 0x19, 0x40, 0x49, 0x87, 0x2a, - 0xa4, 0x9e, 0x22, 0x3a, 0x06, 0x01, 0x9a, 0x8d, 0x89, 0xf9, 0x95, 0xc1, 0xaf, 0xf0, 0x11, 0x37, - 0x08, 0x63, 0xc8, 0x6a, 0x6a, 0x38, 0xc6, 0x02, 0x26, 0xf3, 0xee, 0x54, 0x32, 0xca, 0xb8, 0x2d, - 0x61, 0x92, 0x82, 0x42, 0x24, 0xfd, 0xd6, 0xef, 0xc1, 0x29, 0x73, 0x42, 0xbe, 0x65, 0xe3, 0x8e, - 0x81, 0xe7, 0x0c, 0xa1, 0x73, 0xaa, 0x6e, 0xed, 0x4d, 0x91, 0x7a, 0xce, 0x74, 0x0c, 0xbe, 0x5e, - 0xfa, 0xee, 0xcd, 0x55, 0xe3, 0x1f, 0x6f, 0xae, 0x1a, 0xff, 0x7a, 0x73, 0xd5, 0x38, 0xcc, 0x89, - 0x7f, 0x64, 0xef, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0x20, 0x47, 0x7d, 0x27, 0x1a, 0x1f, 0x00, - 0x00, + // 2607 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5a, 0xcf, 0x6f, 0x1b, 0xc7, + 0xf5, 0xd7, 0x8a, 0x3f, 0x44, 0x3e, 0xfe, 0x10, 0x3d, 0x71, 0xf2, 0x65, 0x16, 0x81, 0xa3, 0x6c, + 0x62, 0x45, 0x96, 0x1d, 0xd2, 0x5f, 0xd9, 0x86, 0x5c, 0xbb, 0x75, 0x62, 0xfd, 0x82, 0x14, 0x4b, + 0x36, 0x3b, 0x72, 0xe1, 0x22, 0x48, 0x81, 0xae, 0xc8, 0x21, 0xb5, 0xf5, 0x6a, 0x77, 0xbb, 0x3b, + 0x94, 0xac, 0x04, 0x28, 0xda, 0x43, 0x81, 0x22, 0x87, 0x1e, 0x7a, 0xe8, 0x2d, 0x97, 0x16, 0xe8, + 0xa9, 0x87, 0xf6, 0x0f, 0x68, 0xce, 0x01, 0xda, 0x43, 0xcf, 0x3d, 0x04, 0x85, 0xff, 0x87, 0x16, + 0xe8, 0xad, 0x78, 0x33, 0xb3, 0xe4, 0xf0, 0x87, 0x96, 0x64, 0x5d, 0xf4, 0xc4, 0x9d, 0x37, 0xef, + 0xc7, 0xbc, 0xf7, 0xe6, 0xbd, 0xf9, 0xcc, 0x80, 0x50, 0xea, 0xd8, 0x9c, 0x9d, 0xd9, 0xe7, 0xb5, + 0x20, 0xf4, 0xb9, 0x4f, 0xde, 0x3c, 0xf1, 0x8f, 0xce, 0x6b, 0x47, 0x5d, 0xc7, 0x6d, 0x3d, 0x77, + 0x78, 0xed, 0xf4, 0xff, 0x6b, 0xed, 0xd0, 0xf7, 0x38, 0xf3, 0x5a, 0xe6, 0x5a, 0xc7, 0xe1, 0xc7, + 0xdd, 0xa3, 0x5a, 0xd3, 0x3f, 0xa9, 0x77, 0xfc, 0x8e, 0x5f, 0xef, 0xf8, 0x7e, 0xc7, 0x65, 0x76, + 0xe0, 0x44, 0xea, 0xb3, 0x1e, 0x06, 0xcd, 0x7a, 0xc4, 0x6d, 0xde, 0x8d, 0xa4, 0x3a, 0xf3, 0x83, + 0x61, 0x19, 0x41, 0x3e, 0xea, 0xb6, 0xc5, 0x48, 0x0c, 0xc4, 0x97, 0x62, 0xaf, 0x6b, 0xec, 0xb8, + 0x90, 0x7a, 0xbc, 0x90, 0xba, 0x1d, 0x38, 0x75, 0x7e, 0x1e, 0xb0, 0xa8, 0x7e, 0xe6, 0x87, 0xcf, + 0x59, 0xa8, 0x04, 0x6e, 0x5c, 0x28, 0x10, 0xf9, 0xee, 0x29, 0x0b, 0xeb, 0xc1, 0x51, 0xdd, 0x0f, + 0xe2, 0xd5, 0xdc, 0x49, 0xe0, 0xee, 0x86, 0x4d, 0x16, 0xf8, 0xae, 0xd3, 0x3c, 0x47, 0x19, 0xf9, + 0xa5, 0xc4, 0x6e, 0x5d, 0x28, 0xd6, 0xe5, 0x8e, 0x8b, 0x4b, 0x6b, 0xda, 0x41, 0x84, 0x62, 0xf8, + 0x3b, 0xc6, 0x73, 0xee, 0x7b, 0x4e, 0xc4, 0x1d, 0xa7, 0xe3, 0xd4, 0xdb, 0x91, 0x90, 0x91, 0xae, + 0x60, 0xa8, 0x24, 0xbb, 0xf5, 0xe7, 0x34, 0x64, 0x29, 0x8b, 0xba, 0x2e, 0x27, 0xcb, 0x50, 0x0a, + 0x59, 0x7b, 0x8b, 0x05, 0x21, 0x6b, 0xda, 0x9c, 0xb5, 0xaa, 0xc6, 0x92, 0xb1, 0x92, 0xdf, 0x9d, + 0xa3, 0x83, 0x64, 0xf2, 0x3d, 0x28, 0x87, 0xac, 0x1d, 0x69, 0x8c, 0xf3, 0x4b, 0xc6, 0x4a, 0x61, + 0xed, 0x7a, 0xed, 0xc2, 0x1c, 0xd6, 0x28, 0x6b, 0x1f, 0xd8, 0x41, 0x5f, 0x64, 0x77, 0x8e, 0x0e, + 0x29, 0x21, 0x6b, 0x90, 0x0a, 0x59, 0xbb, 0x9a, 0x12, 0xba, 0xae, 0x24, 0xeb, 0xda, 0x9d, 0xa3, + 0xc8, 0x4c, 0xd6, 0x21, 0x8d, 0x5a, 0xaa, 0x69, 0x21, 0xf4, 0xce, 0xc4, 0x05, 0xec, 0xce, 0x51, + 0x21, 0x40, 0x1e, 0x41, 0xee, 0x84, 0x71, 0xbb, 0x65, 0x73, 0xbb, 0x0a, 0x4b, 0xa9, 0x95, 0xc2, + 0x5a, 0x3d, 0x51, 0x18, 0x03, 0x54, 0x3b, 0x50, 0x12, 0xdb, 0x1e, 0x0f, 0xcf, 0x69, 0x4f, 0x01, + 0x79, 0x06, 0x45, 0x9b, 0x73, 0x86, 0x51, 0x75, 0x7c, 0x2f, 0xaa, 0x16, 0x85, 0xc2, 0x5b, 0x93, + 0x15, 0x3e, 0xd4, 0xa4, 0xa4, 0xd2, 0x01, 0x45, 0xe6, 0x7d, 0x28, 0x0d, 0xd8, 0x24, 0x15, 0x48, + 0x3d, 0x67, 0xe7, 0x32, 0x31, 0x14, 0x3f, 0xc9, 0x65, 0xc8, 0x9c, 0xda, 0x6e, 0x97, 0x89, 0x1c, + 0x14, 0xa9, 0x1c, 0xdc, 0x9b, 0xbf, 0x6b, 0x98, 0xc7, 0x70, 0x69, 0x44, 0xff, 0x18, 0x05, 0xdf, + 0xd1, 0x15, 0x14, 0xd6, 0xde, 0x4f, 0x58, 0xb5, 0xae, 0x4e, 0xb3, 0xb4, 0x91, 0x83, 0x6c, 0x28, + 0x1c, 0xb2, 0x7e, 0x6d, 0x40, 0x65, 0x38, 0xd5, 0x64, 0x4f, 0x25, 0xc9, 0x10, 0x61, 0xb9, 0x33, + 0xc3, 0x2e, 0x41, 0x82, 0x0a, 0x8c, 0x50, 0x61, 0xae, 0x43, 0xbe, 0x47, 0x9a, 0x14, 0x8c, 0xbc, + 0xb6, 0x44, 0x6b, 0x1d, 0x52, 0x94, 0xb5, 0x49, 0x19, 0xe6, 0x1d, 0xb5, 0xaf, 0xe9, 0xbc, 0xd3, + 0x22, 0x4b, 0x90, 0x6a, 0xb1, 0xb6, 0x72, 0xbd, 0x5c, 0x0b, 0x8e, 0x6a, 0x5b, 0xac, 0xed, 0x78, + 0x0e, 0xba, 0x48, 0x71, 0xca, 0xfa, 0x8d, 0x81, 0xf5, 0x81, 0xcb, 0x22, 0x1f, 0x0e, 0xf8, 0x31, + 0x79, 0xb7, 0x8f, 0xac, 0xfe, 0x59, 0xf2, 0xea, 0x6f, 0x0f, 0x66, 0x62, 0x42, 0x09, 0xe8, 0xde, + 0x7d, 0x1f, 0x8a, 0x7a, 0x6e, 0xc8, 0x2e, 0x14, 0xb4, 0x7d, 0xa4, 0x16, 0xbc, 0x3c, 0x5d, 0x66, + 0xa9, 0x2e, 0x6a, 0xfd, 0x2e, 0x05, 0x05, 0x6d, 0x92, 0x3c, 0x80, 0xf4, 0x73, 0xc7, 0x93, 0x21, + 0x2c, 0xaf, 0xad, 0x4e, 0xa7, 0xf2, 0x91, 0xe3, 0xb5, 0xa8, 0x90, 0x23, 0x0d, 0xad, 0xee, 0xe6, + 0xc5, 0xb2, 0x6e, 0x4f, 0xa7, 0xe3, 0xc2, 0xe2, 0xbb, 0x39, 0x43, 0xdb, 0x90, 0x4d, 0x83, 0x40, + 0x3a, 0xb0, 0xf9, 0xb1, 0x68, 0x1a, 0x79, 0x2a, 0xbe, 0xc9, 0x4d, 0x78, 0xcd, 0xf1, 0x9e, 0xfa, + 0xdc, 0x6f, 0x84, 0xac, 0xe5, 0xe0, 0xe6, 0x7b, 0x7a, 0x1e, 0xb0, 0x6a, 0x46, 0xb0, 0x8c, 0x9b, + 0x22, 0x0d, 0x28, 0x4b, 0xf2, 0x61, 0xf7, 0xe8, 0x47, 0xac, 0xc9, 0xa3, 0x6a, 0x56, 0xf8, 0xb3, + 0x92, 0xb0, 0x84, 0x3d, 0x5d, 0x80, 0x0e, 0xc9, 0xbf, 0x52, 0xb5, 0x5b, 0x7f, 0x34, 0xa0, 0x34, + 0xa0, 0x9e, 0x7c, 0x34, 0x90, 0xaa, 0x1b, 0xd3, 0x2e, 0x4b, 0x4b, 0xd6, 0xc7, 0x90, 0x6d, 0x39, + 0x1d, 0x16, 0x71, 0x91, 0xaa, 0xfc, 0xc6, 0xda, 0xd7, 0xdf, 0xbc, 0x3d, 0xf7, 0xb7, 0x6f, 0xde, + 0x5e, 0xd5, 0x8e, 0x18, 0x3f, 0x60, 0x5e, 0xd3, 0xf7, 0xb8, 0xed, 0x78, 0x2c, 0xc4, 0xf3, 0xf8, + 0x03, 0x29, 0x52, 0xdb, 0x12, 0x3f, 0x54, 0x69, 0xc0, 0xa0, 0x7b, 0xf6, 0x09, 0x13, 0x79, 0xca, + 0x53, 0xf1, 0x6d, 0x71, 0x28, 0x51, 0xc6, 0xbb, 0xa1, 0x47, 0xd9, 0x8f, 0xbb, 0xc8, 0xf4, 0xad, + 0xb8, 0x91, 0x88, 0x45, 0x4f, 0x6a, 0xe8, 0xc8, 0x48, 0x95, 0x00, 0x59, 0x81, 0x0c, 0x0b, 0x43, + 0x3f, 0x54, 0xc5, 0x43, 0x6a, 0x12, 0x19, 0xd4, 0xc2, 0xa0, 0x59, 0x3b, 0x14, 0xc8, 0x80, 0x4a, + 0x06, 0xab, 0x02, 0xe5, 0xd8, 0x6a, 0x14, 0xf8, 0x5e, 0xc4, 0xac, 0x45, 0x0c, 0x5d, 0xd0, 0xe5, + 0x91, 0x5a, 0x87, 0xf5, 0x95, 0x01, 0xe5, 0x98, 0x22, 0x79, 0xc8, 0xa7, 0x50, 0xe8, 0xb7, 0x86, + 0xb8, 0x07, 0xdc, 0x4b, 0x0c, 0xaa, 0x2e, 0xaf, 0xf5, 0x15, 0xd5, 0x12, 0x74, 0x75, 0xe6, 0x63, + 0xa8, 0x0c, 0x33, 0x8c, 0xc9, 0xfe, 0x7b, 0x83, 0x0d, 0x62, 0xb8, 0x5f, 0x69, 0xbb, 0xe1, 0xab, + 0x79, 0x78, 0x93, 0x32, 0x01, 0x45, 0xf6, 0x4e, 0xec, 0x0e, 0xdb, 0xf4, 0xbd, 0xb6, 0xd3, 0x89, + 0xc3, 0x5c, 0x11, 0xcd, 0x30, 0xd6, 0x8c, 0x7d, 0x71, 0x05, 0x72, 0x0d, 0xd7, 0xe6, 0x6d, 0x3f, + 0x3c, 0x51, 0xca, 0x8b, 0xa8, 0x3c, 0xa6, 0xd1, 0xde, 0x2c, 0x59, 0x82, 0x82, 0x52, 0x7c, 0xe0, + 0xb7, 0xe2, 0x74, 0xea, 0x24, 0x52, 0x85, 0x85, 0x7d, 0xbf, 0xf3, 0x18, 0x93, 0x2d, 0x2b, 0x2c, + 0x1e, 0x12, 0x0b, 0x8a, 0x8a, 0x31, 0xec, 0x55, 0x57, 0x86, 0x0e, 0xd0, 0xc8, 0x5b, 0x90, 0x3f, + 0x64, 0x51, 0xe4, 0xf8, 0xde, 0xde, 0x56, 0x35, 0x2b, 0xe4, 0xfb, 0x04, 0xd4, 0x7d, 0xc8, 0xfd, + 0x90, 0xed, 0x6d, 0x55, 0x17, 0xa4, 0x6e, 0x35, 0x24, 0x07, 0x50, 0x3e, 0x14, 0x58, 0xaa, 0x81, + 0x08, 0xca, 0x61, 0x51, 0x35, 0x27, 0x52, 0x74, 0x75, 0x34, 0x45, 0x3a, 0xe6, 0xaa, 0x09, 0xf6, + 0x73, 0x3a, 0x24, 0x6c, 0xfd, 0xca, 0x00, 0x73, 0x5c, 0x00, 0xd5, 0x6e, 0xf8, 0x18, 0xb2, 0x72, + 0x7f, 0xcb, 0x20, 0xfe, 0x67, 0x95, 0x21, 0x7f, 0xc9, 0x1b, 0x90, 0x95, 0xda, 0x55, 0x51, 0xab, + 0x51, 0x9c, 0xa5, 0x54, 0x2f, 0x4b, 0xd6, 0x3f, 0x0c, 0xa8, 0xaa, 0x45, 0xc9, 0xe5, 0x62, 0xbb, + 0x88, 0x93, 0xfa, 0x1e, 0x64, 0x25, 0x51, 0xd5, 0x8e, 0x48, 0xa0, 0xa4, 0x3c, 0x09, 0xa8, 0x9a, + 0x9b, 0x21, 0xd1, 0x5a, 0x1a, 0x53, 0x83, 0x69, 0x1c, 0xda, 0x02, 0xe9, 0xd1, 0x2d, 0xf0, 0x5f, + 0x4e, 0xc6, 0x2f, 0x8d, 0xde, 0x6e, 0xd6, 0xfd, 0x56, 0xb9, 0x98, 0xce, 0xf1, 0x47, 0x90, 0x11, + 0x89, 0x54, 0x5e, 0x27, 0xa3, 0x10, 0xcd, 0x94, 0x10, 0x8a, 0x6d, 0x51, 0xa9, 0xc3, 0xfa, 0x69, + 0x7f, 0x77, 0x8c, 0xe1, 0xfa, 0x5f, 0xec, 0x0e, 0xeb, 0xe7, 0x59, 0x28, 0x1e, 0xe2, 0x02, 0xe2, + 0xfc, 0xd7, 0x00, 0xfa, 0xbd, 0x40, 0x85, 0x62, 0xb8, 0x43, 0x68, 0x1c, 0xc4, 0x84, 0xdc, 0x8e, + 0xf2, 0x58, 0xc1, 0xa5, 0xde, 0x98, 0x7c, 0x02, 0x85, 0xf8, 0xfb, 0x49, 0xc0, 0xab, 0x29, 0x91, + 0xbc, 0xbb, 0x09, 0x21, 0xd3, 0x57, 0x52, 0xd3, 0x44, 0x55, 0xab, 0xd3, 0x28, 0xe4, 0x06, 0x5c, + 0xb2, 0x5d, 0xd7, 0x3f, 0x53, 0xfd, 0x5b, 0x74, 0x62, 0xd1, 0x09, 0x72, 0x74, 0x74, 0x02, 0xcf, + 0x65, 0x8d, 0xf8, 0x30, 0x0c, 0xed, 0x73, 0x2c, 0x8a, 0xac, 0xe0, 0x1f, 0x37, 0x85, 0x47, 0xe4, + 0x8e, 0xe3, 0xd9, 0x6e, 0x15, 0x04, 0x8f, 0x1c, 0x60, 0xeb, 0xd9, 0x7e, 0x11, 0xf8, 0x21, 0x67, + 0xe1, 0x43, 0xce, 0xc3, 0x6a, 0x41, 0x04, 0x73, 0x80, 0x46, 0x1a, 0x50, 0xdc, 0xb4, 0x9b, 0xc7, + 0x6c, 0xef, 0x04, 0x89, 0x31, 0x8c, 0x4f, 0x3a, 0x38, 0x05, 0xfb, 0x93, 0x40, 0xc7, 0xef, 0xba, + 0x06, 0xd2, 0x84, 0x72, 0xec, 0xba, 0x3c, 0x0e, 0xaa, 0x25, 0xa1, 0xf3, 0xfe, 0xac, 0xa1, 0x94, + 0xd2, 0xd2, 0xc4, 0x90, 0x4a, 0x4c, 0xe4, 0x36, 0x76, 0x7e, 0x9b, 0xb3, 0x6a, 0x59, 0xf8, 0xdc, + 0x1b, 0x8f, 0x29, 0xc4, 0xc5, 0x57, 0x28, 0x44, 0xf3, 0x01, 0x54, 0x86, 0x93, 0x3b, 0x0b, 0x0a, + 0x37, 0xbf, 0x0b, 0xaf, 0x8d, 0xf1, 0xe8, 0x95, 0x4e, 0xba, 0x3f, 0x18, 0x70, 0x69, 0x24, 0x0d, + 0x88, 0x36, 0xc4, 0x09, 0x23, 0x55, 0x8a, 0x6f, 0x72, 0x00, 0x19, 0x4c, 0x73, 0xa4, 0x70, 0xe7, + 0xfa, 0x2c, 0x79, 0xad, 0x09, 0x49, 0x19, 0x7f, 0xa9, 0xc5, 0xbc, 0x0b, 0xd0, 0x27, 0xce, 0x74, + 0x17, 0xf9, 0x14, 0x4a, 0x2a, 0xc9, 0xaa, 0x5f, 0x54, 0x24, 0x84, 0x55, 0xc2, 0x08, 0x51, 0xfb, + 0x40, 0x28, 0x35, 0x23, 0x10, 0xb2, 0x3e, 0x87, 0x45, 0xca, 0xec, 0xd6, 0x8e, 0xe3, 0xb2, 0x8b, + 0xcf, 0x7b, 0x2c, 0x7e, 0xc7, 0x65, 0x0d, 0x84, 0xc1, 0x71, 0xf1, 0xab, 0x31, 0xb9, 0x07, 0x19, + 0x6a, 0x7b, 0x1d, 0xa6, 0x4c, 0xbf, 0x97, 0x60, 0x5a, 0x18, 0x41, 0x5e, 0x2a, 0x45, 0xac, 0xfb, + 0x90, 0xef, 0xd1, 0xb0, 0x75, 0x3d, 0x69, 0xb7, 0x23, 0x26, 0xdb, 0x60, 0x8a, 0xaa, 0x11, 0xd2, + 0xf7, 0x99, 0xd7, 0x51, 0xa6, 0x53, 0x54, 0x8d, 0xac, 0x65, 0xbc, 0x3b, 0xc6, 0x2b, 0x57, 0xa1, + 0x21, 0x90, 0xde, 0xc2, 0xbb, 0x82, 0x21, 0xea, 0x55, 0x7c, 0x5b, 0x2d, 0x04, 0x70, 0x76, 0x6b, + 0xcb, 0x09, 0x2f, 0x76, 0xb0, 0x0a, 0x0b, 0x5b, 0x4e, 0xa8, 0xf9, 0x17, 0x0f, 0xc9, 0x32, 0x42, + 0xbb, 0xa6, 0xdb, 0x6d, 0xa1, 0xb7, 0x9c, 0x85, 0x9e, 0x3a, 0xde, 0x86, 0xa8, 0xd6, 0x87, 0x32, + 0x8e, 0xc2, 0x8a, 0x5a, 0xcc, 0x0d, 0x58, 0x60, 0x1e, 0x0f, 0xb1, 0x8c, 0x24, 0xfe, 0x23, 0x35, + 0xf9, 0xac, 0x52, 0x13, 0xcf, 0x2a, 0x02, 0x67, 0xd2, 0x98, 0xc5, 0x5a, 0x87, 0x45, 0x24, 0x24, + 0x27, 0x82, 0x40, 0x5a, 0x5b, 0xa4, 0xf8, 0xb6, 0xee, 0x41, 0xa5, 0x2f, 0xa8, 0x4c, 0x2f, 0x43, + 0x1a, 0x2f, 0x42, 0xaa, 0xaf, 0x8f, 0xb3, 0x2b, 0xe6, 0xad, 0x77, 0x61, 0x31, 0x2e, 0xfe, 0x0b, + 0x8d, 0x5a, 0x04, 0x2a, 0x7d, 0x26, 0x85, 0x81, 0x4b, 0x50, 0x68, 0x38, 0x5e, 0x0c, 0x11, 0xad, + 0x97, 0x06, 0x14, 0x1b, 0xbe, 0xd7, 0x47, 0x3c, 0x0d, 0x58, 0x8c, 0x4b, 0xf7, 0x61, 0x63, 0x6f, + 0xd3, 0x0e, 0xe2, 0x18, 0x2c, 0x8d, 0xee, 0x0f, 0xf5, 0x30, 0x55, 0x93, 0x8c, 0x1b, 0x69, 0x3c, + 0xfe, 0xe8, 0xb0, 0x38, 0xf9, 0x08, 0x16, 0xf6, 0xf7, 0x37, 0x84, 0xa6, 0xf9, 0x99, 0x34, 0xc5, + 0x62, 0xe4, 0x01, 0x2c, 0x3c, 0x13, 0x8f, 0x72, 0x91, 0x3a, 0xa2, 0xc6, 0xec, 0x55, 0x19, 0x21, + 0xc9, 0x46, 0x59, 0xd3, 0x0f, 0x5b, 0x34, 0x16, 0xb2, 0xfe, 0x69, 0x40, 0xe1, 0x99, 0xdd, 0xbf, + 0x7e, 0xf4, 0xef, 0x3b, 0xaf, 0x70, 0x6e, 0xab, 0xfb, 0xce, 0x65, 0xc8, 0xb8, 0xec, 0x94, 0xb9, + 0x6a, 0x8f, 0xcb, 0x01, 0x52, 0xa3, 0x63, 0x3f, 0x94, 0x65, 0x5d, 0xa4, 0x72, 0x80, 0x05, 0xd1, + 0x62, 0xdc, 0x76, 0xdc, 0x6a, 0x7a, 0x29, 0x85, 0x67, 0xbc, 0x1c, 0x61, 0xe6, 0xba, 0xa1, 0xab, + 0x2e, 0xa1, 0xf8, 0x49, 0x2c, 0x48, 0x3b, 0x5e, 0xdb, 0x17, 0xe7, 0x9f, 0x6a, 0x8b, 0x0a, 0x80, + 0x78, 0x6d, 0x9f, 0x8a, 0x39, 0xf2, 0x0e, 0x64, 0x43, 0xac, 0xbf, 0xa8, 0xba, 0x20, 0x82, 0x92, + 0x47, 0x2e, 0x59, 0xa5, 0x6a, 0xc2, 0x2a, 0x43, 0x51, 0xfa, 0xad, 0x92, 0xff, 0xfb, 0x79, 0x78, + 0xed, 0x31, 0x3b, 0xdb, 0x8c, 0xfd, 0x8a, 0x03, 0xb2, 0x04, 0x85, 0x1e, 0x6d, 0x6f, 0x4b, 0x6d, + 0x21, 0x9d, 0x84, 0xc6, 0x0e, 0xfc, 0xae, 0xc7, 0xe3, 0x1c, 0x0a, 0x63, 0x82, 0x42, 0xd5, 0x04, + 0xb9, 0x0a, 0x0b, 0x8f, 0x19, 0x3f, 0xf3, 0xc3, 0xe7, 0xc2, 0xeb, 0xf2, 0x5a, 0x01, 0x79, 0x1e, + 0x33, 0x8e, 0x50, 0x91, 0xc6, 0x73, 0x88, 0x4c, 0x83, 0x18, 0x99, 0xa6, 0xc7, 0x21, 0xd3, 0x78, + 0x96, 0xac, 0x43, 0xa1, 0xe9, 0x7b, 0x11, 0x0f, 0x6d, 0x07, 0x0d, 0x67, 0x04, 0xf3, 0xeb, 0xc8, + 0x2c, 0x13, 0xbb, 0xd9, 0x9f, 0xa4, 0x3a, 0x27, 0x59, 0x05, 0x60, 0x2f, 0x78, 0x68, 0xef, 0xfa, + 0x51, 0xef, 0xba, 0x0e, 0x28, 0x87, 0x84, 0xbd, 0x06, 0xd5, 0x66, 0xb1, 0x43, 0x1e, 0xfb, 0x11, + 0x17, 0x77, 0x56, 0x79, 0xd5, 0xe8, 0x8d, 0xad, 0x37, 0xe0, 0xf2, 0x60, 0xb4, 0x54, 0x18, 0xef, + 0xc3, 0xff, 0x51, 0xe6, 0x32, 0x3b, 0x62, 0xb3, 0x47, 0xd2, 0x32, 0x11, 0xdb, 0x0f, 0x0b, 0x2b, + 0xc5, 0xff, 0x4a, 0x41, 0x61, 0xfb, 0x05, 0x6b, 0x1e, 0xb0, 0x28, 0xb2, 0x3b, 0xe2, 0x92, 0xd4, + 0x08, 0xfd, 0x26, 0x8b, 0xa2, 0x9e, 0xae, 0x3e, 0x81, 0x7c, 0x1b, 0xd2, 0x7b, 0x9e, 0xc3, 0xd5, + 0xd9, 0xb9, 0x9c, 0x78, 0x47, 0x75, 0xb8, 0xd2, 0xb9, 0x3b, 0x47, 0x85, 0x14, 0xb9, 0x07, 0x69, + 0xec, 0x3c, 0xd3, 0x74, 0xff, 0x96, 0x26, 0x8b, 0x32, 0x64, 0x43, 0xbc, 0x25, 0x3b, 0x9f, 0x31, + 0x95, 0xc1, 0x95, 0xe4, 0x63, 0xcb, 0xf9, 0x8c, 0xf5, 0x35, 0x28, 0x49, 0xb2, 0x8d, 0x57, 0x3c, + 0x3b, 0xe4, 0xac, 0xa5, 0x32, 0x7b, 0x2d, 0x09, 0x2c, 0x49, 0xce, 0xbe, 0x96, 0x58, 0x16, 0x83, + 0xb0, 0xfd, 0xc2, 0xe1, 0xaa, 0x52, 0x92, 0x82, 0x80, 0x6c, 0x9a, 0x23, 0x38, 0x44, 0xe9, 0x2d, + 0xdf, 0x93, 0x99, 0x4f, 0x96, 0x46, 0x36, 0x4d, 0x1a, 0x87, 0x18, 0x86, 0x43, 0xa7, 0x83, 0x18, + 0x34, 0x37, 0x31, 0x0c, 0x92, 0x51, 0x0b, 0x83, 0x24, 0x6c, 0x2c, 0x40, 0x46, 0x40, 0x24, 0xeb, + 0x2f, 0x06, 0x14, 0xb4, 0x3c, 0x4d, 0x51, 0x93, 0x6f, 0x41, 0x1a, 0x2f, 0x48, 0x2a, 0xff, 0x39, + 0x51, 0x91, 0x78, 0x61, 0x12, 0x54, 0x6c, 0x2a, 0x3b, 0x2d, 0xd9, 0x30, 0x4b, 0x14, 0x3f, 0x91, + 0xf2, 0x94, 0x9f, 0x8b, 0x94, 0xe5, 0x28, 0x7e, 0x92, 0x1b, 0x90, 0x3b, 0x64, 0xcd, 0x6e, 0xe8, + 0xf0, 0x73, 0x91, 0x84, 0xf2, 0x5a, 0x45, 0xb4, 0x1a, 0x45, 0x13, 0x85, 0xdb, 0xe3, 0x20, 0xd7, + 0x21, 0x1f, 0xb1, 0x66, 0xc8, 0x38, 0xf3, 0x4e, 0x55, 0x55, 0x95, 0x14, 0x7b, 0xc8, 0xf8, 0xb6, + 0x77, 0x4a, 0xfb, 0xf3, 0xd6, 0x23, 0xdc, 0xc9, 0x7d, 0x6f, 0x08, 0xa4, 0x37, 0xf1, 0x12, 0x89, + 0x6e, 0x94, 0xa8, 0xf8, 0x26, 0x2b, 0x90, 0xd9, 0x9e, 0xf4, 0x94, 0xb3, 0x1d, 0x3f, 0xe5, 0x0c, + 0xee, 0x00, 0x3c, 0xc6, 0xb4, 0x8c, 0x58, 0x0f, 0x21, 0xdf, 0xdb, 0xa5, 0xa4, 0x0c, 0xf3, 0x3b, + 0x2d, 0x65, 0x69, 0x7e, 0xa7, 0x85, 0x7e, 0x6f, 0x3f, 0xd9, 0x11, 0x56, 0x72, 0x14, 0x3f, 0x7b, + 0x68, 0x23, 0xa5, 0xa1, 0x8d, 0x75, 0x28, 0x0d, 0x6c, 0x55, 0x64, 0xa2, 0xfe, 0x59, 0x14, 0x2f, + 0x19, 0xbf, 0xa5, 0x1b, 0x6e, 0x24, 0x74, 0x09, 0x37, 0xdc, 0xc8, 0x7a, 0x17, 0x4a, 0x03, 0xc9, + 0x45, 0x26, 0x71, 0x9d, 0x56, 0xa0, 0x14, 0xbf, 0x57, 0x19, 0x2c, 0x0e, 0x3d, 0x94, 0x92, 0xab, + 0x90, 0x95, 0x0f, 0x72, 0x95, 0x39, 0xf3, 0xcd, 0x2f, 0xbe, 0x5c, 0x7a, 0x7d, 0x88, 0x41, 0x4e, + 0x22, 0xdb, 0x46, 0xd7, 0x6b, 0xb9, 0xac, 0x62, 0x8c, 0x65, 0x93, 0x93, 0x66, 0xfa, 0x17, 0xbf, + 0xbd, 0x32, 0xb7, 0x6a, 0xc3, 0xa5, 0x91, 0x47, 0x3e, 0xf2, 0x2e, 0xa4, 0x0f, 0x99, 0xdb, 0x8e, + 0xcd, 0x8c, 0x30, 0xe0, 0x24, 0x79, 0x07, 0x52, 0xd4, 0x3e, 0xab, 0x18, 0x66, 0xf5, 0x8b, 0x2f, + 0x97, 0x2e, 0x8f, 0xbe, 0x14, 0xda, 0x67, 0xd2, 0xc4, 0xda, 0x9f, 0x0a, 0x90, 0xdf, 0xdf, 0xdf, + 0xd8, 0x08, 0x9d, 0x56, 0x87, 0x91, 0x9f, 0x19, 0x40, 0x46, 0xdf, 0x4f, 0xc8, 0xed, 0xc9, 0xd7, + 0xee, 0xd1, 0xf7, 0x2a, 0xf3, 0xce, 0x8c, 0x52, 0x0a, 0xb2, 0xfc, 0x04, 0x2e, 0x8d, 0xbc, 0x1a, + 0x90, 0x5b, 0xd3, 0x5e, 0xfc, 0xb5, 0xb7, 0x15, 0xf3, 0xf6, 0x6c, 0x42, 0xca, 0xfe, 0x27, 0x90, + 0x11, 0x38, 0x9f, 0xbc, 0x3f, 0xe5, 0x75, 0xcf, 0x5c, 0x99, 0xcc, 0xa8, 0x74, 0x37, 0x21, 0x17, + 0x63, 0x65, 0xb2, 0x9a, 0xb8, 0xba, 0x81, 0xab, 0x80, 0x79, 0x7d, 0x2a, 0x5e, 0x65, 0xe4, 0x87, + 0xb0, 0xa0, 0x20, 0x30, 0xb9, 0x36, 0x41, 0xae, 0x0f, 0xc6, 0xcd, 0xd5, 0x69, 0x58, 0xfb, 0x6e, + 0xc4, 0x50, 0x37, 0xd1, 0x8d, 0x21, 0x20, 0x9d, 0xe8, 0xc6, 0x08, 0x76, 0x6e, 0xf6, 0x2f, 0xc8, + 0x89, 0x46, 0x86, 0x80, 0x73, 0xa2, 0x91, 0x61, 0xfc, 0x4c, 0x9e, 0x41, 0x1a, 0xf1, 0x33, 0x49, + 0x3a, 0x2b, 0x34, 0x80, 0x6d, 0x26, 0xed, 0x89, 0x01, 0xe0, 0xfd, 0x03, 0x3c, 0x53, 0xc5, 0x5b, + 0x48, 0xf2, 0x69, 0xaa, 0xbd, 0xa3, 0x9b, 0xd7, 0xa6, 0xe0, 0xec, 0xab, 0x57, 0xef, 0x08, 0x2b, + 0x53, 0x3c, 0x66, 0x4f, 0x56, 0x3f, 0xf4, 0x6c, 0xee, 0x43, 0x51, 0x87, 0x4a, 0xa4, 0x96, 0x20, + 0x3a, 0x06, 0x81, 0x9a, 0xf5, 0xa9, 0xf9, 0x95, 0xc1, 0xcf, 0xf1, 0x12, 0x39, 0x08, 0xa3, 0xc8, + 0x5a, 0x62, 0x38, 0xc6, 0x02, 0x36, 0xf3, 0xd6, 0x4c, 0x32, 0xca, 0xb8, 0x2d, 0x61, 0x9a, 0x82, + 0x62, 0x24, 0x19, 0x75, 0xf4, 0xe0, 0x9c, 0x39, 0x25, 0xdf, 0x8a, 0x71, 0xd3, 0xc0, 0x7d, 0x86, + 0xd0, 0x3d, 0x51, 0xb7, 0x76, 0xa7, 0x49, 0xdc, 0x67, 0xfa, 0x1d, 0x60, 0xa3, 0xf8, 0xf5, 0xcb, + 0x2b, 0xc6, 0x5f, 0x5f, 0x5e, 0x31, 0xfe, 0xfe, 0xf2, 0x8a, 0x71, 0x94, 0x15, 0xff, 0x0e, 0xb8, + 0xf5, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa0, 0x24, 0x02, 0x46, 0xa6, 0x21, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2833,6 +3024,8 @@ const _ = grpc.SupportPackageIsVersion4 type LLBBridgeClient interface { // apicaps:CapResolveImage ResolveImageConfig(ctx context.Context, in *ResolveImageConfigRequest, opts ...grpc.CallOption) (*ResolveImageConfigResponse, error) + // apicaps:CapSourceMetaResolver + ResolveSourceMeta(ctx context.Context, in *ResolveSourceMetaRequest, opts ...grpc.CallOption) (*ResolveSourceMetaResponse, error) // apicaps:CapSolveBase Solve(ctx context.Context, in *SolveRequest, opts ...grpc.CallOption) (*SolveResponse, error) // apicaps:CapReadFile @@ -2871,6 +3064,15 @@ func (c *lLBBridgeClient) ResolveImageConfig(ctx context.Context, in *ResolveIma return out, nil } +func (c *lLBBridgeClient) ResolveSourceMeta(ctx context.Context, in *ResolveSourceMetaRequest, opts ...grpc.CallOption) (*ResolveSourceMetaResponse, error) { + out := new(ResolveSourceMetaResponse) + err := c.cc.Invoke(ctx, "/moby.buildkit.v1.frontend.LLBBridge/ResolveSourceMeta", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *lLBBridgeClient) Solve(ctx context.Context, in *SolveRequest, opts ...grpc.CallOption) (*SolveResponse, error) { out := new(SolveResponse) err := c.cc.Invoke(ctx, "/moby.buildkit.v1.frontend.LLBBridge/Solve", in, out, opts...) @@ -3005,6 +3207,8 @@ func (c *lLBBridgeClient) Warn(ctx context.Context, in *WarnRequest, opts ...grp type LLBBridgeServer interface { // apicaps:CapResolveImage ResolveImageConfig(context.Context, *ResolveImageConfigRequest) (*ResolveImageConfigResponse, error) + // apicaps:CapSourceMetaResolver + ResolveSourceMeta(context.Context, *ResolveSourceMetaRequest) (*ResolveSourceMetaResponse, error) // apicaps:CapSolveBase Solve(context.Context, *SolveRequest) (*SolveResponse, error) // apicaps:CapReadFile @@ -3033,6 +3237,9 @@ type UnimplementedLLBBridgeServer struct { func (*UnimplementedLLBBridgeServer) ResolveImageConfig(ctx context.Context, req *ResolveImageConfigRequest) (*ResolveImageConfigResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ResolveImageConfig not implemented") } +func (*UnimplementedLLBBridgeServer) ResolveSourceMeta(ctx context.Context, req *ResolveSourceMetaRequest) (*ResolveSourceMetaResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResolveSourceMeta not implemented") +} func (*UnimplementedLLBBridgeServer) Solve(ctx context.Context, req *SolveRequest) (*SolveResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Solve not implemented") } @@ -3092,6 +3299,24 @@ func _LLBBridge_ResolveImageConfig_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _LLBBridge_ResolveSourceMeta_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResolveSourceMetaRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LLBBridgeServer).ResolveSourceMeta(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/moby.buildkit.v1.frontend.LLBBridge/ResolveSourceMeta", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LLBBridgeServer).ResolveSourceMeta(ctx, req.(*ResolveSourceMetaRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _LLBBridge_Solve_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SolveRequest) if err := dec(in); err != nil { @@ -3324,6 +3549,10 @@ var _LLBBridge_serviceDesc = grpc.ServiceDesc{ MethodName: "ResolveImageConfig", Handler: _LLBBridge_ResolveImageConfig_Handler, }, + { + MethodName: "ResolveSourceMeta", + Handler: _LLBBridge_ResolveSourceMeta_Handler, + }, { MethodName: "Solve", Handler: _LLBBridge_Solve_Handler, @@ -4166,7 +4395,7 @@ func (m *ResolveImageConfigResponse) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } -func (m *SolveRequest) Marshal() (dAtA []byte, err error) { +func (m *ResolveSourceMetaRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4176,12 +4405,12 @@ func (m *SolveRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *ResolveSourceMetaRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ResolveSourceMetaRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -4201,50 +4430,221 @@ func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGateway(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x7a + dAtA[i] = 0x42 } } - if m.Evaluate { + if len(m.ResolveMode) > 0 { + i -= len(m.ResolveMode) + copy(dAtA[i:], m.ResolveMode) + i = encodeVarintGateway(dAtA, i, uint64(len(m.ResolveMode))) i-- - if m.Evaluate { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } + dAtA[i] = 0x22 + } + if len(m.LogName) > 0 { + i -= len(m.LogName) + copy(dAtA[i:], m.LogName) + i = encodeVarintGateway(dAtA, i, uint64(len(m.LogName))) i-- - dAtA[i] = 0x70 + dAtA[i] = 0x1a } - if len(m.FrontendInputs) > 0 { - for k := range m.FrontendInputs { - v := m.FrontendInputs[k] - baseI := i - if v != nil { - { - size, err := v.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGateway(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 + if m.Platform != nil { + { + size, err := m.Platform.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i -= len(k) - copy(dAtA[i:], k) - i = encodeVarintGateway(dAtA, i, uint64(len(k))) - i-- - dAtA[i] = 0xa - i = encodeVarintGateway(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x6a + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x12 } - if len(m.CacheImports) > 0 { - for iNdEx := len(m.CacheImports) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.CacheImports[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { + if m.Source != nil { + { + size, err := m.Source.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveSourceMetaResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveSourceMetaResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveSourceMetaResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Image != nil { + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Source != nil { + { + size, err := m.Source.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveSourceImageResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveSourceImageResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveSourceImageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Config) > 0 { + i -= len(m.Config) + copy(dAtA[i:], m.Config) + i = encodeVarintGateway(dAtA, i, uint64(len(m.Config))) + i-- + dAtA[i] = 0x12 + } + if len(m.Digest) > 0 { + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) + i = encodeVarintGateway(dAtA, i, uint64(len(m.Digest))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SolveRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SolveRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.SourcePolicies) > 0 { + for iNdEx := len(m.SourcePolicies) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SourcePolicies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } + } + if m.Evaluate { + i-- + if m.Evaluate { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x70 + } + if len(m.FrontendInputs) > 0 { + for k := range m.FrontendInputs { + v := m.FrontendInputs[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGateway(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintGateway(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintGateway(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x6a + } + } + if len(m.CacheImports) > 0 { + for iNdEx := len(m.CacheImports) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CacheImports[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { return 0, err } i -= size @@ -5426,20 +5826,20 @@ func (m *InitMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x20 } if len(m.Fds) > 0 { - dAtA28 := make([]byte, len(m.Fds)*10) - var j27 int + dAtA32 := make([]byte, len(m.Fds)*10) + var j31 int for _, num := range m.Fds { for num >= 1<<7 { - dAtA28[j27] = uint8(uint64(num)&0x7f | 0x80) + dAtA32[j31] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j27++ + j31++ } - dAtA28[j27] = uint8(num) - j27++ + dAtA32[j31] = uint8(num) + j31++ } - i -= j27 - copy(dAtA[i:], dAtA28[:j27]) - i = encodeVarintGateway(dAtA, i, uint64(j27)) + i -= j31 + copy(dAtA[i:], dAtA32[:j31]) + i = encodeVarintGateway(dAtA, i, uint64(j31)) i-- dAtA[i] = 0x1a } @@ -6071,6 +6471,80 @@ func (m *ResolveImageConfigResponse) Size() (n int) { return n } +func (m *ResolveSourceMetaRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Source != nil { + l = m.Source.Size() + n += 1 + l + sovGateway(uint64(l)) + } + if m.Platform != nil { + l = m.Platform.Size() + n += 1 + l + sovGateway(uint64(l)) + } + l = len(m.LogName) + if l > 0 { + n += 1 + l + sovGateway(uint64(l)) + } + l = len(m.ResolveMode) + if l > 0 { + n += 1 + l + sovGateway(uint64(l)) + } + if len(m.SourcePolicies) > 0 { + for _, e := range m.SourcePolicies { + l = e.Size() + n += 1 + l + sovGateway(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResolveSourceMetaResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Source != nil { + l = m.Source.Size() + n += 1 + l + sovGateway(uint64(l)) + } + if m.Image != nil { + l = m.Image.Size() + n += 1 + l + sovGateway(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResolveSourceImageResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Digest) + if l > 0 { + n += 1 + l + sovGateway(uint64(l)) + } + l = len(m.Config) + if l > 0 { + n += 1 + l + sovGateway(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *SolveRequest) Size() (n int) { if m == nil { return 0 @@ -9102,6 +9576,467 @@ func (m *ResolveImageConfigResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResolveSourceMetaRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveSourceMetaRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveSourceMetaRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Source == nil { + m.Source = &pb.SourceOp{} + } + if err := m.Source.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Platform == nil { + m.Platform = &pb.Platform{} + } + if err := m.Platform.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LogName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LogName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResolveMode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ResolveMode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourcePolicies", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourcePolicies = append(m.SourcePolicies, &pb1.Policy{}) + if err := m.SourcePolicies[len(m.SourcePolicies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGateway(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGateway + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveSourceMetaResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveSourceMetaResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveSourceMetaResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Source == nil { + m.Source = &pb.SourceOp{} + } + if err := m.Source.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Image", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Image == nil { + m.Image = &ResolveSourceImageResponse{} + } + if err := m.Image.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGateway(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGateway + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveSourceImageResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveSourceImageResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveSourceImageResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGateway + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGateway + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGateway + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Config = append(m.Config[:0], dAtA[iNdEx:postIndex]...) + if m.Config == nil { + m.Config = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGateway(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGateway + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *SolveRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto index c00d97391a43b..f34d8c6c9c73f 100644 --- a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto +++ b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto @@ -2,15 +2,13 @@ syntax = "proto3"; package moby.buildkit.v1.frontend; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "github.com/gogo/googleapis/google/rpc/status.proto"; -import "github.com/moby/buildkit/solver/pb/ops.proto"; +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; import "github.com/moby/buildkit/api/types/worker.proto"; +import "github.com/moby/buildkit/solver/pb/ops.proto"; +import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto"; import "github.com/moby/buildkit/util/apicaps/pb/caps.proto"; import "github.com/tonistiigi/fsutil/types/stat.proto"; -import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto"; - - option (gogoproto.sizer_all) = true; option (gogoproto.marshaler_all) = true; @@ -19,6 +17,8 @@ option (gogoproto.unmarshaler_all) = true; service LLBBridge { // apicaps:CapResolveImage rpc ResolveImageConfig(ResolveImageConfigRequest) returns (ResolveImageConfigResponse); + // apicaps:CapSourceMetaResolver + rpc ResolveSourceMeta(ResolveSourceMetaRequest) returns (ResolveSourceMetaResponse); // apicaps:CapSolveBase rpc Solve(SolveRequest) returns (SolveResponse); // apicaps:CapReadFile @@ -70,7 +70,7 @@ message RefMap { } message Attestations { - repeated Attestation attestation = 1; + repeated Attestation attestation = 1; } message Attestation { @@ -134,6 +134,24 @@ message ResolveImageConfigResponse { string Ref = 3; } +message ResolveSourceMetaRequest { + pb.SourceOp Source = 1; + pb.Platform Platform = 2; + string LogName = 3; + string ResolveMode = 4; + repeated moby.buildkit.v1.sourcepolicy.Policy SourcePolicies = 8; +} + +message ResolveSourceMetaResponse { + pb.SourceOp Source = 1; + ResolveSourceImageResponse Image = 2; +} + +message ResolveSourceImageResponse { + string Digest = 1 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false]; + bytes Config = 2; +} + message SolveRequest { pb.Definition Definition = 1; string Frontend = 2; @@ -167,7 +185,7 @@ message SolveResponse { // deprecated string ref = 1; // can be used by readfile request // deprecated -/* bytes ExporterAttr = 2;*/ + // bytes ExporterAttr = 2; // these fields are returned when allowMapReturn was set Result result = 3; diff --git a/vendor/github.com/moby/buildkit/session/auth/auth.proto b/vendor/github.com/moby/buildkit/session/auth/auth.proto index 139b0d0e3903d..1b4667b91fa5b 100644 --- a/vendor/github.com/moby/buildkit/session/auth/auth.proto +++ b/vendor/github.com/moby/buildkit/session/auth/auth.proto @@ -5,10 +5,10 @@ package moby.filesync.v1; option go_package = "auth"; service Auth{ - rpc Credentials(CredentialsRequest) returns (CredentialsResponse); - rpc FetchToken(FetchTokenRequest) returns (FetchTokenResponse); - rpc GetTokenAuthority(GetTokenAuthorityRequest) returns (GetTokenAuthorityResponse); - rpc VerifyTokenAuthority(VerifyTokenAuthorityRequest) returns (VerifyTokenAuthorityResponse); + rpc Credentials(CredentialsRequest) returns (CredentialsResponse); + rpc FetchToken(FetchTokenRequest) returns (FetchTokenResponse); + rpc GetTokenAuthority(GetTokenAuthorityRequest) returns (GetTokenAuthorityResponse); + rpc VerifyTokenAuthority(VerifyTokenAuthorityRequest) returns (VerifyTokenAuthorityResponse); } message CredentialsRequest { diff --git a/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go b/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go index 27bc5d5414962..56bffe5355d0a 100644 --- a/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go +++ b/vendor/github.com/moby/buildkit/session/filesync/diffcopy.go @@ -47,6 +47,22 @@ type streamWriterCloser struct { } func (wc *streamWriterCloser) Write(dt []byte) (int, error) { + // grpc-go has a 4MB limit on messages by default. Split large messages + // so we don't get close to that limit. + const maxChunkSize = 3 * 1024 * 1024 + if len(dt) > maxChunkSize { + n1, err := wc.Write(dt[:maxChunkSize]) + if err != nil { + return n1, err + } + dt = dt[maxChunkSize:] + var n2 int + if n2, err = wc.Write(dt); err != nil { + return n1 + n2, err + } + return n1 + n2, nil + } + if err := wc.ClientStream.SendMsg(&BytesMessage{Data: dt}); err != nil { // SendMsg return EOF on remote errors if errors.Is(err, io.EOF) { diff --git a/vendor/github.com/moby/buildkit/session/filesync/filesync.go b/vendor/github.com/moby/buildkit/session/filesync/filesync.go index d299d7ad9ea56..30d4545cf3b57 100644 --- a/vendor/github.com/moby/buildkit/session/filesync/filesync.go +++ b/vendor/github.com/moby/buildkit/session/filesync/filesync.go @@ -11,6 +11,7 @@ import ( "unicode" "github.com/moby/buildkit/session" + "github.com/moby/buildkit/util/bklog" "github.com/pkg/errors" "github.com/tonistiigi/fsutil" fstypes "github.com/tonistiigi/fsutil/types" @@ -21,12 +22,13 @@ import ( ) const ( - keyOverrideExcludes = "override-excludes" keyIncludePatterns = "include-patterns" keyExcludePatterns = "exclude-patterns" keyFollowPaths = "followpaths" keyDirName = "dir-name" keyExporterMetaPrefix = "exporter-md-" + + keyExporterID = "buildkit-attachable-exporter-id" ) type fsSyncProvider struct { @@ -35,21 +37,22 @@ type fsSyncProvider struct { doneCh chan error } +type FileOutputFunc func(map[string]string) (io.WriteCloser, error) + type SyncedDir struct { - Dir string - Excludes []string - Map func(string, *fstypes.Stat) fsutil.MapResult + Dir string + Map func(string, *fstypes.Stat) fsutil.MapResult } type DirSource interface { - LookupDir(string) (SyncedDir, bool) + LookupDir(string) (fsutil.FS, bool) } -type StaticDirSource map[string]SyncedDir +type StaticDirSource map[string]fsutil.FS var _ DirSource = StaticDirSource{} -func (dirs StaticDirSource) LookupDir(name string) (SyncedDir, bool) { +func (dirs StaticDirSource) LookupDir(name string) (fsutil.FS, bool) { dir, found := dirs[name] return dir, found } @@ -93,18 +96,22 @@ func (sp *fsSyncProvider) handle(method string, stream grpc.ServerStream) (retEr dirName = name[0] } + excludes := opts[keyExcludePatterns] + includes := opts[keyIncludePatterns] + followPaths := opts[keyFollowPaths] + dir, ok := sp.dirs.LookupDir(dirName) if !ok { return InvalidSessionError{status.Errorf(codes.NotFound, "no access allowed to dir %q", dirName)} } - - excludes := opts[keyExcludePatterns] - if len(dir.Excludes) != 0 && (len(opts[keyOverrideExcludes]) == 0 || opts[keyOverrideExcludes][0] != "true") { - excludes = dir.Excludes + dir, err := fsutil.NewFilterFS(dir, &fsutil.FilterOpt{ + ExcludePatterns: excludes, + IncludePatterns: includes, + FollowPaths: followPaths, + }) + if err != nil { + return err } - includes := opts[keyIncludePatterns] - - followPaths := opts[keyFollowPaths] var progress progressCb if sp.p != nil { @@ -117,12 +124,7 @@ func (sp *fsSyncProvider) handle(method string, stream grpc.ServerStream) (retEr doneCh = sp.doneCh sp.doneCh = nil } - err := pr.sendFn(stream, fsutil.NewFS(dir.Dir, &fsutil.WalkOpt{ - ExcludePatterns: excludes, - IncludePatterns: includes, - FollowPaths: followPaths, - Map: dir.Map, - }), progress) + err = pr.sendFn(stream, dir, progress) if doneCh != nil { if err != nil { doneCh <- err @@ -155,16 +157,15 @@ var supportedProtocols = []protocol{ // FSSendRequestOpt defines options for FSSend request type FSSendRequestOpt struct { - Name string - IncludePatterns []string - ExcludePatterns []string - FollowPaths []string - OverrideExcludes bool // deprecated: this is used by docker/cli for automatically loading .dockerignore from the directory - DestDir string - CacheUpdater CacheUpdater - ProgressCb func(int, bool) - Filter func(string, *fstypes.Stat) bool - Differ fsutil.DiffType + Name string + IncludePatterns []string + ExcludePatterns []string + FollowPaths []string + DestDir string + CacheUpdater CacheUpdater + ProgressCb func(int, bool) + Filter func(string, *fstypes.Stat) bool + Differ fsutil.DiffType } // CacheUpdater is an object capable of sending notifications for the cache hash changes @@ -188,9 +189,6 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error { } opts := make(map[string][]string) - if opt.OverrideExcludes { - opts[keyOverrideExcludes] = []string{"true"} - } if opt.IncludePatterns != nil { opts[keyIncludePatterns] = opt.IncludePatterns @@ -206,8 +204,8 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error { opts[keyDirName] = []string{opt.Name} - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(errors.WithStack(context.Canceled)) client := NewFileSyncClient(c.Conn()) @@ -237,39 +235,87 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error { return pr.recvFn(stream, opt.DestDir, opt.CacheUpdater, opt.ProgressCb, opt.Differ, opt.Filter) } -// NewFSSyncTargetDir allows writing into a directory -func NewFSSyncTargetDir(outdir string) session.Attachable { - p := &fsSyncTarget{ +type FSSyncTarget interface { + target() *fsSyncTarget +} + +type fsSyncTarget struct { + id int + outdir string + f FileOutputFunc +} + +func (target *fsSyncTarget) target() *fsSyncTarget { + return target +} + +func WithFSSync(id int, f FileOutputFunc) FSSyncTarget { + return &fsSyncTarget{ + id: id, + f: f, + } +} + +func WithFSSyncDir(id int, outdir string) FSSyncTarget { + return &fsSyncTarget{ + id: id, outdir: outdir, } - return p } -// NewFSSyncTarget allows writing into an io.WriteCloser -func NewFSSyncTarget(f func(map[string]string) (io.WriteCloser, error)) session.Attachable { - p := &fsSyncTarget{ - f: f, +func NewFSSyncTarget(targets ...FSSyncTarget) session.Attachable { + fs := make(map[int]FileOutputFunc) + outdirs := make(map[int]string) + for _, t := range targets { + t := t.target() + if t.f != nil { + fs[t.id] = t.f + } + if t.outdir != "" { + outdirs[t.id] = t.outdir + } + } + return &fsSyncAttachable{ + fs: fs, + outdirs: outdirs, } - return p } -type fsSyncTarget struct { - outdir string - f func(map[string]string) (io.WriteCloser, error) +type fsSyncAttachable struct { + fs map[int]FileOutputFunc + outdirs map[int]string } -func (sp *fsSyncTarget) Register(server *grpc.Server) { +func (sp *fsSyncAttachable) Register(server *grpc.Server) { RegisterFileSendServer(server, sp) } -func (sp *fsSyncTarget) DiffCopy(stream FileSend_DiffCopyServer) (err error) { - if sp.outdir != "" { - return syncTargetDiffCopy(stream, sp.outdir) +func (sp *fsSyncAttachable) chooser(ctx context.Context) int { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return 0 + } + values := md[keyExporterID] + if len(values) == 0 { + return 0 } + id, err := strconv.ParseInt(values[0], 10, 64) + if err != nil { + return 0 + } + return int(id) +} - if sp.f == nil { - return errors.New("empty outfile and outdir") +func (sp *fsSyncAttachable) DiffCopy(stream FileSend_DiffCopyServer) (err error) { + id := sp.chooser(stream.Context()) + if outdir, ok := sp.outdirs[id]; ok { + return syncTargetDiffCopy(stream, outdir) } + f, ok := sp.fs[id] + if !ok { + return errors.Errorf("exporter %d not found", id) + } + opts, _ := metadata.FromIncomingContext(stream.Context()) // if no metadata continue with empty object md := map[string]string{} for k, v := range opts { @@ -277,7 +323,7 @@ func (sp *fsSyncTarget) DiffCopy(stream FileSend_DiffCopyServer) (err error) { md[strings.TrimPrefix(k, keyExporterMetaPrefix)] = strings.Join(v, ",") } } - wc, err := sp.f(md) + wc, err := f(md) if err != nil { return err } @@ -293,7 +339,7 @@ func (sp *fsSyncTarget) DiffCopy(stream FileSend_DiffCopyServer) (err error) { return writeTargetFile(stream, wc) } -func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress func(int, bool)) error { +func CopyToCaller(ctx context.Context, fs fsutil.FS, id int, c session.Caller, progress func(int, bool)) error { method := session.MethodURL(_FileSend_serviceDesc.ServiceName, "diffcopy") if !c.Supports(method) { return errors.Errorf("method %s not supported by the client", method) @@ -301,6 +347,16 @@ func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress client := NewFileSendClient(c.Conn()) + opts, ok := metadata.FromOutgoingContext(ctx) + if !ok { + opts = make(map[string][]string) + } + if existingVal, ok := opts[keyExporterID]; ok { + bklog.G(ctx).Warnf("overwriting grpc metadata key %q from value %+v to %+v", keyExporterID, existingVal, id) + } + opts[keyExporterID] = []string{fmt.Sprint(id)} + ctx = metadata.NewOutgoingContext(ctx, opts) + cc, err := client.DiffCopy(ctx) if err != nil { return errors.WithStack(err) @@ -309,7 +365,7 @@ func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress return sendDiffCopy(cc, fs, progress) } -func CopyFileWriter(ctx context.Context, md map[string]string, c session.Caller) (io.WriteCloser, error) { +func CopyFileWriter(ctx context.Context, md map[string]string, id int, c session.Caller) (io.WriteCloser, error) { method := session.MethodURL(_FileSend_serviceDesc.ServiceName, "diffcopy") if !c.Supports(method) { return nil, errors.Errorf("method %s not supported by the client", method) @@ -317,11 +373,21 @@ func CopyFileWriter(ctx context.Context, md map[string]string, c session.Caller) client := NewFileSendClient(c.Conn()) - opts := make(map[string][]string, len(md)) + opts, ok := metadata.FromOutgoingContext(ctx) + if !ok { + opts = make(map[string][]string, len(md)) + } for k, v := range md { - opts[keyExporterMetaPrefix+k] = []string{v} + k := keyExporterMetaPrefix + k + if existingVal, ok := opts[k]; ok { + bklog.G(ctx).Warnf("overwriting grpc metadata key %q from value %+v to %+v", k, existingVal, v) + } + opts[k] = []string{v} } - + if existingVal, ok := opts[keyExporterID]; ok { + bklog.G(ctx).Warnf("overwriting grpc metadata key %q from value %+v to %+v", keyExporterID, existingVal, id) + } + opts[keyExporterID] = []string{fmt.Sprint(id)} ctx = metadata.NewOutgoingContext(ctx, opts) cc, err := client.DiffCopy(ctx) @@ -360,13 +426,13 @@ func decodeOpts(opts map[string][]string) map[string][]string { md := make(map[string][]string, len(opts)) for k, v := range opts { out := make([]string, len(v)) - var isDecoded bool + var isEncoded bool if v, ok := opts[k+"-encoded"]; ok && len(v) > 0 { if b, _ := strconv.ParseBool(v[0]); b { - isDecoded = true + isEncoded = true } } - if isDecoded { + if isEncoded { for i, s := range v { out[i], _ = url.QueryUnescape(s) } @@ -382,13 +448,14 @@ func decodeOpts(opts map[string][]string) map[string][]string { // is backwards compatible and avoids encoding ASCII characters. func encodeStringForHeader(inputs []string) ([]string, bool) { var encode bool +loop: for _, input := range inputs { for _, runeVal := range input { // Only encode non-ASCII characters, and characters that have special // meaning during decoding. if runeVal > unicode.MaxASCII { encode = true - break + break loop } } } diff --git a/vendor/github.com/moby/buildkit/session/filesync/filesync.proto b/vendor/github.com/moby/buildkit/session/filesync/filesync.proto index 9e39179285ee9..68162d8a38f44 100644 --- a/vendor/github.com/moby/buildkit/session/filesync/filesync.proto +++ b/vendor/github.com/moby/buildkit/session/filesync/filesync.proto @@ -6,17 +6,18 @@ option go_package = "filesync"; import "github.com/tonistiigi/fsutil/types/wire.proto"; +// FileSync exposes local files from the client to the server. service FileSync{ - rpc DiffCopy(stream fsutil.types.Packet) returns (stream fsutil.types.Packet); - rpc TarStream(stream fsutil.types.Packet) returns (stream fsutil.types.Packet); + rpc DiffCopy(stream fsutil.types.Packet) returns (stream fsutil.types.Packet); + rpc TarStream(stream fsutil.types.Packet) returns (stream fsutil.types.Packet); } +// FileSend allows sending files from the server back to the client. service FileSend{ - rpc DiffCopy(stream BytesMessage) returns (stream BytesMessage); + rpc DiffCopy(stream BytesMessage) returns (stream BytesMessage); } - // BytesMessage contains a chunk of byte data -message BytesMessage{ +message BytesMessage { bytes data = 1; } diff --git a/vendor/github.com/moby/buildkit/session/group.go b/vendor/github.com/moby/buildkit/session/group.go index 4b9ba221f5fea..e701d1d292060 100644 --- a/vendor/github.com/moby/buildkit/session/group.go +++ b/vendor/github.com/moby/buildkit/session/group.go @@ -72,8 +72,9 @@ func (sm *Manager) Any(ctx context.Context, g Group, f func(context.Context, str return errors.Errorf("no active sessions") } - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) c, err := sm.Get(timeoutCtx, id, false) if err != nil { lastErr = err diff --git a/vendor/github.com/moby/buildkit/session/grpc.go b/vendor/github.com/moby/buildkit/session/grpc.go index bf8180722adfc..0bc0652546b1b 100644 --- a/vendor/github.com/moby/buildkit/session/grpc.go +++ b/vendor/github.com/moby/buildkit/session/grpc.go @@ -7,6 +7,7 @@ import ( "sync/atomic" "time" + "github.com/containerd/containerd/defaults" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/grpcerrors" @@ -44,11 +45,13 @@ func grpcClientConn(ctx context.Context, conn net.Conn) (context.Context, *grpc. dialOpts := []grpc.DialOption{ dialer, grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), } if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { - unary = append(unary, filterClient(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) - stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) + unary = append(unary, filterClient(otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 + stream = append(stream, otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 } unary = append(unary, grpcerrors.UnaryClientInterceptor) @@ -71,14 +74,14 @@ func grpcClientConn(ctx context.Context, conn net.Conn) (context.Context, *grpc. return nil, nil, errors.Wrap(err, "failed to create grpc client") } - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) go monitorHealth(ctx, cc, cancel) return ctx, cc, nil } -func monitorHealth(ctx context.Context, cc *grpc.ClientConn, cancelConn func()) { - defer cancelConn() +func monitorHealth(ctx context.Context, cc *grpc.ClientConn, cancelConn func(error)) { + defer cancelConn(errors.WithStack(context.Canceled)) defer cc.Close() ticker := time.NewTicker(5 * time.Second) @@ -101,9 +104,11 @@ func monitorHealth(ctx context.Context, cc *grpc.ClientConn, cancelConn func()) healthcheckStart := time.Now() timeout := time.Duration(math.Max(float64(defaultHealthcheckDuration), float64(lastHealthcheckDuration)*1.5)) - ctx, cancel := context.WithTimeout(ctx, timeout) + + ctx, cancel := context.WithCancelCause(ctx) + ctx, _ = context.WithTimeoutCause(ctx, timeout, errors.WithStack(context.DeadlineExceeded)) _, err := healthClient.Check(ctx, &grpc_health_v1.HealthCheckRequest{}) - cancel() + cancel(errors.WithStack(context.Canceled)) lastHealthcheckDuration = time.Since(healthcheckStart) logFields := logrus.Fields{ diff --git a/vendor/github.com/moby/buildkit/session/manager.go b/vendor/github.com/moby/buildkit/session/manager.go index 2678e6738dab5..2eda89d2be075 100644 --- a/vendor/github.com/moby/buildkit/session/manager.go +++ b/vendor/github.com/moby/buildkit/session/manager.go @@ -99,8 +99,8 @@ func (sm *Manager) HandleConn(ctx context.Context, conn net.Conn, opts map[strin // caller needs to take lock, this function will release it func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[string][]string) error { - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(errors.WithStack(context.Canceled)) opts = canonicalHeaders(opts) @@ -156,8 +156,8 @@ func (sm *Manager) Get(ctx context.Context, id string, noWait bool) (Caller, err id = p[1] } - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(errors.WithStack(context.Canceled)) go func() { <-ctx.Done() @@ -173,7 +173,7 @@ func (sm *Manager) Get(ctx context.Context, id string, noWait bool) (Caller, err select { case <-ctx.Done(): sm.mu.Unlock() - return nil, errors.Wrapf(ctx.Err(), "no active session for %s", id) + return nil, errors.Wrapf(context.Cause(ctx), "no active session for %s", id) default: } var ok bool diff --git a/vendor/github.com/moby/buildkit/session/secrets/secrets.proto b/vendor/github.com/moby/buildkit/session/secrets/secrets.proto index 17d862450d9c6..0860e59bcda85 100644 --- a/vendor/github.com/moby/buildkit/session/secrets/secrets.proto +++ b/vendor/github.com/moby/buildkit/session/secrets/secrets.proto @@ -5,7 +5,7 @@ package moby.buildkit.secrets.v1; option go_package = "secrets"; service Secrets{ - rpc GetSecret(GetSecretRequest) returns (GetSecretResponse); + rpc GetSecret(GetSecretRequest) returns (GetSecretResponse); } diff --git a/vendor/github.com/moby/buildkit/session/session.go b/vendor/github.com/moby/buildkit/session/session.go index f56a18730d22e..5a1ffcb58eeca 100644 --- a/vendor/github.com/moby/buildkit/session/session.go +++ b/vendor/github.com/moby/buildkit/session/session.go @@ -42,7 +42,7 @@ type Session struct { name string sharedKey string ctx context.Context - cancelCtx func() + cancelCtx func(error) done chan struct{} grpcServer *grpc.Server conn net.Conn @@ -59,8 +59,8 @@ func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) { serverOpts := []grpc.ServerOption{} if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { - unary = append(unary, filterServer(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) - stream = append(stream, otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) + unary = append(unary, filterServer(otelgrpc.UnaryServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators)))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 + stream = append(stream, otelgrpc.StreamServerInterceptor(otelgrpc.WithTracerProvider(span.TracerProvider()), otelgrpc.WithPropagators(propagators))) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/buildkit/issues/4681 } unary = append(unary, grpcerrors.UnaryServerInterceptor) @@ -107,11 +107,11 @@ func (s *Session) Run(ctx context.Context, dialer Dialer) error { s.mu.Unlock() return nil } - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) s.cancelCtx = cancel s.done = make(chan struct{}) - defer cancel() + defer cancel(errors.WithStack(context.Canceled)) defer close(s.done) meta := make(map[string][]string) diff --git a/vendor/github.com/moby/buildkit/session/sshforward/copy.go b/vendor/github.com/moby/buildkit/session/sshforward/copy.go index eac5f7614a7d3..804debd16df41 100644 --- a/vendor/github.com/moby/buildkit/session/sshforward/copy.go +++ b/vendor/github.com/moby/buildkit/session/sshforward/copy.go @@ -39,7 +39,7 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream Stream, closeStre select { case <-ctx.Done(): conn.Close() - return ctx.Err() + return context.Cause(ctx) default: } if _, err := conn.Write(p.Data); err != nil { @@ -65,7 +65,7 @@ func Copy(ctx context.Context, conn io.ReadWriteCloser, stream Stream, closeStre } select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) default: } p := &BytesMessage{Data: buf[:n]} diff --git a/vendor/github.com/moby/buildkit/session/sshforward/ssh.go b/vendor/github.com/moby/buildkit/session/sshforward/ssh.go index a808fcb1f077d..8a041b311f769 100644 --- a/vendor/github.com/moby/buildkit/session/sshforward/ssh.go +++ b/vendor/github.com/moby/buildkit/session/sshforward/ssh.go @@ -26,7 +26,7 @@ func (s *server) run(ctx context.Context, l net.Listener, id string) error { eg.Go(func() error { <-ctx.Done() - return ctx.Err() + return context.Cause(ctx) }) eg.Go(func() error { diff --git a/vendor/github.com/moby/buildkit/snapshot/diffapply_freebsd.go b/vendor/github.com/moby/buildkit/snapshot/diffapply_freebsd.go new file mode 100644 index 0000000000000..ffc50cd744a33 --- /dev/null +++ b/vendor/github.com/moby/buildkit/snapshot/diffapply_freebsd.go @@ -0,0 +1,17 @@ +package snapshot + +import ( + "context" + + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/snapshots" + "github.com/pkg/errors" +) + +func (sn *mergeSnapshotter) diffApply(ctx context.Context, dest Mountable, diffs ...Diff) (_ snapshots.Usage, rerr error) { + return snapshots.Usage{}, errors.New("diffApply not yet supported on FreeBSD") +} + +func needsUserXAttr(ctx context.Context, sn Snapshotter, lm leases.Manager) (bool, error) { + return false, errors.New("needs userxattr not supported on FreeBSD") +} diff --git a/vendor/github.com/moby/buildkit/snapshot/diffapply_unix.go b/vendor/github.com/moby/buildkit/snapshot/diffapply_unix.go index c4875000ea9e6..ddba5d117f7a1 100644 --- a/vendor/github.com/moby/buildkit/snapshot/diffapply_unix.go +++ b/vendor/github.com/moby/buildkit/snapshot/diffapply_unix.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build !windows && !freebsd +// +build !windows,!freebsd package snapshot @@ -600,8 +600,10 @@ func (d *differ) doubleWalkingChanges(ctx context.Context, handle func(context.C if prevErr != nil { return prevErr } - if ctx.Err() != nil { - return ctx.Err() + select { + case <-ctx.Done(): + return context.Cause(ctx) + default: } if kind == fs.ChangeKindUnmodified { @@ -689,8 +691,11 @@ func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context if prevErr != nil { return prevErr } - if ctx.Err() != nil { - return ctx.Err() + + select { + case <-ctx.Done(): + return context.Cause(ctx) + default: } if kind == fs.ChangeKindUnmodified { @@ -719,7 +724,10 @@ func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context return errors.Errorf("unhandled stat type for %+v", srcfi) } - if !srcfi.IsDir() && c.srcStat.Nlink > 1 { + // Changes with Delete kind may share the same inode even if they are unrelated. + // Skip them to avoid creating hardlinks between whiteouts as whiteouts are not + // always created and may leave the hardlink dangling. + if !srcfi.IsDir() && c.srcStat.Nlink > 1 && c.kind != fs.ChangeKindDelete { if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok { c.linkSubPath = linkSubPath } else { diff --git a/vendor/github.com/moby/buildkit/snapshot/localmounter_freebsd.go b/vendor/github.com/moby/buildkit/snapshot/localmounter_freebsd.go new file mode 100644 index 0000000000000..4c9f1774ead5e --- /dev/null +++ b/vendor/github.com/moby/buildkit/snapshot/localmounter_freebsd.go @@ -0,0 +1,66 @@ +package snapshot + +import ( + "os" + + "github.com/containerd/containerd/mount" + "github.com/pkg/errors" +) + +func (lm *localMounter) Mount() (string, error) { + lm.mu.Lock() + defer lm.mu.Unlock() + + if lm.mounts == nil && lm.mountable != nil { + mounts, release, err := lm.mountable.Mount() + if err != nil { + return "", err + } + lm.mounts = mounts + lm.release = release + } + + if !lm.forceRemount && len(lm.mounts) == 1 && lm.mounts[0].Type == "nullfs" { + ro := false + for _, opt := range lm.mounts[0].Options { + if opt == "ro" { + ro = true + break + } + } + if !ro { + return lm.mounts[0].Source, nil + } + } + + dir, err := os.MkdirTemp("", "buildkit-mount") + if err != nil { + return "", errors.Wrap(err, "failed to create temp dir") + } + + if err := mount.All(lm.mounts, dir); err != nil { + os.RemoveAll(dir) + return "", errors.Wrapf(err, "failed to mount %s: %+v", dir, lm.mounts) + } + lm.target = dir + return dir, nil +} + +func (lm *localMounter) Unmount() error { + lm.mu.Lock() + defer lm.mu.Unlock() + + if lm.target != "" { + if err := mount.Unmount(lm.target, 0); err != nil { + return err + } + os.RemoveAll(lm.target) + lm.target = "" + } + + if lm.release != nil { + return lm.release() + } + + return nil +} diff --git a/vendor/github.com/moby/buildkit/snapshot/localmounter_unix.go b/vendor/github.com/moby/buildkit/snapshot/localmounter_linux.go similarity index 97% rename from vendor/github.com/moby/buildkit/snapshot/localmounter_unix.go rename to vendor/github.com/moby/buildkit/snapshot/localmounter_linux.go index 0e1f40f298c45..7c7848497490c 100644 --- a/vendor/github.com/moby/buildkit/snapshot/localmounter_unix.go +++ b/vendor/github.com/moby/buildkit/snapshot/localmounter_linux.go @@ -1,6 +1,3 @@ -//go:build !windows -// +build !windows - package snapshot import ( diff --git a/vendor/github.com/moby/buildkit/snapshot/merge.go b/vendor/github.com/moby/buildkit/snapshot/merge.go index b565a844844c0..2d589087c8ec2 100644 --- a/vendor/github.com/moby/buildkit/snapshot/merge.go +++ b/vendor/github.com/moby/buildkit/snapshot/merge.go @@ -185,12 +185,14 @@ func mergeUsageOf(info snapshots.Info) (usage snapshots.Usage, ok bool, rerr err if info.Labels == nil { return snapshots.Usage{}, false, nil } + hasMergeUsageLabel := false if str, ok := info.Labels[mergeUsageSizeLabel]; ok { i, err := strconv.Atoi(str) if err != nil { return snapshots.Usage{}, false, err } usage.Size = int64(i) + hasMergeUsageLabel = true } if str, ok := info.Labels[mergeUsageInodesLabel]; ok { i, err := strconv.Atoi(str) @@ -198,6 +200,10 @@ func mergeUsageOf(info snapshots.Info) (usage snapshots.Usage, ok bool, rerr err return snapshots.Usage{}, false, err } usage.Inodes = int64(i) + hasMergeUsageLabel = true + } + if !hasMergeUsageLabel { + return snapshots.Usage{}, false, nil } return usage, true, nil } diff --git a/vendor/github.com/moby/buildkit/solver/cachekey.go b/vendor/github.com/moby/buildkit/solver/cachekey.go index 9617789de0529..90a10b8cbd33c 100644 --- a/vendor/github.com/moby/buildkit/solver/cachekey.go +++ b/vendor/github.com/moby/buildkit/solver/cachekey.go @@ -24,12 +24,20 @@ type CacheKeyWithSelector struct { CacheKey ExportableCacheKey } +func (ck CacheKeyWithSelector) TraceFields() map[string]any { + fields := ck.CacheKey.TraceFields() + fields["selector"] = ck.Selector.String() + return fields +} + type CacheKey struct { mu sync.RWMutex - ID string - deps [][]CacheKeyWithSelector // only [][]*inMemoryCacheKey + ID string + deps [][]CacheKeyWithSelector + // digest is the digest returned by the CacheMap implementation of this op digest digest.Digest + // vtx is the LLB digest that this op was created for vtx digest.Digest output Index ids map[*cacheManager]string @@ -37,6 +45,35 @@ type CacheKey struct { indexIDs []string } +func (ck *CacheKey) TraceFields() map[string]any { + ck.mu.RLock() + defer ck.mu.RUnlock() + idsMap := map[string]string{} + for cm, id := range ck.ids { + idsMap[cm.ID()] = id + } + + // don't recurse more than one level in showing deps + depsMap := make([]map[string]string, len(ck.deps)) + for i, deps := range ck.deps { + depsMap[i] = map[string]string{} + for _, ck := range deps { + depsMap[i]["id"] = ck.CacheKey.ID + depsMap[i]["selector"] = ck.Selector.String() + } + } + + return map[string]any{ + "id": ck.ID, + "digest": ck.digest, + "vtx": ck.vtx, + "output": ck.output, + "indexIDs": ck.indexIDs, + "ids": idsMap, + "deps": depsMap, + } +} + func (ck *CacheKey) Deps() [][]CacheKeyWithSelector { ck.mu.RLock() defer ck.mu.RUnlock() diff --git a/vendor/github.com/moby/buildkit/solver/cachemanager.go b/vendor/github.com/moby/buildkit/solver/cachemanager.go index 5f5d9f33e230c..cd69ddb826620 100644 --- a/vendor/github.com/moby/buildkit/solver/cachemanager.go +++ b/vendor/github.com/moby/buildkit/solver/cachemanager.go @@ -10,6 +10,7 @@ import ( "github.com/moby/buildkit/identity" "github.com/moby/buildkit/util/bklog" digest "github.com/opencontainers/go-digest" + "github.com/sirupsen/logrus" ) // NewInMemoryCacheManager creates a new in-memory cache manager @@ -55,7 +56,28 @@ func (c *cacheManager) ID() string { return c.id } -func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst digest.Digest, output Index) ([]*CacheKey, error) { +func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst digest.Digest, output Index) (rcks []*CacheKey, rerr error) { + depsField := make([]map[string]any, len(deps)) + for i, dep := range deps { + depsField[i] = dep.TraceFields() + } + lg := bklog.G(context.TODO()).WithFields(logrus.Fields{ + "cache_manager": c.id, + "op": "query", + "deps": depsField, + "input": input, + "digest": dgst, + "output": output, + "stack": bklog.TraceLevelOnlyStack(), + }) + defer func() { + rcksField := make([]map[string]any, len(rcks)) + for i, rck := range rcks { + rcksField[i] = rck.TraceFields() + } + lg.WithError(rerr).WithField("return_cachekeys", rcksField).Trace("cache manager") + }() + c.mu.RLock() defer c.mu.RUnlock() @@ -112,7 +134,21 @@ func (c *cacheManager) Query(deps []CacheKeyWithSelector, input Index, dgst dige return keys, nil } -func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) ([]*CacheRecord, error) { +func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) (rrecs []*CacheRecord, rerr error) { + lg := bklog.G(context.TODO()).WithFields(logrus.Fields{ + "cache_manager": c.id, + "op": "records", + "cachekey": ck.TraceFields(), + "stack": bklog.TraceLevelOnlyStack(), + }) + defer func() { + rrercsField := make([]map[string]any, len(rrecs)) + for i, rrec := range rrecs { + rrercsField[i] = rrec.TraceFields() + } + lg.WithError(rerr).WithField("return_records", rrercsField).Trace("cache manager") + }() + outs := make([]*CacheRecord, 0) if err := c.backend.WalkResults(c.getID(ck), func(r CacheResult) error { if c.results.Exists(ctx, r.ID) { @@ -132,7 +168,21 @@ func (c *cacheManager) Records(ctx context.Context, ck *CacheKey) ([]*CacheRecor return outs, nil } -func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (Result, error) { +func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (rres Result, rerr error) { + lg := bklog.G(context.TODO()).WithFields(logrus.Fields{ + "cache_manager": c.id, + "op": "load", + "record": rec.TraceFields(), + "stack": bklog.TraceLevelOnlyStack(), + }) + defer func() { + rresID := "" + if rres != nil { + rresID = rres.ID() + } + lg.WithError(rerr).WithField("return_result", rresID).Trace("cache manager") + }() + c.mu.RLock() defer c.mu.RUnlock() @@ -150,6 +200,14 @@ type LoadedResult struct { CacheKey *CacheKey } +func (r *LoadedResult) TraceFields() map[string]any { + return map[string]any{ + "result": r.Result.ID(), + "cache_result": r.CacheResult.ID, + "cache_key": r.CacheKey.TraceFields(), + } +} + func (c *cacheManager) filterResults(m map[string]Result, ck *CacheKey, visited map[string]struct{}) (results []LoadedResult, err error) { id := c.getID(ck) if _, ok := visited[id]; ok { @@ -187,7 +245,21 @@ func (c *cacheManager) filterResults(m map[string]Result, ck *CacheKey, visited return } -func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) ([]LoadedResult, error) { +func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) (rres []LoadedResult, rerr error) { + lg := bklog.G(context.TODO()).WithFields(logrus.Fields{ + "cache_manager": c.id, + "op": "load_with_parents", + "record": rec.TraceFields(), + "stack": bklog.TraceLevelOnlyStack(), + }) + defer func() { + rresField := make([]map[string]any, len(rres)) + for i, rres := range rres { + rresField[i] = rres.TraceFields() + } + lg.WithError(rerr).WithField("return_results", rresField).Trace("cache manager") + }() + lwp, ok := c.results.(interface { LoadWithParents(context.Context, CacheResult) (map[string]Result, error) }) @@ -226,7 +298,17 @@ func (c *cacheManager) LoadWithParents(ctx context.Context, rec *CacheRecord) ([ return results, nil } -func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (*ExportableCacheKey, error) { +func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (rck *ExportableCacheKey, rerr error) { + lg := bklog.G(context.TODO()).WithFields(logrus.Fields{ + "cache_manager": c.id, + "op": "save", + "result": r.ID(), + "stack": bklog.TraceLevelOnlyStack(), + }) + defer func() { + lg.WithError(rerr).WithField("return_cachekey", rck.TraceFields()).Trace("cache manager") + }() + c.mu.Lock() defer c.mu.Unlock() @@ -357,7 +439,7 @@ func (c *cacheManager) getIDFromDeps(k *CacheKey) string { func rootKey(dgst digest.Digest, output Index) digest.Digest { if strings.HasPrefix(dgst.String(), "random:") { - return digest.Digest("random:" + strings.TrimPrefix(digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))).String(), digest.Canonical.String()+":")) + return digest.Digest("random:" + digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))).Encoded()) } return digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))) } diff --git a/vendor/github.com/moby/buildkit/solver/edge.go b/vendor/github.com/moby/buildkit/solver/edge.go index 3e4ec18242fdd..d0f19e2105ed5 100644 --- a/vendor/github.com/moby/buildkit/solver/edge.go +++ b/vendor/github.com/moby/buildkit/solver/edge.go @@ -2,6 +2,7 @@ package solver import ( "context" + "strings" "sync" "time" @@ -33,6 +34,28 @@ func newEdge(ed Edge, op activeOp, index *edgeIndex) *edge { cacheRecords: map[string]*CacheRecord{}, cacheRecordsLoaded: map[string]struct{}{}, index: index, + debug: debugScheduler, + } + if !e.debug && len(debugSchedulerSteps) > 0 { + withParents := strings.HasSuffix(debugSchedulerSteps[0], "^") + name := strings.TrimSuffix(debugSchedulerSteps[0], "^") + for _, v := range debugSchedulerSteps { + if strings.Contains(name, v) { + e.debug = true + break + } + } + if !e.debug && withParents { + for _, vtx := range ed.Vertex.Inputs() { + name := strings.TrimSuffix(vtx.Vertex.Name(), "^") + for _, v := range debugSchedulerSteps { + if strings.Contains(name, v) { + e.debug = true + break + } + } + } + } } return e } @@ -64,12 +87,14 @@ type edge struct { hasActiveOutgoing bool releaserCount int + owner *edge keysDidChange bool index *edgeIndex secondaryExporters []expDep failedOnce sync.Once + debug bool } // dep holds state for a dependant edge @@ -85,7 +110,7 @@ type dep struct { err error } -// expDep holds secorndary exporter info for dependency +// expDep holds secondary exporter info for dependency type expDep struct { index int cacheKey CacheKeyWithSelector @@ -116,10 +141,12 @@ type edgeRequest struct { currentKeys int } -// incrementReferenceCount increases the number of times release needs to be +// takeOwnership increases the number of times release needs to be // called to release the edge. Called on merging edges. -func (e *edge) incrementReferenceCount() { - e.releaserCount++ +func (e *edge) takeOwnership(old *edge) { + e.releaserCount += old.releaserCount + 1 + old.owner = e + old.releaseResult() } // release releases the edge resources @@ -128,6 +155,10 @@ func (e *edge) release() { e.releaserCount-- return } + e.releaseResult() +} + +func (e *edge) releaseResult() { e.index.Release(e) if e.result != nil { go e.result.Release(context.TODO()) @@ -172,7 +203,7 @@ func (e *edge) finishIncoming(req pipe.Sender) { if req.Request().Canceled && err == nil { err = context.Canceled } - if debugScheduler { + if e.debug { bklog.G(context.TODO()).Debugf("finishIncoming %s %v %#v desired=%s", e.edge.Vertex.Name(), err, e.edgeState, req.Request().Payload.(*edgeRequest).desiredState) } req.Finalize(&e.edgeState, err) @@ -180,7 +211,7 @@ func (e *edge) finishIncoming(req pipe.Sender) { // updateIncoming updates the current value of incoming pipe request func (e *edge) updateIncoming(req pipe.Sender) { - if debugScheduler { + if e.debug { bklog.G(context.TODO()).Debugf("updateIncoming %s %#v desired=%s", e.edge.Vertex.Name(), e.edgeState, req.Request().Payload.(*edgeRequest).desiredState) } req.Update(&e.edgeState) @@ -361,7 +392,7 @@ func (e *edge) unpark(incoming []pipe.Sender, updates, allPipes []pipe.Receiver, if e.execReq == nil { if added := e.createInputRequests(desiredState, f, false); !added && !e.hasActiveOutgoing && !cacheMapReq { - bklog.G(context.TODO()).Errorf("buildkit scheluding error: leaving incoming open. forcing solve. Please report this with BUILDKIT_SCHEDULER_DEBUG=1") + bklog.G(context.TODO()).Errorf("buildkit scheduling error: leaving incoming open. forcing solve. Please report this with BUILDKIT_SCHEDULER_DEBUG=1") debugSchedulerPreUnpark(e, incoming, updates, allPipes) e.createInputRequests(desiredState, f, true) } @@ -676,7 +707,7 @@ func (e *edge) recalcCurrentState() { } if len(openKeys) == 0 { e.state = edgeStatusCacheSlow - if debugScheduler { + if e.debug { bklog.G(context.TODO()).Debugf("upgrade to cache-slow because no open keys") } } @@ -715,7 +746,7 @@ func (e *edge) respondToIncoming(incoming []pipe.Sender, allPipes []pipe.Receive allIncomingCanComplete = false } - if debugScheduler { + if e.debug { bklog.G(context.TODO()).Debugf("status state=%s cancomplete=%v hasouts=%v noPossibleCache=%v depsCacheFast=%v keys=%d cacheRecords=%d", e.state, allIncomingCanComplete, e.hasActiveOutgoing, e.noCacheMatchPossible, e.allDepsCompletedCacheFast, len(e.keys), len(e.cacheRecords)) } diff --git a/vendor/github.com/moby/buildkit/solver/errdefs/context.go b/vendor/github.com/moby/buildkit/solver/errdefs/context.go index 9e0c5bb990c67..5e0cbce1adb41 100644 --- a/vendor/github.com/moby/buildkit/solver/errdefs/context.go +++ b/vendor/github.com/moby/buildkit/solver/errdefs/context.go @@ -14,7 +14,7 @@ func IsCanceled(ctx context.Context, err error) bool { return true } // grpc does not set cancel correctly when stream gets cancelled and then Recv is called - if err != nil && ctx.Err() == context.Canceled { + if err != nil && errors.Is(context.Cause(ctx), context.Canceled) { // when this error comes from containerd it is not typed at all, just concatenated string if strings.Contains(err.Error(), "EOF") { return true diff --git a/vendor/github.com/moby/buildkit/solver/errdefs/jobs.go b/vendor/github.com/moby/buildkit/solver/errdefs/jobs.go new file mode 100644 index 0000000000000..884792d531437 --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/errdefs/jobs.go @@ -0,0 +1,23 @@ +package errdefs + +import ( + "fmt" + + "google.golang.org/grpc/codes" +) + +type UnknownJobError struct { + id string +} + +func (e *UnknownJobError) Code() codes.Code { + return codes.NotFound +} + +func (e *UnknownJobError) Error() string { + return fmt.Sprintf("no such job %s", e.id) +} + +func NewUnknownJobError(id string) error { + return &UnknownJobError{id: id} +} diff --git a/vendor/github.com/moby/buildkit/solver/internal/pipe/pipe.go b/vendor/github.com/moby/buildkit/solver/internal/pipe/pipe.go index a1a857f39827c..01cfa5a06b6dc 100644 --- a/vendor/github.com/moby/buildkit/solver/internal/pipe/pipe.go +++ b/vendor/github.com/moby/buildkit/solver/internal/pipe/pipe.go @@ -70,11 +70,11 @@ type Status struct { func NewWithFunction(f func(context.Context) (interface{}, error)) (*Pipe, func()) { p := New(Request{}) - ctx, cancel := context.WithCancel(context.TODO()) + ctx, cancel := context.WithCancelCause(context.TODO()) p.OnReceiveCompletion = func() { if req := p.Sender.Request(); req.Canceled { - cancel() + cancel(errors.WithStack(context.Canceled)) } } diff --git a/vendor/github.com/moby/buildkit/solver/jobs.go b/vendor/github.com/moby/buildkit/solver/jobs.go index ec203257e3cd9..9e2940100d399 100644 --- a/vendor/github.com/moby/buildkit/solver/jobs.go +++ b/vendor/github.com/moby/buildkit/solver/jobs.go @@ -18,6 +18,7 @@ import ( "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) // ResolveOpFunc finds an Op implementation for a Vertex @@ -141,6 +142,9 @@ func (s *state) getEdge(index Index) *edge { s.mu.Lock() defer s.mu.Unlock() if e, ok := s.edges[index]; ok { + for e.owner != nil { + e = e.owner + } return e } @@ -153,19 +157,29 @@ func (s *state) getEdge(index Index) *edge { return e } -func (s *state) setEdge(index Index, newEdge *edge) { +func (s *state) setEdge(index Index, targetEdge *edge, targetState *state) { s.mu.Lock() defer s.mu.Unlock() e, ok := s.edges[index] if ok { - if e == newEdge { + for e.owner != nil { + e = e.owner + } + if e == targetEdge { return } - e.release() + } else { + e = newEdge(Edge{Index: index, Vertex: s.vtx}, s.op, s.index) + s.edges[index] = e } + targetEdge.takeOwnership(e) - newEdge.incrementReferenceCount() - s.edges[index] = newEdge + if targetState != nil { + if _, ok := targetState.allPw[s.mpw]; !ok { + targetState.mpw.Add(s.mpw) + targetState.allPw[s.mpw] = struct{}{} + } + } } func (s *state) combinedCacheManager() CacheManager { @@ -186,6 +200,9 @@ func (s *state) combinedCacheManager() CacheManager { func (s *state) Release() { for _, e := range s.edges { + for e.owner != nil { + e = e.owner + } e.release() } if s.op != nil { @@ -239,7 +256,7 @@ type Job struct { startedTime time.Time completedTime time.Time - progressCloser func() + progressCloser func(error) SessionID string uniqueID string // unique ID is used for provenance. We use a different field that client can't control } @@ -264,7 +281,50 @@ func NewSolver(opts SolverOpt) *Solver { return jl } -func (jl *Solver) setEdge(e Edge, newEdge *edge) { +// hasOwner returns true if the provided target edge (or any of it's sibling +// edges) has the provided owner. +func (jl *Solver) hasOwner(target Edge, owner Edge) bool { + jl.mu.RLock() + defer jl.mu.RUnlock() + + st, ok := jl.actives[target.Vertex.Digest()] + if !ok { + return false + } + + var owners []Edge + for _, e := range st.edges { + if e.owner != nil { + owners = append(owners, e.owner.edge) + } + } + for len(owners) > 0 { + var owners2 []Edge + for _, e := range owners { + st, ok = jl.actives[e.Vertex.Digest()] + if !ok { + continue + } + + if st.vtx.Digest() == owner.Vertex.Digest() { + return true + } + + for _, e := range st.edges { + if e.owner != nil { + owners2 = append(owners2, e.owner.edge) + } + } + } + + // repeat recursively, this time with the linked owners owners + owners = owners2 + } + + return false +} + +func (jl *Solver) setEdge(e Edge, targetEdge *edge) { jl.mu.RLock() defer jl.mu.RUnlock() @@ -273,7 +333,10 @@ func (jl *Solver) setEdge(e Edge, newEdge *edge) { return } - st.setEdge(e.Index, newEdge) + // potentially passing nil targetSt is intentional and handled in st.setEdge + targetSt := jl.actives[targetEdge.edge.Vertex.Digest()] + + st.setEdge(e.Index, targetEdge, targetSt) } func (jl *Solver) getState(e Edge) *state { @@ -450,7 +513,7 @@ func (jl *Solver) NewJob(id string) (*Job, error) { pr, ctx, progressCloser := progress.NewContext(context.Background()) pw, _, _ := progress.NewFromContext(ctx) // TODO: expose progress.Pipe() - _, span := trace.NewNoopTracerProvider().Tracer("").Start(ctx, "") + _, span := noop.NewTracerProvider().Tracer("").Start(ctx, "") j := &Job{ list: jl, pr: progress.NewMultiReader(pr), @@ -469,8 +532,9 @@ func (jl *Solver) NewJob(id string) (*Job, error) { } func (jl *Solver) Get(id string) (*Job, error) { - ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second) - defer cancel() + ctx, cancel := context.WithCancelCause(context.Background()) + ctx, _ = context.WithTimeoutCause(ctx, 6*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) go func() { <-ctx.Done() @@ -484,7 +548,7 @@ func (jl *Solver) Get(id string) (*Job, error) { for { select { case <-ctx.Done(): - return nil, errors.Errorf("no such job %s", id) + return nil, errdefs.NewUnknownJobError(id) default: } j, ok := jl.jobs[id] @@ -570,7 +634,7 @@ func (j *Job) walkProvenance(ctx context.Context, e Edge, f func(ProvenanceProvi } func (j *Job) CloseProgress() { - j.progressCloser() + j.progressCloser(errors.WithStack(context.Canceled)) j.pw.Close() } @@ -771,7 +835,7 @@ func (s *sharedOp) CalcSlowCache(ctx context.Context, index Index, p PreprocessF if errdefs.IsCanceled(ctx, err) { complete = false releaseError(err) - err = errors.Wrap(ctx.Err(), err.Error()) + err = errors.Wrap(context.Cause(ctx), err.Error()) } default: } @@ -837,7 +901,7 @@ func (s *sharedOp) CacheMap(ctx context.Context, index int) (resp *cacheMapResp, if errdefs.IsCanceled(ctx, err) { complete = false releaseError(err) - err = errors.Wrap(ctx.Err(), err.Error()) + err = errors.Wrap(context.Cause(ctx), err.Error()) } default: } @@ -916,7 +980,7 @@ func (s *sharedOp) Exec(ctx context.Context, inputs []Result) (outputs []Result, if errdefs.IsCanceled(ctx, err) { complete = false releaseError(err) - err = errors.Wrap(ctx.Err(), err.Error()) + err = errors.Wrap(context.Cause(ctx), err.Error()) } default: } diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go b/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go index 5fd66c9fb68e8..5f1c83bb122c8 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go @@ -10,7 +10,7 @@ import ( "github.com/mitchellh/hashstructure/v2" "github.com/moby/buildkit/cache/remotecache" "github.com/moby/buildkit/client" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" resourcestypes "github.com/moby/buildkit/executor/resources/types" "github.com/moby/buildkit/frontend" @@ -351,32 +351,44 @@ func (rp *resultProxy) Result(ctx context.Context) (res solver.CachedResult, err }) } -func (b *llbBridge) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (resolvedRef string, dgst digest.Digest, config []byte, err error) { +func (b *llbBridge) ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt) (resp *sourceresolver.MetaResponse, err error) { w, err := b.resolveWorker() if err != nil { - return "", "", nil, err + return nil, err } if opt.LogName == "" { - opt.LogName = fmt.Sprintf("resolve image config for %s", ref) + // TODO: better name + opt.LogName = fmt.Sprintf("resolve image config for %s", op.Identifier) } - id := ref // make a deterministic ID for avoiding duplicates - if platform := opt.Platform; platform == nil { - id += platforms.Format(platforms.DefaultSpec()) + id := op.Identifier + if opt.Platform != nil { + id += platforms.Format(*opt.Platform) } else { - id += platforms.Format(*platform) + id += platforms.Format(platforms.DefaultSpec()) } pol, err := loadSourcePolicy(b.builder) if err != nil { - return "", "", nil, err + return nil, err } if pol != nil { opt.SourcePolicies = append(opt.SourcePolicies, pol) } + + if _, err := sourcepolicy.NewEngine(opt.SourcePolicies).Evaluate(ctx, op); err != nil { + return nil, errors.Wrap(err, "could not resolve image due to policy") + } + + // policy is evaluated, so we can remove it from the options + opt.SourcePolicies = nil + err = inBuilderContext(ctx, b.builder, opt.LogName, id, func(ctx context.Context, g session.Group) error { - resolvedRef, dgst, config, err = w.ResolveImageConfig(ctx, ref, opt, b.sm, g) + resp, err = w.ResolveSourceMetadata(ctx, op, opt, b.sm, g) return err }) - return resolvedRef, dgst, config, err + if err != nil { + return nil, err + } + return resp, nil } type lazyCacheManager struct { diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend.go b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend.go index 6212066cd9f27..311fc5043d356 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend.go @@ -27,46 +27,6 @@ func timestampToTime(ts int64) *time.Time { return &tm } -func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Chowner, error) { - if user == nil { - return func(old *copy.User) (*copy.User, error) { - if old == nil { - if idmap == nil { - return nil, nil - } - old = ©.User{} // root - // non-nil old is already mapped - if idmap != nil { - identity, err := idmap.ToHost(idtools.Identity{ - UID: old.UID, - GID: old.GID, - }) - if err != nil { - return nil, err - } - return ©.User{UID: identity.UID, GID: identity.GID}, nil - } - } - return old, nil - }, nil - } - u := *user - if idmap != nil { - identity, err := idmap.ToHost(idtools.Identity{ - UID: user.UID, - GID: user.GID, - }) - if err != nil { - return nil, err - } - u.UID = identity.UID - u.GID = identity.GID - } - return func(*copy.User) (*copy.User, error) { - return &u, nil - }, nil -} - func mkdir(ctx context.Context, d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) error { p, err := fs.RootPath(d, action.Path) if err != nil { @@ -161,14 +121,15 @@ func rmPath(root, src string, allowNotFound bool) error { } p := filepath.Join(dir, base) - if err := os.RemoveAll(p); err != nil { - if errors.Is(err, os.ErrNotExist) && allowNotFound { - return nil + if !allowNotFound { + _, err := os.Stat(p) + + if errors.Is(err, os.ErrNotExist) { + return err } - return err } - return nil + return os.RemoveAll(p) } func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) error { @@ -215,27 +176,22 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * copy.WithXAttrErrorHandler(xattrErrorHandler), } + var m []string if !action.AllowWildcard { - if action.AttemptUnpackDockerCompatibility { - if ok, err := unpack(ctx, src, srcPath, dest, destPath, ch, timestampToTime(action.Timestamp)); err != nil { - return err - } else if ok { - return nil - } + m = []string{srcPath} + } else { + var err error + m, err = copy.ResolveWildcards(src, srcPath, action.FollowSymlink) + if err != nil { + return err } - return copy.Copy(ctx, src, srcPath, dest, destPath, opt...) - } - m, err := copy.ResolveWildcards(src, srcPath, action.FollowSymlink) - if err != nil { - return err - } - - if len(m) == 0 { - if action.AllowEmptyWildcard { - return nil + if len(m) == 0 { + if action.AllowEmptyWildcard { + return nil + } + return errors.Errorf("%s not found", srcPath) } - return errors.Errorf("%s not found", srcPath) } for _, s := range m { @@ -254,7 +210,21 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * return nil } +// NewFileOpBackend returns a new file operation backend. The executor is currently only used for Windows, +// and it is used to construct the readUserFn field set in the returned Backend. +func NewFileOpBackend(readUser ReadUserCallback) (*Backend, error) { + if readUser == nil { + return nil, errors.New("readUser callback must be provided") + } + return &Backend{ + readUser: readUser, + }, nil +} + +type ReadUserCallback func(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) + type Backend struct { + readUser ReadUserCallback } func (fb *Backend) Mkdir(ctx context.Context, m, user, group fileoptypes.Mount, action pb.FileActionMkDir) error { @@ -270,7 +240,7 @@ func (fb *Backend) Mkdir(ctx context.Context, m, user, group fileoptypes.Mount, } defer lm.Unmount() - u, err := readUser(action.Owner, user, group) + u, err := fb.readUserWrapper(action.Owner, user, group) if err != nil { return err } @@ -291,7 +261,7 @@ func (fb *Backend) Mkfile(ctx context.Context, m, user, group fileoptypes.Mount, } defer lm.Unmount() - u, err := readUser(action.Owner, user, group) + u, err := fb.readUserWrapper(action.Owner, user, group) if err != nil { return err } @@ -339,7 +309,7 @@ func (fb *Backend) Copy(ctx context.Context, m1, m2, user, group fileoptypes.Mou } defer lm2.Unmount() - u, err := readUser(action.Owner, user, group) + u, err := fb.readUserWrapper(action.Owner, user, group) if err != nil { return err } @@ -347,6 +317,33 @@ func (fb *Backend) Copy(ctx context.Context, m1, m2, user, group fileoptypes.Mou return docopy(ctx, src, dest, action, u, mnt2.m.IdentityMapping()) } +func (fb *Backend) readUserWrapper(owner *pb.ChownOpt, user, group fileoptypes.Mount) (*copy.User, error) { + var userMountable, groupMountable snapshot.Mountable + if user != nil { + usr, ok := user.(*Mount) + if !ok { + return nil, errors.Errorf("invalid mount type %T", user) + } + userMountable = usr.Mountable() + } + + if group != nil { + grp, ok := group.(*Mount) + if !ok { + return nil, errors.Errorf("invalid mount type %T", group) + } + groupMountable = grp.Mountable() + } + + // We don't check the mountables for nil here. Depending on the ChownOpt value, + // one of them may be nil. Allow the readUser function to handle this. + u, err := fb.readUser(owner, userMountable, groupMountable) + if err != nil { + return nil, err + } + return u, nil +} + func cleanPath(s string) (string, error) { s, err := system.CheckSystemDriveAndRemoveDriveLetter(s, runtime.GOOS) if err != nil { diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_unix.go b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_unix.go new file mode 100644 index 0000000000000..d01290f300ace --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_unix.go @@ -0,0 +1,49 @@ +//go:build !windows +// +build !windows + +package file + +import ( + "github.com/docker/docker/pkg/idtools" + copy "github.com/tonistiigi/fsutil/copy" +) + +func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Chowner, error) { + if user == nil { + return func(old *copy.User) (*copy.User, error) { + if old == nil { + if idmap == nil { + return nil, nil + } + old = ©.User{} // root + // non-nil old is already mapped + if idmap != nil { + identity, err := idmap.ToHost(idtools.Identity{ + UID: old.UID, + GID: old.GID, + }) + if err != nil { + return nil, err + } + return ©.User{UID: identity.UID, GID: identity.GID}, nil + } + } + return old, nil + }, nil + } + u := *user + if idmap != nil { + identity, err := idmap.ToHost(idtools.Identity{ + UID: user.UID, + GID: user.GID, + }) + if err != nil { + return nil, err + } + u.UID = identity.UID + u.GID = identity.GID + } + return func(*copy.User) (*copy.User, error) { + return &u, nil + }, nil +} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_windows.go b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_windows.go new file mode 100644 index 0000000000000..03f3bbe7b3089 --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/file/backend_windows.go @@ -0,0 +1,22 @@ +package file + +import ( + "github.com/docker/docker/pkg/idtools" + copy "github.com/tonistiigi/fsutil/copy" +) + +func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Chowner, error) { + if user == nil || user.SID == "" { + return func(old *copy.User) (*copy.User, error) { + if old == nil || old.SID == "" { + old = ©.User{ + SID: idtools.ContainerAdministratorSidString, + } + } + return old, nil + }, nil + } + return func(*copy.User) (*copy.User, error) { + return user, nil + }, nil +} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/refmanager.go b/vendor/github.com/moby/buildkit/solver/llbsolver/file/refmanager.go index b9f3b2ea3ca37..cb26ba2886659 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/file/refmanager.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/file/refmanager.go @@ -79,6 +79,10 @@ type Mount struct { readonly bool } +func (m *Mount) Mountable() snapshot.Mountable { + return m.m +} + func (m *Mount) Release(ctx context.Context) error { if m.mr != nil { return m.mr.Release(ctx) diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/user_nolinux.go b/vendor/github.com/moby/buildkit/solver/llbsolver/file/user_nolinux.go deleted file mode 100644 index 80652fd4abe4b..0000000000000 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/file/user_nolinux.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !linux -// +build !linux - -package file - -import ( - "github.com/moby/buildkit/solver/llbsolver/ops/fileoptypes" - "github.com/moby/buildkit/solver/pb" - "github.com/pkg/errors" - copy "github.com/tonistiigi/fsutil/copy" -) - -func readUser(chopt *pb.ChownOpt, mu, mg fileoptypes.Mount) (*copy.User, error) { - if chopt == nil { - return nil, nil - } - return nil, errors.New("only implemented in linux") -} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/history.go b/vendor/github.com/moby/buildkit/solver/llbsolver/history.go index d055a7bf54f08..fc4a8ecdb4dfa 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/history.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/history.go @@ -326,7 +326,7 @@ func (h *HistoryQueue) delete(ref string, sync bool) error { if err := h.opt.DB.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(recordsBucket)) if b == nil { - return os.ErrNotExist + return errors.Wrapf(os.ErrNotExist, "failed to retrieve bucket %s", recordsBucket) } err1 := b.Delete([]byte(ref)) var opts []leases.DeleteOpt @@ -393,11 +393,11 @@ func (h *HistoryQueue) UpdateRef(ctx context.Context, ref string, upt func(r *co if err := h.opt.DB.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(recordsBucket)) if b == nil { - return os.ErrNotExist + return errors.Wrapf(os.ErrNotExist, "failed to retrieve bucket %s", recordsBucket) } dt := b.Get([]byte(ref)) if dt == nil { - return os.ErrNotExist + return errors.Wrapf(os.ErrNotExist, "failed to retrieve ref %s", ref) } if err := br.Unmarshal(dt); err != nil { @@ -433,11 +433,11 @@ func (h *HistoryQueue) Status(ctx context.Context, ref string, st chan<- *client if err := h.opt.DB.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(recordsBucket)) if b == nil { - return os.ErrNotExist + return errors.Wrapf(os.ErrNotExist, "failed to retrieve bucket %s", recordsBucket) } dt := b.Get([]byte(ref)) if dt == nil { - return os.ErrNotExist + return errors.Wrapf(os.ErrNotExist, "failed to retrieve ref %s", ref) } if err := br.Unmarshal(dt); err != nil { @@ -526,9 +526,14 @@ func (h *HistoryQueue) update(ctx context.Context, rec controlapi.BuildHistoryRe return err } if rec.Result != nil { - if err := h.addResource(ctx, l, rec.Result.Result, true); err != nil { + if err := h.addResource(ctx, l, rec.Result.ResultDeprecated, true); err != nil { return err } + for _, res := range rec.Result.Results { + if err := h.addResource(ctx, l, res, true); err != nil { + return err + } + } for _, att := range rec.Result.Attestations { if err := h.addResource(ctx, l, att, false); err != nil { return err @@ -536,9 +541,14 @@ func (h *HistoryQueue) update(ctx context.Context, rec controlapi.BuildHistoryRe } } for _, r := range rec.Results { - if err := h.addResource(ctx, l, r.Result, true); err != nil { + if err := h.addResource(ctx, l, r.ResultDeprecated, true); err != nil { return err } + for _, res := range r.Results { + if err := h.addResource(ctx, l, res, true); err != nil { + return err + } + } for _, att := range r.Attestations { if err := h.addResource(ctx, l, att, false); err != nil { return err @@ -835,7 +845,7 @@ func (h *HistoryQueue) Listen(ctx context.Context, req *controlapi.BuildHistoryR for { select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) case e := <-sub.ch: if req.Ref != "" && req.Ref != e.Record.Ref { continue diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/mounts/mount.go b/vendor/github.com/moby/buildkit/solver/llbsolver/mounts/mount.go index b61e7e3d1c0c5..90acbd44bc125 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/mounts/mount.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/mounts/mount.go @@ -136,7 +136,7 @@ func (g *cacheRefGetter) getRefCacheDirNoCache(ctx context.Context, key string, select { case <-ctx.Done(): cacheRefsLocker.Lock(key) - return nil, ctx.Err() + return nil, context.Cause(ctx) case <-time.After(100 * time.Millisecond): cacheRefsLocker.Lock(key) } @@ -199,7 +199,7 @@ type sshMountInstance struct { } func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) { - ctx, cancel := context.WithCancel(context.TODO()) + ctx, cancel := context.WithCancelCause(context.TODO()) uid := int(sm.sm.mount.SSHOpt.Uid) gid := int(sm.sm.mount.SSHOpt.Gid) @@ -210,7 +210,7 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) { GID: gid, }) if err != nil { - cancel() + cancel(err) return nil, nil, err } uid = identity.UID @@ -224,7 +224,7 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) { Mode: int(sm.sm.mount.SSHOpt.Mode & 0777), }) if err != nil { - cancel() + cancel(err) return nil, nil, err } release := func() error { @@ -232,7 +232,7 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) { if cleanup != nil { err = cleanup() } - cancel() + cancel(err) return err } @@ -305,10 +305,15 @@ func (sm *secretMountInstance) Mount() ([]mount.Mount, func() error, error) { return nil, nil, err } + var mountOpts []string + if sm.sm.mount.SecretOpt.Mode&0o111 == 0 { + mountOpts = append(mountOpts, "noexec") + } + tmpMount := mount.Mount{ Type: "tmpfs", Source: "tmpfs", - Options: []string{"nodev", "nosuid", "noexec", fmt.Sprintf("uid=%d,gid=%d", os.Geteuid(), os.Getegid())}, + Options: append([]string{"nodev", "nosuid", fmt.Sprintf("uid=%d,gid=%d", os.Geteuid(), os.Getegid())}, mountOpts...), } if userns.RunningInUserNS() { @@ -364,7 +369,7 @@ func (sm *secretMountInstance) Mount() ([]mount.Mount, func() error, error) { return []mount.Mount{{ Type: "bind", Source: fp, - Options: []string{"ro", "rbind", "nodev", "nosuid", "noexec"}, + Options: append([]string{"ro", "rbind", "nodev", "nosuid"}, mountOpts...), }}, cleanup, nil } @@ -483,7 +488,7 @@ type cacheRefShare struct { func (r *cacheRefShare) clone(ctx context.Context) cache.MutableRef { bklog.G(ctx).WithFields(map[string]any{ "key": r.key, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), }).Trace("cloning cache mount ref share") cacheRef := &cacheRef{cacheRefShare: r} if cacheRefCloneHijack != nil { @@ -498,7 +503,7 @@ func (r *cacheRefShare) clone(ctx context.Context) cache.MutableRef { func (r *cacheRefShare) release(ctx context.Context) error { bklog.G(ctx).WithFields(map[string]any{ "key": r.key, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), }).Trace("releasing cache mount ref share main") if r.main != nil { delete(r.main.shares, r.key) @@ -516,7 +521,7 @@ type cacheRef struct { func (r *cacheRef) Release(ctx context.Context) error { bklog.G(ctx).WithFields(map[string]any{ "key": r.key, - "stack": bklog.LazyStackTrace{}, + "stack": bklog.TraceLevelOnlyStack(), }).Trace("releasing cache mount ref share") if r.main != nil { r.main.mu.Lock() diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/diff.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/diff.go index 338a8748e8c6f..dbaf7ca08e32f 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/diff.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/diff.go @@ -55,7 +55,7 @@ func (d *diffOp) CacheMap(ctx context.Context, group session.Group, index int) ( } cm := &solver.CacheMap{ - Digest: digest.Digest(dt), + Digest: digest.FromBytes(dt), Deps: make([]struct { Selector digest.Digest ComputeDigestFunc solver.ResultBasedCacheFunc diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go index eee0dd39fb6e0..f24f065c27703 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go @@ -90,20 +90,55 @@ func cloneExecOp(old *pb.ExecOp) pb.ExecOp { n.Mounts = nil for i := range old.Mounts { m := *old.Mounts[i] + + if m.CacheOpt != nil { + co := *m.CacheOpt + m.CacheOpt = &co + } + n.Mounts = append(n.Mounts, &m) } return n } +func checkShouldClearCacheOpts(m *pb.Mount) bool { + if m.CacheOpt == nil { + return false + } + + // This is a dockerfile default cache mount. + // We are treating this as a special case so we don't cause a cache miss unintentionally. + if m.CacheOpt.ID == m.Dest && m.CacheOpt.Sharing == 0 { + return false + } + + // Check the case where a dockerfile cache-namespace may be used. + // This would be `/` + _, trimmed, ok := strings.Cut(m.CacheOpt.ID, "/") + if ok && trimmed == m.Dest && m.CacheOpt.Sharing == 0 { + return false + } + + return true +} + func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*solver.CacheMap, bool, error) { op := cloneExecOp(e.op) + for i := range op.Meta.ExtraHosts { h := op.Meta.ExtraHosts[i] h.IP = "" op.Meta.ExtraHosts[i] = h } + for i := range op.Mounts { - op.Mounts[i].Selector = "" + m := op.Mounts[i] + m.Selector = "" + + if checkShouldClearCacheOpts(m) { + m.CacheOpt.ID = "" + m.CacheOpt.Sharing = 0 + } } op.Meta.ProxyEnv = nil @@ -113,6 +148,8 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol OS: e.platform.OS, Architecture: e.platform.Architecture, Variant: e.platform.Variant, + OSVersion: e.platform.OSVersion, + OSFeatures: e.platform.OSFeatures, } } @@ -133,17 +170,21 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol } dt, err := json.Marshal(struct { - Type string - Exec *pb.ExecOp - OS string - Arch string - Variant string `json:",omitempty"` + Type string + Exec *pb.ExecOp + OS string + Arch string + Variant string `json:",omitempty"` + OSVersion string `json:",omitempty"` + OSFeatures []string `json:",omitempty"` }{ - Type: execCacheType, - Exec: &op, - OS: p.OS, - Arch: p.Architecture, - Variant: p.Variant, + Type: execCacheType, + Exec: &op, + OS: p.OS, + Arch: p.Architecture, + Variant: p.Variant, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, }) if err != nil { return nil, false, err @@ -171,7 +212,7 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol } cm.Deps[i].Selector = digest.FromBytes(bytes.Join(dgsts, []byte{0})) } - if !dep.NoContentBasedHash { + if dep.ContentBasedHash { cm.Deps[i].ComputeDigestFunc = opsutils.NewContentHashFunc(toSelectors(dedupePaths(dep.Selectors))) } cm.Deps[i].PreprocessFunc = unlazyResultFunc @@ -181,6 +222,12 @@ func (e *ExecOp) CacheMap(ctx context.Context, g session.Group, index int) (*sol } func dedupePaths(inp []string) []string { + // If there's one or fewer inputs, then dedupe won't do anything. + // Skip the allocations and logic of this function in that case. + if len(inp) <= 1 { + return inp + } + old := make(map[string]struct{}, len(inp)) for _, p := range inp { old[p] = struct{}{} @@ -189,7 +236,10 @@ func dedupePaths(inp []string) []string { for p1 := range old { var skip bool for p2 := range old { - if p1 != p2 && strings.HasPrefix(p1, p2+"/") { + // Check if p2 is a prefix of p1. Ensure that p2 ends in a slash + // so that we know p2 is a parent directory of p1. We don't want + // /foo to be a parent of /foobar. + if p1 != p2 && strings.HasPrefix(p1, forceTrailingSlash(p2)) { skip = true break } @@ -204,17 +254,32 @@ func dedupePaths(inp []string) []string { return paths } +// forceTrailingSlash ensures that the path always ends with a path separator. +// If the path already ends with a /, this method returns the same string. +func forceTrailingSlash(s string) string { + if strings.HasSuffix(s, "/") { + return s + } + return s + "/" +} + func toSelectors(p []string) []opsutils.Selector { sel := make([]opsutils.Selector, 0, len(p)) for _, p := range p { + if p == "" || p == "/" { + return nil + } sel = append(sel, opsutils.Selector{Path: p, FollowLinks: true}) } return sel } type dep struct { - Selectors []string - NoContentBasedHash bool + Selectors []string + + // ContentBasedHash enables content-based caching. This is used to ensure + // that all caching is done safely and efficiently. + ContentBasedHash bool } func (e *ExecOp) getMountDeps() ([]dep, error) { @@ -227,15 +292,56 @@ func (e *ExecOp) getMountDeps() ([]dep, error) { return nil, errors.Errorf("invalid mountinput %v", m) } - sel := m.Selector - if sel != "" { - sel = path.Join("/", sel) - deps[m.Input].Selectors = append(deps[m.Input].Selectors, sel) + sel := path.Join("/", m.Selector) + deps[m.Input].Selectors = append(deps[m.Input].Selectors, sel) + + // Assume that we *cannot* perform content-based caching, and then + // enable it selectively only for cases where we want to + contentBasedCache := false + + // Allow content-based cached where safe - these are enforced to avoid + // the following case: + // - A "snapshot" contains "foo/a.txt" and "bar/b.txt" + // - "RUN --mount from=snapshot,src=bar touch bar/c.txt" creates a new + // file in bar + // - If we run again, but this time "snapshot" contains a new + // "foo/sneaky.txt", the content-based cache matches the previous + // run, since we only select "bar" + // - But this cached result is incorrect - "foo/sneaky.txt" isn't in + // our cached result, but it is in our input. + if m.Output == pb.SkipOutput { + // if the mount has no outputs, it's safe to enable content-based + // caching, since it's guaranteed to not be used as an input for + // any future steps + contentBasedCache = true + } else if m.Readonly { + // if the mount is read-only, then it's also safe, since it can't + // be modified by the operation + contentBasedCache = true + } else if sel == pb.RootMount { + // if the mount mounts the entire source, then it's also safe, + // since there are no unselected "sneaky" files + contentBasedCache = true } - if (!m.Readonly || m.Dest == pb.RootMount) && m.Output != -1 { // exclude read-only rootfs && read-write mounts - deps[m.Input].NoContentBasedHash = true + // Now apply the user-specified option. + switch m.ContentCache { + case pb.MountContentCache_OFF: + contentBasedCache = false + case pb.MountContentCache_ON: + if !contentBasedCache { + // If we can't enable cache for safety, then force-enabling it is invalid + return nil, errors.Errorf("invalid mount cache content %v", m) + } + case pb.MountContentCache_DEFAULT: + if m.Dest == pb.RootMount { + // we explicitly choose to not implement it on the root mount, + // since this is likely very expensive (and not incredibly useful) + contentBasedCache = false + } } + + deps[m.Input].ContentBasedHash = contentBasedCache } return deps, nil } diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec_binfmt.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec_binfmt.go index c2c5504cc36bc..41a8047dce93d 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec_binfmt.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec_binfmt.go @@ -90,6 +90,8 @@ func getEmulator(ctx context.Context, p *pb.Platform, idmap *idtools.IdentityMap pp := platforms.Normalize(ocispecs.Platform{ Architecture: p.Architecture, OS: p.OS, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, Variant: p.Variant, }) diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/file.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/file.go index db81201f1ac5e..f17869381a90f 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/file.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/file.go @@ -167,7 +167,12 @@ func (f *fileOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu inpRefs = append(inpRefs, workerRef.ImmutableRef) } - fs := NewFileOpSolver(f.w, &file.Backend{}, f.refManager) + backend, err := file.NewFileOpBackend(getReadUserFn(f.w)) + if err != nil { + return nil, err + } + + fs := NewFileOpSolver(f.w, backend, f.refManager) outs, err := fs.Solve(ctx, inpRefs, f.op.Actions, g) if err != nil { return nil, err diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/merge.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/merge.go index db1b025bff40f..23a36db66a976 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/merge.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/merge.go @@ -47,7 +47,7 @@ func (m *mergeOp) CacheMap(ctx context.Context, group session.Group, index int) } cm := &solver.CacheMap{ - Digest: digest.Digest(dt), + Digest: digest.FromBytes(dt), Deps: make([]struct { Selector digest.Digest ComputeDigestFunc solver.ResultBasedCacheFunc diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go index fabd300d4b5c8..d6d1712a442b8 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go @@ -60,7 +60,7 @@ func (s *SourceOp) instance(ctx context.Context) (source.SourceInstance, error) if s.src != nil { return s.src, nil } - id, err := source.FromLLB(s.op, s.platform) + id, err := s.sm.Identifier(s.op, s.platform) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (s *SourceOp) CacheMap(ctx context.Context, g session.Group, index int) (*s dgst := digest.FromBytes([]byte(sourceCacheType + ":" + k)) if strings.HasPrefix(k, "session:") { - dgst = digest.Digest("random:" + strings.TrimPrefix(dgst.String(), dgst.Algorithm().String()+":")) + dgst = digest.Digest("random:" + dgst.Encoded()) } return &solver.CacheMap{ diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/file/user_linux.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_linux.go similarity index 82% rename from vendor/github.com/moby/buildkit/solver/llbsolver/file/user_linux.go rename to vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_linux.go index 1f17431f5c326..c6d9557730d38 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/file/user_linux.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_linux.go @@ -1,4 +1,4 @@ -package file +package ops import ( "os" @@ -6,14 +6,18 @@ import ( "github.com/containerd/continuity/fs" "github.com/moby/buildkit/snapshot" - "github.com/moby/buildkit/solver/llbsolver/ops/fileoptypes" "github.com/moby/buildkit/solver/pb" - "github.com/opencontainers/runc/libcontainer/user" + "github.com/moby/buildkit/worker" + "github.com/moby/sys/user" "github.com/pkg/errors" copy "github.com/tonistiigi/fsutil/copy" ) -func readUser(chopt *pb.ChownOpt, mu, mg fileoptypes.Mount) (*copy.User, error) { +func getReadUserFn(worker worker.Worker) func(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { + return readUser +} + +func readUser(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { if chopt == nil { return nil, nil } @@ -24,11 +28,8 @@ func readUser(chopt *pb.ChownOpt, mu, mg fileoptypes.Mount) (*copy.User, error) if mu == nil { return nil, errors.Errorf("invalid missing user mount") } - mmu, ok := mu.(*Mount) - if !ok { - return nil, errors.Errorf("invalid mount type %T", mu) - } - lm := snapshot.LocalMounter(mmu.m) + + lm := snapshot.LocalMounter(mu) dir, err := lm.Mount() if err != nil { return nil, err @@ -78,11 +79,8 @@ func readUser(chopt *pb.ChownOpt, mu, mg fileoptypes.Mount) (*copy.User, error) if mg == nil { return nil, errors.Errorf("invalid missing group mount") } - mmg, ok := mg.(*Mount) - if !ok { - return nil, errors.Errorf("invalid mount type %T", mg) - } - lm := snapshot.LocalMounter(mmg.m) + + lm := snapshot.LocalMounter(mg) dir, err := lm.Mount() if err != nil { return nil, err diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_other.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_other.go new file mode 100644 index 0000000000000..f173ae38ca440 --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_other.go @@ -0,0 +1,23 @@ +//go:build !linux && !windows +// +build !linux,!windows + +package ops + +import ( + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/worker" + "github.com/pkg/errors" + copy "github.com/tonistiigi/fsutil/copy" +) + +func getReadUserFn(worker worker.Worker) func(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { + return readUser +} + +func readUser(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { + if chopt == nil { + return nil, nil + } + return nil, errors.New("only implemented in linux and windows") +} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_windows.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_windows.go new file mode 100644 index 0000000000000..553a2d210d0f4 --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/user_windows.go @@ -0,0 +1,48 @@ +package ops + +import ( + "context" + + "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/util/windows" + "github.com/moby/buildkit/worker" + "github.com/pkg/errors" + copy "github.com/tonistiigi/fsutil/copy" +) + +func getReadUserFn(worker worker.Worker) func(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { + return func(chopt *pb.ChownOpt, mu, mg snapshot.Mountable) (*copy.User, error) { + return readUser(chopt, mu, mg, worker) + } +} + +func readUser(chopt *pb.ChownOpt, mu, mg snapshot.Mountable, worker worker.Worker) (*copy.User, error) { + if chopt == nil { + return nil, nil + } + + if chopt.User != nil { + switch u := chopt.User.User.(type) { + case *pb.UserOpt_ByName: + if mu == nil { + return nil, errors.Errorf("invalid missing user mount") + } + + rootMounts, release, err := mu.Mount() + if err != nil { + return nil, err + } + defer release() + ident, err := windows.ResolveUsernameToSID(context.Background(), worker.Executor(), rootMounts, u.ByName.Name) + if err != nil { + return nil, err + } + return ©.User{SID: ident.SID}, nil + default: + return ©.User{SID: idtools.ContainerAdministratorSidString}, nil + } + } + return ©.User{SID: idtools.ContainerAdministratorSidString}, nil +} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/proc/sbom.go b/vendor/github.com/moby/buildkit/solver/llbsolver/proc/sbom.go index 20cdc71dae33b..49996d6a9ecfd 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/proc/sbom.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/proc/sbom.go @@ -4,6 +4,7 @@ import ( "context" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor/resources" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/frontend" @@ -26,8 +27,10 @@ func SBOMProcessor(scannerRef string, useCache bool, resolveMode string) llbsolv return nil, err } - scanner, err := sbom.CreateSBOMScanner(ctx, s.Bridge(j), scannerRef, llb.ResolveImageConfigOpt{ - ResolveMode: resolveMode, + scanner, err := sbom.CreateSBOMScanner(ctx, s.Bridge(j), scannerRef, sourceresolver.Opt{ + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: resolveMode, + }, }) if err != nil { return nil, err diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance.go b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance.go index 665c678adcd20..eb6163e492347 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance.go @@ -11,7 +11,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache/config" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor/resources" "github.com/moby/buildkit/exporter/containerimage" "github.com/moby/buildkit/exporter/containerimage/exptypes" @@ -20,7 +20,6 @@ import ( "github.com/moby/buildkit/solver/llbsolver/ops" "github.com/moby/buildkit/solver/llbsolver/provenance" "github.com/moby/buildkit/solver/pb" - "github.com/moby/buildkit/source" "github.com/moby/buildkit/worker" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -81,6 +80,9 @@ func (b *provenanceBridge) requests(r *frontend.Result) (*resultRequests, error) } for k, ref := range r.Refs { + if ref == nil { + continue + } r, ok := b.findByResult(ref) if !ok { return nil, errors.Errorf("could not find request for ref %s", ref.ID()) @@ -131,21 +133,25 @@ func (b *provenanceBridge) findByResult(rp solver.ResultProxy) (*resultWithBridg return nil, false } -func (b *provenanceBridge) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (resolvedRef string, dgst digest.Digest, config []byte, err error) { - ref, dgst, config, err = b.llbBridge.ResolveImageConfig(ctx, ref, opt) +func (b *provenanceBridge) ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt) (*sourceresolver.MetaResponse, error) { + resp, err := b.llbBridge.ResolveSourceMetadata(ctx, op, opt) if err != nil { - return "", "", nil, err + return nil, err } - - b.mu.Lock() - b.images = append(b.images, provenance.ImageSource{ - Ref: ref, - Platform: opt.Platform, - Digest: dgst, - Local: opt.ResolverType == llb.ResolverTypeOCILayout, - }) - b.mu.Unlock() - return ref, dgst, config, nil + if img := resp.Image; img != nil { + local := !strings.HasPrefix(resp.Op.Identifier, "docker-image://") + ref := strings.TrimPrefix(resp.Op.Identifier, "docker-image://") + ref = strings.TrimPrefix(ref, "oci-layout://") + b.mu.Lock() + b.images = append(b.images, provenance.ImageSource{ + Ref: ref, + Platform: opt.Platform, + Digest: img.Digest, + Local: local, + }) + b.mu.Unlock() + } + return resp, nil } func (b *provenanceBridge) Solve(ctx context.Context, req frontend.SolveRequest, sid string) (res *frontend.Result, err error) { @@ -178,7 +184,7 @@ func (b *provenanceBridge) Solve(ctx context.Context, req frontend.SolveRequest, } if req.Evaluate { err = res.EachRef(func(ref solver.ResultProxy) error { - _, err := res.Ref.Result(ctx) + _, err := ref.Result(ctx) return err }) } @@ -270,70 +276,9 @@ func captureProvenance(ctx context.Context, res solver.CachedResultWithProvenanc switch op := pp.(type) { case *ops.SourceOp: id, pin := op.Pin() - switch s := id.(type) { - case *source.ImageIdentifier: - dgst, err := digest.Parse(pin) - if err != nil { - return errors.Wrapf(err, "failed to parse image digest %s", pin) - } - c.AddImage(provenance.ImageSource{ - Ref: s.Reference.String(), - Platform: s.Platform, - Digest: dgst, - }) - case *source.LocalIdentifier: - c.AddLocal(provenance.LocalSource{ - Name: s.Name, - }) - case *source.GitIdentifier: - url := s.Remote - if s.Ref != "" { - url += "#" + s.Ref - } - c.AddGit(provenance.GitSource{ - URL: url, - Commit: pin, - }) - if s.AuthTokenSecret != "" { - c.AddSecret(provenance.Secret{ - ID: s.AuthTokenSecret, - Optional: true, - }) - } - if s.AuthHeaderSecret != "" { - c.AddSecret(provenance.Secret{ - ID: s.AuthHeaderSecret, - Optional: true, - }) - } - if s.MountSSHSock != "" { - c.AddSSH(provenance.SSH{ - ID: s.MountSSHSock, - Optional: true, - }) - } - case *source.HTTPIdentifier: - dgst, err := digest.Parse(pin) - if err != nil { - return errors.Wrapf(err, "failed to parse HTTP digest %s", pin) - } - c.AddHTTP(provenance.HTTPSource{ - URL: s.URL, - Digest: dgst, - }) - case *source.OCIIdentifier: - dgst, err := digest.Parse(pin) - if err != nil { - return errors.Wrapf(err, "failed to parse OCI digest %s", pin) - } - c.AddImage(provenance.ImageSource{ - Ref: s.Reference.String(), - Platform: s.Platform, - Digest: dgst, - Local: true, - }) - default: - return errors.Errorf("unknown source identifier %T", id) + err := id.Capture(c, pin) + if err != nil { + return err } case *ops.ExecOp: pr := op.Proto() @@ -552,12 +497,12 @@ func (ce *cacheExporter) Add(dgst digest.Digest) solver.CacheExporterRecord { } } -func (ce *cacheExporter) Visit(v interface{}) { - ce.m[v] = struct{}{} +func (ce *cacheExporter) Visit(target any) { + ce.m[target] = struct{}{} } -func (ce *cacheExporter) Visited(v interface{}) bool { - _, ok := ce.m[v] +func (ce *cacheExporter) Visited(target any) bool { + _, ok := ce.m[target] return ok } @@ -579,7 +524,7 @@ func (c *cacheRecord) AddResult(dgst digest.Digest, idx int, createdAt time.Time d.Annotations = containerimage.RemoveInternalLayerAnnotations(d.Annotations, true) descs[i] = d } - c.ce.layers[e] = append(c.ce.layers[e], descs) + c.ce.layers[e] = appendLayerChain(c.ce.layers[e], descs) } func (c *cacheRecord) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) { @@ -758,3 +703,25 @@ func walkDigests(dgsts []digest.Digest, ops map[digest.Digest]*pb.Op, dgst diges dgsts = append(dgsts, dgst) return dgsts, nil } + +// appendLayerChain appends a layer chain to the set of layers while checking for duplicate layer chains. +func appendLayerChain(layers [][]ocispecs.Descriptor, descs []ocispecs.Descriptor) [][]ocispecs.Descriptor { + for _, layerDescs := range layers { + if len(layerDescs) != len(descs) { + continue + } + + matched := true + for i, d := range layerDescs { + if d.Digest != descs[i].Digest { + matched = false + break + } + } + + if matched { + return layers + } + } + return append(layers, descs) +} diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/buildconfig.go b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/buildconfig.go index 8f903585be5c4..362273029832b 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/buildconfig.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/buildconfig.go @@ -13,7 +13,7 @@ type BuildConfig struct { type BuildStep struct { ID string `json:"id,omitempty"` - Op interface{} `json:"op,omitempty"` + Op pb.Op `json:"op,omitempty"` Inputs []string `json:"inputs,omitempty"` ResourceUsage *resourcestypes.Samples `json:"resourceUsage,omitempty"` } diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/capture.go b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/capture.go index f4d43fba4c6fb..54645eb61a9d9 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/capture.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/provenance/capture.go @@ -3,7 +3,7 @@ package provenance import ( "sort" - distreference "github.com/docker/distribution/reference" + distreference "github.com/distribution/reference" resourcestypes "github.com/moby/buildkit/executor/resources/types" "github.com/moby/buildkit/solver/result" "github.com/moby/buildkit/util/urlutil" @@ -152,7 +152,9 @@ func (c *Capture) AddImage(i ImageSource) { return } if v.Platform != nil && i.Platform != nil { - if v.Platform.Architecture == i.Platform.Architecture && v.Platform.OS == i.Platform.OS && v.Platform.Variant == i.Platform.Variant { + // NOTE: Deliberately excluding OSFeatures, as there's no extant (or rational) case where a source image is an index and contains images distinguished only by OSFeature + // See https://github.com/moby/buildkit/pull/4387#discussion_r1376234241 and https://github.com/opencontainers/image-spec/issues/1147 + if v.Platform.Architecture == i.Platform.Architecture && v.Platform.OS == i.Platform.OS && v.Platform.OSVersion == i.Platform.OSVersion && v.Platform.Variant == i.Platform.Variant { return } } diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go b/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go index 00b88b8159a79..7e33be3b48860 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go @@ -53,7 +53,7 @@ const ( type ExporterRequest struct { Type string Attrs map[string]string - Exporter exporter.ExporterInstance + Exporters []exporter.ExporterInstance CacheExporters []RemoteCacheExporter } @@ -123,6 +123,12 @@ func New(opt Opt) (*Solver, error) { return s, nil } +func (s *Solver) Close() error { + s.solver.Close() + err := s.sysSampler.Close() + return err +} + func (s *Solver) resolver() solver.ResolveOpFunc { return func(v solver.Vertex, b solver.Builder) (solver.Op, error) { w, err := s.resolveWorker() @@ -149,11 +155,11 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge { return s.bridge(b) } -func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest, j *solver.Job, usage *resources.SysSampler) (func(*Result, exporter.DescriptorReference, error) error, error) { +func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest, j *solver.Job, usage *resources.SysSampler) (func(*Result, []exporter.DescriptorReference, error) error, error) { var stopTrace func() []tracetest.SpanStub if s := trace.SpanFromContext(ctx); s.SpanContext().IsValid() { - if exp, err := detect.Exporter(); err == nil { + if exp, _, err := detect.Exporter(); err == nil { if rec, ok := exp.(*detect.TraceRecorder); ok { stopTrace = rec.Record(s.SpanContext().TraceID()) } @@ -182,7 +188,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend return nil, err } - return func(res *Result, descref exporter.DescriptorReference, err error) error { + return func(res *Result, descrefs []exporter.DescriptorReference, err error) error { en := time.Now() rec.CompletedAt = &en @@ -195,8 +201,9 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend } } - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() + ctx, cancel := context.WithCancelCause(context.Background()) + ctx, _ = context.WithTimeoutCause(ctx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) var mu sync.Mutex ch := make(chan *client.SolveStatus) @@ -268,6 +275,9 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend } for k, r := range res.Refs { + if r == nil { + continue + } k, r := k, r cp := res.Provenance.Refs[k] eg.Go(func() error { @@ -313,24 +323,39 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend return j.Status(ctx2, ch) }) - if descref != nil { + setDeprecated := true + for i, descref := range descrefs { + i, descref := i, descref + if descref == nil { + continue + } + deprecate := setDeprecated + setDeprecated = false eg.Go(func() error { mu.Lock() - if rec.Result == nil { - rec.Result = &controlapi.BuildResultInfo{} - } desc := descref.Descriptor() - rec.Result.Result = &controlapi.Descriptor{ + controlDesc := &controlapi.Descriptor{ Digest: desc.Digest, Size_: desc.Size, MediaType: desc.MediaType, Annotations: desc.Annotations, } + if rec.Result == nil { + rec.Result = &controlapi.BuildResultInfo{} + } + if rec.Result.Results == nil { + rec.Result.Results = make(map[int64]*controlapi.Descriptor) + } + if deprecate { + // write the first available descriptor to the deprecated + // field for legacy clients + rec.Result.ResultDeprecated = controlDesc + } + rec.Result.Results[int64(i)] = controlDesc mu.Unlock() return nil }) } - if err1 := eg.Wait(); err == nil { err = err1 } @@ -424,15 +449,17 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro var res *frontend.Result var resProv *Result - var descref exporter.DescriptorReference + var descrefs []exporter.DescriptorReference var releasers []func() defer func() { for _, f := range releasers { f() } - if descref != nil { - descref.Release() + for _, descref := range descrefs { + if descref != nil { + descref.Release() + } } }() @@ -477,7 +504,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro return nil, err1 } defer func() { - err = rec(resProv, descref, err) + err = rec(resProv, descrefs, err) }() } @@ -487,7 +514,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro case <-fwd.Done(): res, err = fwd.Result() case <-ctx.Done(): - err = ctx.Err() + err = context.Cause(ctx) } if err != nil { return nil, err @@ -556,21 +583,9 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro cacheExporters, inlineCacheExporter := splitCacheExporters(exp.CacheExporters) var exporterResponse map[string]string - if e := exp.Exporter; e != nil { - meta, err := runInlineCacheExporter(ctx, e, inlineCacheExporter, j, cached) - if err != nil { - return nil, err - } - for k, v := range meta { - inp.AddMeta(k, v) - } - - if err := inBuilderContext(ctx, j, e.Name(), j.SessionID+"-export", func(ctx context.Context, _ session.Group) error { - exporterResponse, descref, err = e.Export(ctx, inp, j.SessionID) - return err - }); err != nil { - return nil, err - } + exporterResponse, descrefs, err = s.runExporters(ctx, exp.Exporters, inlineCacheExporter, j, cached, inp) + if err != nil { + return nil, err } cacheExporterResponse, err := runCacheExporters(ctx, cacheExporters, j, cached, inp) @@ -621,41 +636,43 @@ func runCacheExporters(ctx context.Context, exporters []RemoteCacheExporter, j * var cacheExporterResponse map[string]string resps := make([]map[string]string, len(exporters)) for i, exp := range exporters { - func(exp RemoteCacheExporter, i int) { - eg.Go(func() (err error) { - id := fmt.Sprint(j.SessionID, "-cache-", i) - err = inBuilderContext(ctx, j, exp.Exporter.Name(), id, func(ctx context.Context, _ session.Group) error { - prepareDone := progress.OneOff(ctx, "preparing build cache for export") - if err := result.EachRef(cached, inp, func(res solver.CachedResult, ref cache.ImmutableRef) error { - ctx = withDescHandlerCacheOpts(ctx, ref) - - // Configure compression - compressionConfig := exp.Config().Compression - - // all keys have same export chain so exporting others is not needed - _, err = res.CacheKeys()[0].Exporter.ExportTo(ctx, exp, solver.CacheExportOpt{ - ResolveRemotes: workerRefResolver(cacheconfig.RefConfig{Compression: compressionConfig}, false, g), - Mode: exp.CacheExportMode, - Session: g, - CompressionOpt: &compressionConfig, - }) - return err - }); err != nil { - return prepareDone(err) - } - resps[i], err = exp.Finalize(ctx) + i, exp := i, exp + eg.Go(func() (err error) { + id := fmt.Sprint(j.SessionID, "-cache-", i) + err = inBuilderContext(ctx, j, exp.Exporter.Name(), id, func(ctx context.Context, _ session.Group) error { + prepareDone := progress.OneOff(ctx, "preparing build cache for export") + if err := result.EachRef(cached, inp, func(res solver.CachedResult, ref cache.ImmutableRef) error { + ctx = withDescHandlerCacheOpts(ctx, ref) + + // Configure compression + compressionConfig := exp.Config().Compression + + // all keys have same export chain so exporting others is not needed + _, err = res.CacheKeys()[0].Exporter.ExportTo(ctx, exp, solver.CacheExportOpt{ + ResolveRemotes: workerRefResolver(cacheconfig.RefConfig{Compression: compressionConfig}, false, g), + Mode: exp.CacheExportMode, + Session: g, + CompressionOpt: &compressionConfig, + }) + return err + }); err != nil { return prepareDone(err) - }) - if exp.IgnoreError { - err = nil } - return err + resps[i], err = exp.Finalize(ctx) + return prepareDone(err) }) - }(exp, i) + if exp.IgnoreError { + err = nil + } + return err + }) } if err := eg.Wait(); err != nil { return nil, err } + + // TODO: separate these out, and return multiple cache exporter responses + // to the client for _, resp := range resps { for k, v := range resp { if cacheExporterResponse == nil { @@ -667,42 +684,69 @@ func runCacheExporters(ctx context.Context, exporters []RemoteCacheExporter, j * return cacheExporterResponse, nil } -func runInlineCacheExporter(ctx context.Context, e exporter.ExporterInstance, inlineExporter *RemoteCacheExporter, j *solver.Job, cached *result.Result[solver.CachedResult]) (map[string][]byte, error) { - meta := map[string][]byte{} +func runInlineCacheExporter(ctx context.Context, e exporter.ExporterInstance, inlineExporter inlineCacheExporter, j *solver.Job, cached *result.Result[solver.CachedResult]) (*result.Result[*exptypes.InlineCacheEntry], error) { if inlineExporter == nil { return nil, nil } - if err := inBuilderContext(ctx, j, "preparing layers for inline cache", j.SessionID+"-cache-inline", func(ctx context.Context, _ session.Group) error { - if res := cached.Ref; res != nil { - dtic, err := inlineCache(ctx, inlineExporter.Exporter, res, e.Config().Compression(), session.NewGroup(j.SessionID)) - if err != nil { - return err - } - if dtic != nil { - meta[exptypes.ExporterInlineCache] = dtic - } + + done := progress.OneOff(ctx, "preparing layers for inline cache") + res, err := result.ConvertResult(cached, func(res solver.CachedResult) (*exptypes.InlineCacheEntry, error) { + dtic, err := inlineCache(ctx, inlineExporter, res, e.Config().Compression(), session.NewGroup(j.SessionID)) + if err != nil { + return nil, err } - for k, res := range cached.Refs { - dtic, err := inlineCache(ctx, inlineExporter.Exporter, res, e.Config().Compression(), session.NewGroup(j.SessionID)) - if err != nil { - return err - } - if dtic != nil { - meta[fmt.Sprintf("%s/%s", exptypes.ExporterInlineCache, k)] = dtic + if dtic == nil { + return nil, nil + } + return &exptypes.InlineCacheEntry{Data: dtic}, nil + }) + return res, done(err) +} + +func (s *Solver) runExporters(ctx context.Context, exporters []exporter.ExporterInstance, inlineCacheExporter inlineCacheExporter, job *solver.Job, cached *result.Result[solver.CachedResult], inp *result.Result[cache.ImmutableRef]) (exporterResponse map[string]string, descrefs []exporter.DescriptorReference, err error) { + eg, ctx := errgroup.WithContext(ctx) + resps := make([]map[string]string, len(exporters)) + descs := make([]exporter.DescriptorReference, len(exporters)) + for i, exp := range exporters { + i, exp := i, exp + eg.Go(func() error { + id := fmt.Sprint(job.SessionID, "-export-", i) + return inBuilderContext(ctx, job, exp.Name(), id, func(ctx context.Context, _ session.Group) error { + inlineCache := exptypes.InlineCache(func(ctx context.Context) (*result.Result[*exptypes.InlineCacheEntry], error) { + return runInlineCacheExporter(ctx, exp, inlineCacheExporter, job, cached) + }) + + resps[i], descs[i], err = exp.Export(ctx, inp, inlineCache, job.SessionID) + if err != nil { + return err + } + return nil + }) + }) + } + if err := eg.Wait(); err != nil { + return nil, nil, err + } + + // TODO: separate these out, and return multiple exporter responses to the + // client + for _, resp := range resps { + for k, v := range resp { + if exporterResponse == nil { + exporterResponse = make(map[string]string) } + exporterResponse[k] = v } - return nil - }); err != nil { - return nil, err } - return meta, nil + + return exporterResponse, descs, nil } -func splitCacheExporters(exporters []RemoteCacheExporter) (rest []RemoteCacheExporter, inline *RemoteCacheExporter) { +func splitCacheExporters(exporters []RemoteCacheExporter) (rest []RemoteCacheExporter, inline inlineCacheExporter) { rest = make([]RemoteCacheExporter, 0, len(exporters)) - for i, exp := range exporters { - if _, ok := asInlineCache(exp.Exporter); ok { - inline = &exporters[i] + for _, exp := range exporters { + if ic, ok := asInlineCache(exp.Exporter); ok { + inline = ic continue } rest = append(rest, exp) @@ -738,6 +782,9 @@ func addProvenanceToResult(res *frontend.Result, br *provenanceBridge) (*Result, out.Provenance.Refs = make(map[string]*provenance.Capture, len(res.Refs)) } for k, ref := range res.Refs { + if ref == nil { + continue + } cp, err := getProvenance(ref, reqs.refs[k].bridge, k, reqs) if err != nil { return nil, err @@ -840,6 +887,7 @@ func getProvenance(ref solver.ResultProxy, br *provenanceBridge, id string, reqs } type inlineCacheExporter interface { + solver.CacheExporterTarget ExportForLayers(context.Context, []digest.Digest) ([]byte, error) } @@ -848,11 +896,7 @@ func asInlineCache(e remotecache.Exporter) (inlineCacheExporter, bool) { return ie, ok } -func inlineCache(ctx context.Context, e remotecache.Exporter, res solver.CachedResult, compressionopt compression.Config, g session.Group) ([]byte, error) { - ie, ok := asInlineCache(e) - if !ok { - return nil, nil - } +func inlineCache(ctx context.Context, ie inlineCacheExporter, res solver.CachedResult, compressionopt compression.Config, g session.Group) ([]byte, error) { workerRef, ok := res.Sys().(*worker.WorkerRef) if !ok { return nil, errors.Errorf("invalid reference: %T", res.Sys()) @@ -871,7 +915,7 @@ func inlineCache(ctx context.Context, e remotecache.Exporter, res solver.CachedR ctx = withDescHandlerCacheOpts(ctx, workerRef.ImmutableRef) refCfg := cacheconfig.RefConfig{Compression: compressionopt} - if _, err := res.CacheKeys()[0].Exporter.ExportTo(ctx, e, solver.CacheExportOpt{ + if _, err := res.CacheKeys()[0].Exporter.ExportTo(ctx, ie, solver.CacheExportOpt{ ResolveRemotes: workerRefResolver(refCfg, true, g), // load as many compression blobs as possible Mode: solver.CacheExportModeMin, Session: g, diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/sourcepolicy.go b/vendor/github.com/moby/buildkit/solver/llbsolver/sourcepolicy.go index 11a49616b301c..ac61bb547aaca 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/sourcepolicy.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/sourcepolicy.go @@ -7,5 +7,5 @@ import ( ) type SourcePolicyEvaluator interface { - Evaluate(ctx context.Context, op *pb.Op) (bool, error) + Evaluate(ctx context.Context, op *pb.SourceOp) (bool, error) } diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go b/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go index d57f2a053db13..c58eb135e7d77 100644 --- a/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go +++ b/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go @@ -9,7 +9,6 @@ import ( "github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver/llbsolver/ops/opsutils" "github.com/moby/buildkit/solver/pb" - "github.com/moby/buildkit/source" "github.com/moby/buildkit/util/entitlements" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" @@ -80,17 +79,29 @@ func NormalizeRuntimePlatforms() LoadOpt { OS: p.OS, Architecture: p.Architecture, Variant: p.Variant, + OSVersion: p.OSVersion, + OSFeatures: p.OSFeatures, } } op.Platform = defaultPlatform } - platform := ocispecs.Platform{OS: op.Platform.OS, Architecture: op.Platform.Architecture, Variant: op.Platform.Variant} + platform := ocispecs.Platform{ + OS: op.Platform.OS, + Architecture: op.Platform.Architecture, + Variant: op.Platform.Variant, + OSVersion: op.Platform.OSVersion, + OSFeatures: op.Platform.OSFeatures, + } normalizedPlatform := platforms.Normalize(platform) op.Platform = &pb.Platform{ OS: normalizedPlatform.OS, Architecture: normalizedPlatform.Architecture, Variant: normalizedPlatform.Variant, + OSVersion: normalizedPlatform.OSVersion, + } + if normalizedPlatform.OSFeatures != nil { + op.Platform.OSFeatures = append([]string{}, normalizedPlatform.OSFeatures...) } return nil @@ -191,8 +202,10 @@ func recomputeDigests(ctx context.Context, all map[digest.Digest]*pb.Op, visited var mutated bool for _, input := range op.Inputs { - if ctx.Err() != nil { - return "", ctx.Err() + select { + case <-ctx.Done(): + return "", context.Cause(ctx) + default: } iDgst, err := recomputeDigests(ctx, all, visited, input.Digest) @@ -240,7 +253,7 @@ func loadLLB(ctx context.Context, def *pb.Definition, polEngine SourcePolicyEval } dgst := digest.FromBytes(dt) if polEngine != nil { - mutated, err := polEngine.Evaluate(ctx, &op) + mutated, err := polEngine.Evaluate(ctx, op.GetSource()) if err != nil { return solver.Edge{}, errors.Wrap(err, "error evaluating the source policy") } @@ -318,13 +331,6 @@ func loadLLB(ctx context.Context, def *pb.Definition, polEngine SourcePolicyEval func llbOpName(pbOp *pb.Op, load func(digest.Digest) (solver.Vertex, error)) (string, error) { switch op := pbOp.Op.(type) { case *pb.Op_Source: - if id, err := source.FromLLB(op, nil); err == nil { - if id, ok := id.(*source.LocalIdentifier); ok { - if len(id.IncludePatterns) == 1 { - return op.Source.Identifier + " (" + id.IncludePatterns[0] + ")", nil - } - } - } return op.Source.Identifier, nil case *pb.Op_Exec: return strings.Join(op.Exec.Meta.Args, " "), nil diff --git a/vendor/github.com/moby/buildkit/solver/pb/caps.go b/vendor/github.com/moby/buildkit/solver/pb/caps.go index 5e1963ff8faab..69fedae65dd75 100644 --- a/vendor/github.com/moby/buildkit/solver/pb/caps.go +++ b/vendor/github.com/moby/buildkit/solver/pb/caps.go @@ -57,6 +57,7 @@ const ( CapExecMountTmpfsSize apicaps.CapID = "exec.mount.tmpfs.size" CapExecMountSecret apicaps.CapID = "exec.mount.secret" CapExecMountSSH apicaps.CapID = "exec.mount.ssh" + CapExecMountContentCache apicaps.CapID = "exec.mount.cache.content" CapExecCgroupsMounted apicaps.CapID = "exec.cgroup" CapExecSecretEnv apicaps.CapID = "exec.secretenv" @@ -85,6 +86,8 @@ const ( // CapSourceDateEpoch is the capability to automatically handle the date epoch CapSourceDateEpoch apicaps.CapID = "exporter.sourcedateepoch" + CapMultipleExporters apicaps.CapID = "exporter.multiple" + CapSourcePolicy apicaps.CapID = "source.policy" ) @@ -335,6 +338,12 @@ func init() { Status: apicaps.CapStatusExperimental, }) + Caps.Init(apicaps.Cap{ + ID: CapExecMountContentCache, + Enabled: true, + Status: apicaps.CapStatusExperimental, + }) + Caps.Init(apicaps.Cap{ ID: CapExecCgroupsMounted, Enabled: true, @@ -454,6 +463,12 @@ func init() { Status: apicaps.CapStatusExperimental, }) + Caps.Init(apicaps.Cap{ + ID: CapMultipleExporters, + Enabled: true, + Status: apicaps.CapStatusExperimental, + }) + Caps.Init(apicaps.Cap{ ID: CapSourcePolicy, Enabled: true, diff --git a/vendor/github.com/moby/buildkit/solver/pb/json.go b/vendor/github.com/moby/buildkit/solver/pb/json.go new file mode 100644 index 0000000000000..8460ffc10f31a --- /dev/null +++ b/vendor/github.com/moby/buildkit/solver/pb/json.go @@ -0,0 +1,96 @@ +package pb + +import "encoding/json" + +func (m *Op) UnmarshalJSON(data []byte) error { + var v struct { + Inputs []*Input `json:"inputs,omitempty"` + Op struct { + *Op_Exec + *Op_Source + *Op_File + *Op_Build + *Op_Merge + *Op_Diff + } + Platform *Platform `json:"platform,omitempty"` + Constraints *WorkerConstraints `json:"constraints,omitempty"` + } + + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + m.Inputs = v.Inputs + switch { + case v.Op.Op_Exec != nil: + m.Op = v.Op.Op_Exec + case v.Op.Op_Source != nil: + m.Op = v.Op.Op_Source + case v.Op.Op_File != nil: + m.Op = v.Op.Op_File + case v.Op.Op_Build != nil: + m.Op = v.Op.Op_Build + case v.Op.Op_Merge != nil: + m.Op = v.Op.Op_Merge + case v.Op.Op_Diff != nil: + m.Op = v.Op.Op_Diff + } + m.Platform = v.Platform + m.Constraints = v.Constraints + return nil +} + +func (m *FileAction) UnmarshalJSON(data []byte) error { + var v struct { + Input InputIndex `json:"input"` + SecondaryInput InputIndex `json:"secondaryInput"` + Output OutputIndex `json:"output"` + Action struct { + *FileAction_Copy + *FileAction_Mkfile + *FileAction_Mkdir + *FileAction_Rm + } + } + + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + m.Input = v.Input + m.SecondaryInput = v.SecondaryInput + m.Output = v.Output + switch { + case v.Action.FileAction_Copy != nil: + m.Action = v.Action.FileAction_Copy + case v.Action.FileAction_Mkfile != nil: + m.Action = v.Action.FileAction_Mkfile + case v.Action.FileAction_Mkdir != nil: + m.Action = v.Action.FileAction_Mkdir + case v.Action.FileAction_Rm != nil: + m.Action = v.Action.FileAction_Rm + } + return nil +} + +func (m *UserOpt) UnmarshalJSON(data []byte) error { + var v struct { + User struct { + *UserOpt_ByName + *UserOpt_ByID + } + } + + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch { + case v.User.UserOpt_ByName != nil: + m.User = v.User.UserOpt_ByName + case v.User.UserOpt_ByID != nil: + m.User = v.User.UserOpt_ByID + } + return nil +} diff --git a/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go b/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go index aadff21b6474b..55db95d9aae76 100644 --- a/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go +++ b/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go @@ -117,6 +117,35 @@ func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_8de16154b2733812, []int{2} } +// MountContentCache ... +type MountContentCache int32 + +const ( + MountContentCache_DEFAULT MountContentCache = 0 + MountContentCache_ON MountContentCache = 1 + MountContentCache_OFF MountContentCache = 2 +) + +var MountContentCache_name = map[int32]string{ + 0: "DEFAULT", + 1: "ON", + 2: "OFF", +} + +var MountContentCache_value = map[string]int32{ + "DEFAULT": 0, + "ON": 1, + "OFF": 2, +} + +func (x MountContentCache) String() string { + return proto.EnumName(MountContentCache_name, int32(x)) +} + +func (MountContentCache) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8de16154b2733812, []int{3} +} + // CacheSharingOpt defines different sharing modes for cache mount type CacheSharingOpt int32 @@ -146,11 +175,12 @@ func (x CacheSharingOpt) String() string { } func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8de16154b2733812, []int{3} + return fileDescriptor_8de16154b2733812, []int{4} } // Op represents a vertex of the LLB DAG. type Op struct { + // changes to this structure must be represented in json.go. // inputs is a set of input edges. Inputs []*Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` // Types that are valid to be assigned to Op: @@ -770,17 +800,18 @@ func (m *SecretEnv) GetOptional() bool { // Mount specifies how to mount an input Op as a filesystem. type Mount struct { - Input InputIndex `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"` - Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` - Dest string `protobuf:"bytes,3,opt,name=dest,proto3" json:"dest,omitempty"` - Output OutputIndex `protobuf:"varint,4,opt,name=output,proto3,customtype=OutputIndex" json:"output"` - Readonly bool `protobuf:"varint,5,opt,name=readonly,proto3" json:"readonly,omitempty"` - MountType MountType `protobuf:"varint,6,opt,name=mountType,proto3,enum=pb.MountType" json:"mountType,omitempty"` - TmpfsOpt *TmpfsOpt `protobuf:"bytes,19,opt,name=TmpfsOpt,proto3" json:"TmpfsOpt,omitempty"` - CacheOpt *CacheOpt `protobuf:"bytes,20,opt,name=cacheOpt,proto3" json:"cacheOpt,omitempty"` - SecretOpt *SecretOpt `protobuf:"bytes,21,opt,name=secretOpt,proto3" json:"secretOpt,omitempty"` - SSHOpt *SSHOpt `protobuf:"bytes,22,opt,name=SSHOpt,proto3" json:"SSHOpt,omitempty"` - ResultID string `protobuf:"bytes,23,opt,name=resultID,proto3" json:"resultID,omitempty"` + Input InputIndex `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"` + Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` + Dest string `protobuf:"bytes,3,opt,name=dest,proto3" json:"dest,omitempty"` + Output OutputIndex `protobuf:"varint,4,opt,name=output,proto3,customtype=OutputIndex" json:"output"` + Readonly bool `protobuf:"varint,5,opt,name=readonly,proto3" json:"readonly,omitempty"` + MountType MountType `protobuf:"varint,6,opt,name=mountType,proto3,enum=pb.MountType" json:"mountType,omitempty"` + TmpfsOpt *TmpfsOpt `protobuf:"bytes,19,opt,name=TmpfsOpt,proto3" json:"TmpfsOpt,omitempty"` + CacheOpt *CacheOpt `protobuf:"bytes,20,opt,name=cacheOpt,proto3" json:"cacheOpt,omitempty"` + SecretOpt *SecretOpt `protobuf:"bytes,21,opt,name=secretOpt,proto3" json:"secretOpt,omitempty"` + SSHOpt *SSHOpt `protobuf:"bytes,22,opt,name=SSHOpt,proto3" json:"SSHOpt,omitempty"` + ResultID string `protobuf:"bytes,23,opt,name=resultID,proto3" json:"resultID,omitempty"` + ContentCache MountContentCache `protobuf:"varint,24,opt,name=contentCache,proto3,enum=pb.MountContentCache" json:"contentCache,omitempty"` } func (m *Mount) Reset() { *m = Mount{} } @@ -875,6 +906,13 @@ func (m *Mount) GetResultID() string { return "" } +func (m *Mount) GetContentCache() MountContentCache { + if m != nil { + return m.ContentCache + } + return MountContentCache_DEFAULT +} + // TmpfsOpt defines options describing tpmfs mounts type TmpfsOpt struct { // Specify an upper limit on the size of the filesystem. @@ -1961,6 +1999,7 @@ func (m *FileOp) GetActions() []*FileAction { } type FileAction struct { + // changes to this structure must be represented in json.go. Input InputIndex `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"` SecondaryInput InputIndex `protobuf:"varint,2,opt,name=secondaryInput,proto3,customtype=InputIndex" json:"secondaryInput"` Output OutputIndex `protobuf:"varint,3,opt,name=output,proto3,customtype=OutputIndex" json:"output"` @@ -2482,6 +2521,8 @@ func (m *ChownOpt) GetGroup() *UserOpt { } type UserOpt struct { + // changes to this structure must be represented in json.go. + // // Types that are valid to be assigned to User: // // *UserOpt_ByName @@ -2795,6 +2836,7 @@ func init() { proto.RegisterEnum("pb.NetMode", NetMode_name, NetMode_value) proto.RegisterEnum("pb.SecurityMode", SecurityMode_name, SecurityMode_value) proto.RegisterEnum("pb.MountType", MountType_name, MountType_value) + proto.RegisterEnum("pb.MountContentCache", MountContentCache_name, MountContentCache_value) proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value) proto.RegisterType((*Op)(nil), "pb.Op") proto.RegisterType((*Platform)(nil), "pb.Platform") @@ -2850,169 +2892,172 @@ func init() { func init() { proto.RegisterFile("ops.proto", fileDescriptor_8de16154b2733812) } var fileDescriptor_8de16154b2733812 = []byte{ - // 2577 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x4f, 0x6f, 0x5b, 0xc7, - 0x11, 0x17, 0xff, 0x93, 0x43, 0x89, 0x66, 0xd6, 0x4e, 0xc2, 0xa8, 0xae, 0xac, 0xbc, 0xa4, 0x81, - 0x2c, 0xdb, 0x12, 0xaa, 0x00, 0x71, 0x60, 0x04, 0x45, 0x25, 0x91, 0x8e, 0x18, 0xc7, 0xa2, 0xb0, - 0xb4, 0x9d, 0x1e, 0x0a, 0x18, 0x4f, 0x8f, 0x4b, 0xea, 0x41, 0xef, 0xbd, 0x7d, 0x78, 0x6f, 0x69, - 0x89, 0x3d, 0xf4, 0xd0, 0x53, 0x8f, 0x01, 0x0a, 0x14, 0xbd, 0x14, 0xfd, 0x12, 0x3d, 0xb6, 0xf7, - 0x00, 0xb9, 0xe4, 0xd0, 0x43, 0xd0, 0x43, 0x5a, 0x38, 0x97, 0x7e, 0x88, 0x16, 0x28, 0x66, 0x76, - 0xdf, 0x1f, 0x52, 0x32, 0x6c, 0xb7, 0x45, 0x4f, 0x9c, 0x37, 0xf3, 0xdb, 0xd9, 0xd9, 0xd9, 0x99, - 0x9d, 0xd9, 0x25, 0x34, 0x64, 0x18, 0x6f, 0x85, 0x91, 0x54, 0x92, 0x15, 0xc3, 0xe3, 0xd5, 0x3b, - 0x13, 0x57, 0x9d, 0x4c, 0x8f, 0xb7, 0x1c, 0xe9, 0x6f, 0x4f, 0xe4, 0x44, 0x6e, 0x93, 0xe8, 0x78, - 0x3a, 0xa6, 0x2f, 0xfa, 0x20, 0x4a, 0x0f, 0xb1, 0xfe, 0x51, 0x84, 0xe2, 0x20, 0x64, 0xef, 0x42, - 0xd5, 0x0d, 0xc2, 0xa9, 0x8a, 0x3b, 0x85, 0xf5, 0xd2, 0x46, 0x73, 0xa7, 0xb1, 0x15, 0x1e, 0x6f, - 0xf5, 0x91, 0xc3, 0x8d, 0x80, 0xad, 0x43, 0x59, 0x9c, 0x0b, 0xa7, 0x53, 0x5c, 0x2f, 0x6c, 0x34, - 0x77, 0x00, 0x01, 0xbd, 0x73, 0xe1, 0x0c, 0xc2, 0x83, 0x25, 0x4e, 0x12, 0xf6, 0x01, 0x54, 0x63, - 0x39, 0x8d, 0x1c, 0xd1, 0x29, 0x11, 0x66, 0x19, 0x31, 0x43, 0xe2, 0x10, 0xca, 0x48, 0x51, 0xd3, - 0xd8, 0xf5, 0x44, 0xa7, 0x9c, 0x69, 0xba, 0xef, 0x7a, 0x1a, 0x43, 0x12, 0xf6, 0x1e, 0x54, 0x8e, - 0xa7, 0xae, 0x37, 0xea, 0x54, 0x08, 0xd2, 0x44, 0xc8, 0x1e, 0x32, 0x08, 0xa3, 0x65, 0x08, 0xf2, - 0x45, 0x34, 0x11, 0x9d, 0x6a, 0x06, 0x7a, 0x88, 0x0c, 0x0d, 0x22, 0x19, 0xce, 0x35, 0x72, 0xc7, - 0xe3, 0x4e, 0x2d, 0x9b, 0xab, 0xeb, 0x8e, 0xc7, 0x7a, 0x2e, 0x94, 0xb0, 0x0d, 0xa8, 0x87, 0x9e, - 0xad, 0xc6, 0x32, 0xf2, 0x3b, 0x90, 0xd9, 0x7d, 0x64, 0x78, 0x3c, 0x95, 0xb2, 0xbb, 0xd0, 0x74, - 0x64, 0x10, 0xab, 0xc8, 0x76, 0x03, 0x15, 0x77, 0x9a, 0x04, 0x7e, 0x13, 0xc1, 0x5f, 0xc8, 0xe8, - 0x54, 0x44, 0xfb, 0x99, 0x90, 0xe7, 0x91, 0x7b, 0x65, 0x28, 0xca, 0xd0, 0xfa, 0x6d, 0x01, 0xea, - 0x89, 0x56, 0x66, 0xc1, 0xf2, 0x6e, 0xe4, 0x9c, 0xb8, 0x4a, 0x38, 0x6a, 0x1a, 0x89, 0x4e, 0x61, - 0xbd, 0xb0, 0xd1, 0xe0, 0x73, 0x3c, 0xd6, 0x82, 0xe2, 0x60, 0x48, 0xfe, 0x6e, 0xf0, 0xe2, 0x60, - 0xc8, 0x3a, 0x50, 0x7b, 0x62, 0x47, 0xae, 0x1d, 0x28, 0x72, 0x70, 0x83, 0x27, 0x9f, 0xec, 0x3a, - 0x34, 0x06, 0xc3, 0x27, 0x22, 0x8a, 0x5d, 0x19, 0x90, 0x5b, 0x1b, 0x3c, 0x63, 0xb0, 0x35, 0x80, - 0xc1, 0xf0, 0xbe, 0xb0, 0x51, 0x69, 0xdc, 0xa9, 0xac, 0x97, 0x36, 0x1a, 0x3c, 0xc7, 0xb1, 0x7e, - 0x09, 0x15, 0xda, 0x6a, 0xf6, 0x19, 0x54, 0x47, 0xee, 0x44, 0xc4, 0x4a, 0x9b, 0xb3, 0xb7, 0xf3, - 0xd5, 0x77, 0x37, 0x96, 0xfe, 0xfa, 0xdd, 0x8d, 0xcd, 0x5c, 0x4c, 0xc9, 0x50, 0x04, 0x8e, 0x0c, - 0x94, 0xed, 0x06, 0x22, 0x8a, 0xb7, 0x27, 0xf2, 0x8e, 0x1e, 0xb2, 0xd5, 0xa5, 0x1f, 0x6e, 0x34, - 0xb0, 0x9b, 0x50, 0x71, 0x83, 0x91, 0x38, 0x27, 0xfb, 0x4b, 0x7b, 0x57, 0x8d, 0xaa, 0xe6, 0x60, - 0xaa, 0xc2, 0xa9, 0xea, 0xa3, 0x88, 0x6b, 0x84, 0xf5, 0x75, 0x01, 0xaa, 0x3a, 0x94, 0xd8, 0x75, - 0x28, 0xfb, 0x42, 0xd9, 0x34, 0x7f, 0x73, 0xa7, 0xae, 0xb7, 0x54, 0xd9, 0x9c, 0xb8, 0x18, 0xa5, - 0xbe, 0x9c, 0xa2, 0xef, 0x8b, 0x59, 0x94, 0x3e, 0x44, 0x0e, 0x37, 0x02, 0xf6, 0x23, 0xa8, 0x05, - 0x42, 0x9d, 0xc9, 0xe8, 0x94, 0x7c, 0xd4, 0xd2, 0x61, 0x71, 0x28, 0xd4, 0x43, 0x39, 0x12, 0x3c, - 0x91, 0xb1, 0xdb, 0x50, 0x8f, 0x85, 0x33, 0x8d, 0x5c, 0x35, 0x23, 0x7f, 0xb5, 0x76, 0xda, 0x14, - 0xac, 0x86, 0x47, 0xe0, 0x14, 0xc1, 0x6e, 0x41, 0x23, 0x16, 0x4e, 0x24, 0x94, 0x08, 0x9e, 0x91, - 0xff, 0x9a, 0x3b, 0x2b, 0x06, 0x1e, 0x09, 0xd5, 0x0b, 0x9e, 0xf1, 0x4c, 0x6e, 0x7d, 0x5d, 0x84, - 0x32, 0xda, 0xcc, 0x18, 0x94, 0xed, 0x68, 0xa2, 0x33, 0xaa, 0xc1, 0x89, 0x66, 0x6d, 0x28, 0xa1, - 0x8e, 0x22, 0xb1, 0x90, 0x44, 0x8e, 0x73, 0x36, 0x32, 0x1b, 0x8a, 0x24, 0x8e, 0x9b, 0xc6, 0x22, - 0x32, 0xfb, 0x48, 0x34, 0xbb, 0x09, 0x8d, 0x30, 0x92, 0xe7, 0xb3, 0xa7, 0xda, 0x82, 0x2c, 0x4a, - 0x91, 0x89, 0x06, 0xd4, 0x43, 0x43, 0xb1, 0x4d, 0x00, 0x71, 0xae, 0x22, 0xfb, 0x40, 0xc6, 0x2a, - 0xee, 0x54, 0xc9, 0x5a, 0x8a, 0x7b, 0x64, 0xf4, 0x8f, 0x78, 0x4e, 0xca, 0x56, 0xa1, 0x7e, 0x22, - 0x63, 0x15, 0xd8, 0xbe, 0xa0, 0x0c, 0x69, 0xf0, 0xf4, 0x9b, 0x59, 0x50, 0x9d, 0x7a, 0xae, 0xef, - 0xaa, 0x4e, 0x23, 0xd3, 0xf1, 0x98, 0x38, 0xdc, 0x48, 0x30, 0x8a, 0x9d, 0x49, 0x24, 0xa7, 0xe1, - 0x91, 0x1d, 0x89, 0x40, 0x51, 0xfe, 0x34, 0xf8, 0x1c, 0x8f, 0x7d, 0x02, 0xef, 0x44, 0xc2, 0x97, - 0xcf, 0x04, 0x6d, 0xd4, 0x50, 0x4d, 0x8f, 0x63, 0x8e, 0x8e, 0x8d, 0xdd, 0x67, 0x82, 0x72, 0xa8, - 0xce, 0x5f, 0x0c, 0xb0, 0x6e, 0x43, 0x55, 0xdb, 0x8d, 0x6e, 0x41, 0xca, 0x64, 0x0a, 0xd1, 0x98, - 0x21, 0xfd, 0xa3, 0x24, 0x43, 0xfa, 0x47, 0x56, 0x17, 0xaa, 0xda, 0x42, 0x44, 0x1f, 0xe2, 0xaa, - 0x0c, 0x1a, 0x69, 0xe4, 0x0d, 0xe5, 0x58, 0xe9, 0x88, 0xe4, 0x44, 0x93, 0x56, 0x3b, 0xd2, 0xfe, - 0x2f, 0x71, 0xa2, 0xad, 0x07, 0xd0, 0x48, 0x77, 0x96, 0xa6, 0xe8, 0x1a, 0x35, 0xc5, 0x7e, 0x17, - 0x07, 0x90, 0xbb, 0xf4, 0xa4, 0x44, 0xa3, 0x1b, 0x65, 0xa8, 0x5c, 0x19, 0xd8, 0x1e, 0x29, 0xaa, - 0xf3, 0xf4, 0xdb, 0xfa, 0x5d, 0x09, 0x2a, 0xb4, 0x30, 0xb6, 0x81, 0x19, 0x11, 0x4e, 0xf5, 0x0a, - 0x4a, 0x7b, 0xcc, 0x64, 0x04, 0x50, 0xee, 0xa5, 0x09, 0x81, 0x79, 0xb8, 0x8a, 0xd1, 0xe9, 0x09, - 0x47, 0xc9, 0xc8, 0xcc, 0x93, 0x7e, 0xe3, 0xfc, 0x23, 0xcc, 0x50, 0x1d, 0x30, 0x44, 0xb3, 0x5b, - 0x50, 0x95, 0x94, 0x56, 0x14, 0x33, 0x2f, 0x48, 0x36, 0x03, 0x41, 0xe5, 0x91, 0xb0, 0x47, 0x32, - 0xf0, 0x66, 0x14, 0x49, 0x75, 0x9e, 0x7e, 0x63, 0xa0, 0x53, 0x1e, 0x3d, 0x9a, 0x85, 0xfa, 0x58, - 0x6d, 0xe9, 0x40, 0x7f, 0x98, 0x30, 0x79, 0x26, 0xc7, 0x83, 0xf3, 0x91, 0x1f, 0x8e, 0xe3, 0x41, - 0xa8, 0x3a, 0x57, 0xb3, 0x90, 0x4c, 0x78, 0x3c, 0x95, 0x22, 0xd2, 0xb1, 0x9d, 0x13, 0x81, 0xc8, - 0x6b, 0x19, 0x72, 0xdf, 0xf0, 0x78, 0x2a, 0xcd, 0x32, 0x0d, 0xa1, 0x6f, 0x12, 0x34, 0x97, 0x69, - 0x88, 0xcd, 0xe4, 0x18, 0xa1, 0xc3, 0xe1, 0x01, 0x22, 0xdf, 0xca, 0x4e, 0x77, 0xcd, 0xe1, 0x46, - 0xa2, 0x57, 0x1b, 0x4f, 0x3d, 0xd5, 0xef, 0x76, 0xde, 0xd6, 0xae, 0x4c, 0xbe, 0xad, 0xb5, 0x6c, - 0x01, 0xe8, 0xd6, 0xd8, 0xfd, 0x85, 0x8e, 0x97, 0x12, 0x27, 0xda, 0xea, 0x43, 0x3d, 0x31, 0xf1, - 0x42, 0x18, 0xdc, 0x81, 0x5a, 0x7c, 0x62, 0x47, 0x6e, 0x30, 0xa1, 0x1d, 0x6a, 0xed, 0x5c, 0x4d, - 0x57, 0x34, 0xd4, 0x7c, 0xb4, 0x22, 0xc1, 0x58, 0x32, 0x09, 0xa9, 0xcb, 0x74, 0xb5, 0xa1, 0x34, - 0x75, 0x47, 0xa4, 0x67, 0x85, 0x23, 0x89, 0x9c, 0x89, 0xab, 0x83, 0x72, 0x85, 0x23, 0x89, 0xf6, - 0xf9, 0x72, 0xa4, 0x6b, 0xe6, 0x0a, 0x27, 0x7a, 0x2e, 0xec, 0x2a, 0x0b, 0x61, 0xe7, 0x25, 0xbe, - 0xf9, 0xbf, 0xcc, 0xf6, 0x9b, 0x02, 0xd4, 0x93, 0x42, 0x8f, 0xe5, 0xc6, 0x1d, 0x89, 0x40, 0xb9, - 0x63, 0x57, 0x44, 0x66, 0xe2, 0x1c, 0x87, 0xdd, 0x81, 0x8a, 0xad, 0x54, 0x94, 0x1c, 0xe2, 0x6f, - 0xe7, 0xbb, 0x84, 0xad, 0x5d, 0x94, 0xf4, 0x02, 0x15, 0xcd, 0xb8, 0x46, 0xad, 0x7e, 0x0c, 0x90, - 0x31, 0xd1, 0xd6, 0x53, 0x31, 0x33, 0x5a, 0x91, 0x64, 0xd7, 0xa0, 0xf2, 0xcc, 0xf6, 0xa6, 0x49, - 0x46, 0xea, 0x8f, 0x7b, 0xc5, 0x8f, 0x0b, 0xd6, 0x9f, 0x8b, 0x50, 0x33, 0x5d, 0x03, 0xbb, 0x0d, - 0x35, 0xea, 0x1a, 0x8c, 0x45, 0x97, 0xa7, 0x5f, 0x02, 0x61, 0xdb, 0x69, 0x3b, 0x94, 0xb3, 0xd1, - 0xa8, 0xd2, 0x6d, 0x91, 0xb1, 0x31, 0x6b, 0x8e, 0x4a, 0x23, 0x31, 0x36, 0x7d, 0x4f, 0x8b, 0xba, - 0x0c, 0x31, 0x76, 0x03, 0x17, 0xfd, 0xc3, 0x51, 0xc4, 0x6e, 0x27, 0xab, 0x2e, 0x93, 0xc6, 0xb7, - 0xf2, 0x1a, 0x2f, 0x2e, 0xba, 0x0f, 0xcd, 0xdc, 0x34, 0x97, 0xac, 0xfa, 0xfd, 0xfc, 0xaa, 0xcd, - 0x94, 0xa4, 0x4e, 0x37, 0x6d, 0x99, 0x17, 0xfe, 0x0b, 0xff, 0x7d, 0x04, 0x90, 0xa9, 0x7c, 0xf5, - 0xe3, 0xcb, 0xfa, 0x53, 0x09, 0x60, 0x10, 0x62, 0x0d, 0x1c, 0xd9, 0x54, 0xb5, 0x97, 0xdd, 0x49, - 0x20, 0x23, 0xf1, 0x94, 0xd2, 0x9c, 0xc6, 0xd7, 0x79, 0x53, 0xf3, 0x28, 0x63, 0xd8, 0x2e, 0x34, - 0x47, 0x22, 0x76, 0x22, 0x97, 0x02, 0xca, 0x38, 0xfd, 0x06, 0xae, 0x29, 0xd3, 0xb3, 0xd5, 0xcd, - 0x10, 0xda, 0x57, 0xf9, 0x31, 0x6c, 0x07, 0x96, 0xc5, 0x79, 0x28, 0x23, 0x65, 0x66, 0xd1, 0xcd, - 0xe5, 0x15, 0xdd, 0xa6, 0x22, 0x9f, 0x66, 0xe2, 0x4d, 0x91, 0x7d, 0x30, 0x1b, 0xca, 0x8e, 0x1d, - 0xc6, 0xa6, 0xa4, 0x77, 0x16, 0xe6, 0xdb, 0xb7, 0x43, 0xed, 0xb4, 0xbd, 0x0f, 0x71, 0xad, 0xbf, - 0xfa, 0xdb, 0x8d, 0x5b, 0xb9, 0x3e, 0xc8, 0x97, 0xc7, 0xb3, 0x6d, 0x8a, 0x97, 0x53, 0x57, 0x6d, - 0x4f, 0x95, 0xeb, 0x6d, 0xdb, 0xa1, 0x8b, 0xea, 0x70, 0x60, 0xbf, 0xcb, 0x49, 0x35, 0xfb, 0x18, - 0x5a, 0x61, 0x24, 0x27, 0x91, 0x88, 0xe3, 0xa7, 0x54, 0x15, 0x4d, 0xb7, 0xfa, 0x86, 0xa9, 0xde, - 0x24, 0xf9, 0x14, 0x05, 0x7c, 0x25, 0xcc, 0x7f, 0xae, 0xfe, 0x04, 0xda, 0x8b, 0x2b, 0x7e, 0x9d, - 0xdd, 0x5b, 0xbd, 0x0b, 0x8d, 0x74, 0x05, 0x2f, 0x1b, 0x58, 0xcf, 0x6f, 0xfb, 0x1f, 0x0b, 0x50, - 0xd5, 0xf9, 0xc8, 0xee, 0x42, 0xc3, 0x93, 0x8e, 0x8d, 0x06, 0x24, 0x37, 0x83, 0x77, 0xb2, 0x74, - 0xdd, 0xfa, 0x3c, 0x91, 0xe9, 0xfd, 0xc8, 0xb0, 0x18, 0x9e, 0x6e, 0x30, 0x96, 0x49, 0xfe, 0xb4, - 0xb2, 0x41, 0xfd, 0x60, 0x2c, 0xb9, 0x16, 0xae, 0x3e, 0x80, 0xd6, 0xbc, 0x8a, 0x4b, 0xec, 0x7c, - 0x6f, 0x3e, 0xd0, 0xa9, 0x1a, 0xa4, 0x83, 0xf2, 0x66, 0xdf, 0x85, 0x46, 0xca, 0x67, 0x9b, 0x17, - 0x0d, 0x5f, 0xce, 0x8f, 0xcc, 0xd9, 0x6a, 0xfd, 0xba, 0x00, 0x90, 0xd9, 0x86, 0xe7, 0x1c, 0xde, - 0x41, 0x82, 0xac, 0x7b, 0x48, 0xbf, 0xa9, 0xf8, 0xda, 0xca, 0x26, 0x5b, 0x96, 0x39, 0xd1, 0x6c, - 0x0b, 0x60, 0x94, 0xe6, 0xfa, 0x0b, 0x4e, 0x80, 0x1c, 0x02, 0xf5, 0x7b, 0x76, 0x30, 0x99, 0xda, - 0x13, 0x61, 0x5a, 0xbc, 0xf4, 0xdb, 0x1a, 0x40, 0x3d, 0xb1, 0x90, 0xad, 0x43, 0x33, 0x36, 0x56, - 0x61, 0x1b, 0x8d, 0xa6, 0x54, 0x78, 0x9e, 0x85, 0xed, 0x70, 0x64, 0x07, 0x13, 0x31, 0xd7, 0x0e, - 0x73, 0xe4, 0x70, 0x23, 0xb0, 0xbe, 0x80, 0x0a, 0x31, 0x30, 0x7b, 0x63, 0x65, 0x47, 0xca, 0x74, - 0xd6, 0xba, 0x79, 0x94, 0x31, 0x99, 0xb4, 0x57, 0xc6, 0xf8, 0xe6, 0x1a, 0xc0, 0xde, 0xc7, 0x16, - 0x75, 0x64, 0xdc, 0x7d, 0x19, 0x0e, 0xc5, 0xd6, 0x27, 0x50, 0x4f, 0xd8, 0xe8, 0x15, 0xcf, 0x0d, - 0x84, 0x31, 0x91, 0x68, 0xbc, 0x91, 0x38, 0x27, 0x76, 0x64, 0x3b, 0x4a, 0xe8, 0x1e, 0xa6, 0xc2, - 0x33, 0x86, 0xf5, 0x1e, 0x34, 0x73, 0x49, 0x89, 0xb1, 0xf8, 0x84, 0xf6, 0x58, 0x1f, 0x0d, 0xfa, - 0xc3, 0xfa, 0x14, 0x56, 0xe6, 0x12, 0x04, 0x2b, 0x99, 0x3b, 0x4a, 0x2a, 0x99, 0xae, 0x52, 0x17, - 0x5a, 0x31, 0x06, 0xe5, 0x33, 0x61, 0x9f, 0x9a, 0x36, 0x8c, 0x68, 0xeb, 0x0f, 0x78, 0xf1, 0x4a, - 0xda, 0xe3, 0x1f, 0x02, 0x9c, 0x28, 0x15, 0x3e, 0xa5, 0x7e, 0xd9, 0x28, 0x6b, 0x20, 0x87, 0x10, - 0xec, 0x06, 0x34, 0xf1, 0x23, 0x36, 0x72, 0xad, 0x9a, 0x46, 0xc4, 0x1a, 0xf0, 0x03, 0x68, 0x8c, - 0xd3, 0xe1, 0x25, 0x13, 0x1f, 0xc9, 0xe8, 0x77, 0xa0, 0x1e, 0x48, 0x23, 0xd3, 0x7b, 0x5b, 0x0b, - 0x64, 0x3a, 0xce, 0xf6, 0x3c, 0x23, 0xab, 0xe8, 0x71, 0xb6, 0xe7, 0x91, 0xd0, 0xba, 0x05, 0x6f, - 0x5c, 0xb8, 0x42, 0xb2, 0xb7, 0xa0, 0x3a, 0x76, 0x3d, 0x45, 0x15, 0x0b, 0xaf, 0x0b, 0xe6, 0xcb, - 0xfa, 0x57, 0x01, 0x20, 0x8b, 0x2d, 0x4c, 0x19, 0x2c, 0x3d, 0x88, 0x59, 0xd6, 0xa5, 0xc6, 0x83, - 0xba, 0x6f, 0x0e, 0x31, 0x13, 0x19, 0xd7, 0xe7, 0xe3, 0x71, 0x2b, 0x39, 0xe3, 0xf4, 0xf1, 0xb6, - 0x63, 0x8e, 0xb7, 0xd7, 0xb9, 0xe6, 0xa5, 0x33, 0x50, 0x17, 0x96, 0xbf, 0xf5, 0x43, 0x96, 0xeb, - 0xdc, 0x48, 0x56, 0x1f, 0xc0, 0xca, 0xdc, 0x94, 0xaf, 0x58, 0xd0, 0xb2, 0xc3, 0x38, 0x9f, 0xe8, - 0x3b, 0x50, 0xd5, 0xcf, 0x05, 0x6c, 0x03, 0x6a, 0xb6, 0xa3, 0x73, 0x3c, 0x77, 0xce, 0xa0, 0x70, - 0x97, 0xd8, 0x3c, 0x11, 0x5b, 0x7f, 0x29, 0x02, 0x64, 0xfc, 0xd7, 0x68, 0xc5, 0xef, 0x41, 0x2b, - 0x16, 0x8e, 0x0c, 0x46, 0x76, 0x34, 0x23, 0xa9, 0xb9, 0xcf, 0x5e, 0x36, 0x64, 0x01, 0x99, 0x6b, - 0xcb, 0x4b, 0x2f, 0x6f, 0xcb, 0x37, 0xa0, 0xec, 0xc8, 0x70, 0x66, 0xea, 0x16, 0x9b, 0x5f, 0xc8, - 0xbe, 0x0c, 0x67, 0x07, 0x4b, 0x9c, 0x10, 0x6c, 0x0b, 0xaa, 0xfe, 0x29, 0x3d, 0xa0, 0xe8, 0x8b, - 0xe0, 0xb5, 0x79, 0xec, 0xc3, 0x53, 0xa4, 0x0f, 0x96, 0xb8, 0x41, 0xb1, 0x5b, 0x50, 0xf1, 0x4f, - 0x47, 0x6e, 0x64, 0x2a, 0xcf, 0xd5, 0x45, 0x78, 0xd7, 0x8d, 0xe8, 0xbd, 0x04, 0x31, 0xcc, 0x82, - 0x62, 0xe4, 0x9b, 0xd7, 0x92, 0xf6, 0x82, 0x37, 0xfd, 0x83, 0x25, 0x5e, 0x8c, 0xfc, 0xbd, 0x3a, - 0x54, 0xb5, 0x5f, 0xad, 0x7f, 0x96, 0xa0, 0x35, 0x6f, 0x25, 0xee, 0x6c, 0x1c, 0x39, 0xc9, 0xce, - 0xc6, 0x91, 0x93, 0xde, 0x58, 0x8a, 0xb9, 0x1b, 0x8b, 0x05, 0x15, 0x79, 0x16, 0x88, 0x28, 0xff, - 0x52, 0xb4, 0x7f, 0x22, 0xcf, 0x02, 0xec, 0x9a, 0xb5, 0x68, 0xae, 0x09, 0xad, 0x98, 0x26, 0xf4, - 0x7d, 0x58, 0x19, 0x4b, 0xcf, 0x93, 0x67, 0xc3, 0x99, 0xef, 0xb9, 0xc1, 0xa9, 0xe9, 0x44, 0xe7, - 0x99, 0x6c, 0x03, 0xae, 0x8c, 0xdc, 0x08, 0xcd, 0xd9, 0x97, 0x81, 0x12, 0x01, 0xdd, 0x83, 0x11, - 0xb7, 0xc8, 0x66, 0x9f, 0xc1, 0xba, 0xad, 0x94, 0xf0, 0x43, 0xf5, 0x38, 0x08, 0x6d, 0xe7, 0xb4, - 0x2b, 0x1d, 0xca, 0x42, 0x3f, 0xb4, 0x95, 0x7b, 0xec, 0x7a, 0xae, 0x9a, 0x91, 0x33, 0xea, 0xfc, - 0xa5, 0x38, 0xf6, 0x01, 0xb4, 0x9c, 0x48, 0xd8, 0x4a, 0x74, 0x45, 0xac, 0x8e, 0x6c, 0x75, 0xd2, - 0xa9, 0xd3, 0xc8, 0x05, 0x2e, 0xae, 0xc1, 0x46, 0x6b, 0xbf, 0x70, 0xbd, 0x91, 0x83, 0x77, 0xcf, - 0x86, 0x5e, 0xc3, 0x1c, 0x93, 0x6d, 0x01, 0x23, 0x46, 0xcf, 0x0f, 0xd5, 0x2c, 0x85, 0x02, 0x41, - 0x2f, 0x91, 0xe0, 0x81, 0xab, 0x5c, 0x5f, 0xc4, 0xca, 0xf6, 0x43, 0xba, 0x56, 0x97, 0x78, 0xc6, - 0x60, 0x37, 0xa1, 0xed, 0x06, 0x8e, 0x37, 0x1d, 0x89, 0xa7, 0x21, 0x2e, 0x24, 0x0a, 0xe2, 0xce, - 0x32, 0x9d, 0x2a, 0x57, 0x0c, 0xff, 0xc8, 0xb0, 0x11, 0x2a, 0xce, 0x17, 0xa0, 0x2b, 0x1a, 0x6a, - 0xf8, 0x09, 0xd4, 0xfa, 0xb2, 0x00, 0xed, 0xc5, 0xc0, 0xc3, 0x6d, 0x0b, 0x71, 0xf1, 0xe6, 0xe6, - 0x8d, 0x74, 0xba, 0x95, 0xc5, 0xdc, 0x56, 0x26, 0xb5, 0xb4, 0x94, 0xab, 0xa5, 0x69, 0x58, 0x94, - 0x5f, 0x1c, 0x16, 0x73, 0x0b, 0xad, 0x2c, 0x2c, 0xd4, 0xfa, 0x7d, 0x01, 0xae, 0x2c, 0x04, 0xf7, - 0x2b, 0x5b, 0xb4, 0x0e, 0x4d, 0xdf, 0x3e, 0x15, 0xfa, 0xdd, 0x22, 0x36, 0x25, 0x24, 0xcf, 0xfa, - 0x1f, 0xd8, 0x17, 0xc0, 0x72, 0x3e, 0xa3, 0x2e, 0xb5, 0x2d, 0x09, 0x90, 0x43, 0xa9, 0xee, 0xcb, - 0xa9, 0xa9, 0xc5, 0x49, 0x80, 0x24, 0xcc, 0x8b, 0x61, 0x54, 0xba, 0x24, 0x8c, 0xac, 0x43, 0xa8, - 0x27, 0x06, 0xb2, 0x1b, 0xe6, 0x61, 0xa9, 0x90, 0xbd, 0x97, 0x3e, 0x8e, 0x45, 0x84, 0xb6, 0xeb, - 0x57, 0xa6, 0x77, 0xa1, 0xa2, 0x7b, 0xd4, 0xe2, 0x45, 0x84, 0x96, 0x58, 0x43, 0xa8, 0x19, 0x0e, - 0xdb, 0x84, 0xea, 0xf1, 0x2c, 0x7d, 0x64, 0x31, 0xc7, 0x05, 0x7e, 0x8f, 0x0c, 0x02, 0xcf, 0x20, - 0x8d, 0x60, 0xd7, 0xa0, 0x7c, 0x3c, 0xeb, 0x77, 0xf5, 0xad, 0x13, 0x4f, 0x32, 0xfc, 0xda, 0xab, - 0x6a, 0x83, 0xac, 0xcf, 0x61, 0x39, 0x3f, 0x2e, 0x2d, 0xec, 0x85, 0x5c, 0x61, 0x4f, 0x8f, 0xec, - 0xe2, 0xcb, 0xae, 0x1f, 0x1f, 0x01, 0xd0, 0x33, 0xf0, 0xeb, 0x5e, 0x5b, 0x7e, 0x0c, 0x35, 0xf3, - 0x7c, 0xcc, 0x3e, 0x58, 0x78, 0x0e, 0x6f, 0xa5, 0x6f, 0xcb, 0x73, 0x6f, 0xe2, 0xd6, 0x3d, 0x6c, - 0x60, 0xcf, 0x44, 0xd4, 0x75, 0xc7, 0xe3, 0xd7, 0x9d, 0xee, 0x1e, 0xb4, 0x1e, 0x87, 0xe1, 0x7f, - 0x36, 0xf6, 0xe7, 0x50, 0xd5, 0xaf, 0xd8, 0x38, 0xc6, 0x43, 0x0b, 0xcc, 0x1e, 0x30, 0xdd, 0xe4, - 0xe6, 0x4d, 0xe2, 0x1a, 0x80, 0xc8, 0x29, 0xce, 0x67, 0x36, 0x97, 0x90, 0xf3, 0x06, 0x70, 0x0d, - 0xd8, 0xdc, 0x80, 0x9a, 0x79, 0x30, 0x65, 0x0d, 0xa8, 0x3c, 0x3e, 0x1c, 0xf6, 0x1e, 0xb5, 0x97, - 0x58, 0x1d, 0xca, 0x07, 0x83, 0xe1, 0xa3, 0x76, 0x01, 0xa9, 0xc3, 0xc1, 0x61, 0xaf, 0x5d, 0xdc, - 0xbc, 0x09, 0xcb, 0xf9, 0x27, 0x53, 0xd6, 0x84, 0xda, 0x70, 0xf7, 0xb0, 0xbb, 0x37, 0xf8, 0x59, - 0x7b, 0x89, 0x2d, 0x43, 0xbd, 0x7f, 0x38, 0xec, 0xed, 0x3f, 0xe6, 0xbd, 0x76, 0x61, 0xf3, 0xa7, - 0xd0, 0x48, 0x5f, 0x91, 0x50, 0xc3, 0x5e, 0xff, 0xb0, 0xdb, 0x5e, 0x62, 0x00, 0xd5, 0x61, 0x6f, - 0x9f, 0xf7, 0x50, 0x6f, 0x0d, 0x4a, 0xc3, 0xe1, 0x41, 0xbb, 0x88, 0xb3, 0xee, 0xef, 0xee, 0x1f, - 0xf4, 0xda, 0x25, 0x24, 0x1f, 0x3d, 0x3c, 0xba, 0x3f, 0x6c, 0x97, 0x37, 0x3f, 0x82, 0x2b, 0x0b, - 0xef, 0x2b, 0x34, 0xfa, 0x60, 0x97, 0xf7, 0x50, 0x53, 0x13, 0x6a, 0x47, 0xbc, 0xff, 0x64, 0xf7, - 0x51, 0xaf, 0x5d, 0x40, 0xc1, 0xe7, 0x83, 0xfd, 0x07, 0xbd, 0x6e, 0xbb, 0xb8, 0x77, 0xfd, 0xab, - 0xe7, 0x6b, 0x85, 0x6f, 0x9e, 0xaf, 0x15, 0xbe, 0x7d, 0xbe, 0x56, 0xf8, 0xfb, 0xf3, 0xb5, 0xc2, - 0x97, 0xdf, 0xaf, 0x2d, 0x7d, 0xf3, 0xfd, 0xda, 0xd2, 0xb7, 0xdf, 0xaf, 0x2d, 0x1d, 0x57, 0xe9, - 0x7f, 0x90, 0x0f, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x3c, 0x38, 0x7a, 0x47, 0x19, 0x00, - 0x00, + // 2627 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcf, 0x6f, 0x5b, 0xc7, + 0xf1, 0x17, 0x7f, 0x93, 0x43, 0x8a, 0x66, 0xd6, 0x4e, 0xc2, 0xe8, 0xeb, 0xaf, 0xac, 0xbc, 0xe4, + 0x1b, 0xc8, 0xb2, 0x2d, 0x21, 0x0a, 0x10, 0xe7, 0x6b, 0x04, 0x45, 0x25, 0x91, 0x8a, 0x18, 0xdb, + 0xa2, 0xb0, 0xb4, 0x9c, 0x1e, 0x0a, 0x18, 0x4f, 0x8f, 0x4b, 0xea, 0x41, 0x8f, 0xef, 0x3d, 0xec, + 0x5b, 0x5a, 0x62, 0x0f, 0x3d, 0xf4, 0xd4, 0x63, 0x80, 0x02, 0xbd, 0x15, 0xfd, 0x27, 0x7a, 0x6c, + 0xef, 0x01, 0x72, 0x09, 0xd0, 0x1e, 0x82, 0x1e, 0xd2, 0xc2, 0xb9, 0xf4, 0x8f, 0x68, 0x81, 0x62, + 0x66, 0xf7, 0xfd, 0x20, 0x25, 0xc3, 0x71, 0x5b, 0xf4, 0xc4, 0xd9, 0x99, 0xcf, 0xce, 0xce, 0xcc, + 0xce, 0xec, 0xce, 0x5b, 0x42, 0x2d, 0x08, 0xa3, 0xcd, 0x50, 0x06, 0x2a, 0x60, 0xf9, 0xf0, 0x64, + 0xe5, 0xde, 0xd8, 0x55, 0xa7, 0xd3, 0x93, 0x4d, 0x27, 0x98, 0x6c, 0x8d, 0x83, 0x71, 0xb0, 0x45, + 0xa2, 0x93, 0xe9, 0x88, 0x46, 0x34, 0x20, 0x4a, 0x4f, 0xb1, 0xfe, 0x96, 0x87, 0x7c, 0x3f, 0x64, + 0xef, 0x42, 0xd9, 0xf5, 0xc3, 0xa9, 0x8a, 0xda, 0xb9, 0xb5, 0xc2, 0x7a, 0x7d, 0xbb, 0xb6, 0x19, + 0x9e, 0x6c, 0xf6, 0x90, 0xc3, 0x8d, 0x80, 0xad, 0x41, 0x51, 0x5c, 0x08, 0xa7, 0x9d, 0x5f, 0xcb, + 0xad, 0xd7, 0xb7, 0x01, 0x01, 0xdd, 0x0b, 0xe1, 0xf4, 0xc3, 0x83, 0x25, 0x4e, 0x12, 0xf6, 0x01, + 0x94, 0xa3, 0x60, 0x2a, 0x1d, 0xd1, 0x2e, 0x10, 0xa6, 0x81, 0x98, 0x01, 0x71, 0x08, 0x65, 0xa4, + 0xa8, 0x69, 0xe4, 0x7a, 0xa2, 0x5d, 0x4c, 0x35, 0xed, 0xbb, 0x9e, 0xc6, 0x90, 0x84, 0xbd, 0x07, + 0xa5, 0x93, 0xa9, 0xeb, 0x0d, 0xdb, 0x25, 0x82, 0xd4, 0x11, 0xb2, 0x8b, 0x0c, 0xc2, 0x68, 0x19, + 0x82, 0x26, 0x42, 0x8e, 0x45, 0xbb, 0x9c, 0x82, 0x1e, 0x23, 0x43, 0x83, 0x48, 0x86, 0x6b, 0x0d, + 0xdd, 0xd1, 0xa8, 0x5d, 0x49, 0xd7, 0xea, 0xb8, 0xa3, 0x91, 0x5e, 0x0b, 0x25, 0x6c, 0x1d, 0xaa, + 0xa1, 0x67, 0xab, 0x51, 0x20, 0x27, 0x6d, 0x48, 0xed, 0x3e, 0x32, 0x3c, 0x9e, 0x48, 0xd9, 0x7d, + 0xa8, 0x3b, 0x81, 0x1f, 0x29, 0x69, 0xbb, 0xbe, 0x8a, 0xda, 0x75, 0x02, 0xbf, 0x89, 0xe0, 0x2f, + 0x02, 0x79, 0x26, 0xe4, 0x5e, 0x2a, 0xe4, 0x59, 0xe4, 0x6e, 0x11, 0xf2, 0x41, 0x68, 0xfd, 0x3a, + 0x07, 0xd5, 0x58, 0x2b, 0xb3, 0xa0, 0xb1, 0x23, 0x9d, 0x53, 0x57, 0x09, 0x47, 0x4d, 0xa5, 0x68, + 0xe7, 0xd6, 0x72, 0xeb, 0x35, 0x3e, 0xc7, 0x63, 0x4d, 0xc8, 0xf7, 0x07, 0x14, 0xef, 0x1a, 0xcf, + 0xf7, 0x07, 0xac, 0x0d, 0x95, 0xa7, 0xb6, 0x74, 0x6d, 0x5f, 0x51, 0x80, 0x6b, 0x3c, 0x1e, 0xb2, + 0x9b, 0x50, 0xeb, 0x0f, 0x9e, 0x0a, 0x19, 0xb9, 0x81, 0x4f, 0x61, 0xad, 0xf1, 0x94, 0xc1, 0x56, + 0x01, 0xfa, 0x83, 0x7d, 0x61, 0xa3, 0xd2, 0xa8, 0x5d, 0x5a, 0x2b, 0xac, 0xd7, 0x78, 0x86, 0x63, + 0xfd, 0x1c, 0x4a, 0xb4, 0xd5, 0xec, 0x73, 0x28, 0x0f, 0xdd, 0xb1, 0x88, 0x94, 0x36, 0x67, 0x77, + 0xfb, 0xab, 0xef, 0x6e, 0x2d, 0xfd, 0xf9, 0xbb, 0x5b, 0x1b, 0x99, 0x9c, 0x0a, 0x42, 0xe1, 0x3b, + 0x81, 0xaf, 0x6c, 0xd7, 0x17, 0x32, 0xda, 0x1a, 0x07, 0xf7, 0xf4, 0x94, 0xcd, 0x0e, 0xfd, 0x70, + 0xa3, 0x81, 0xdd, 0x86, 0x92, 0xeb, 0x0f, 0xc5, 0x05, 0xd9, 0x5f, 0xd8, 0xbd, 0x6e, 0x54, 0xd5, + 0xfb, 0x53, 0x15, 0x4e, 0x55, 0x0f, 0x45, 0x5c, 0x23, 0xac, 0xaf, 0x73, 0x50, 0xd6, 0xa9, 0xc4, + 0x6e, 0x42, 0x71, 0x22, 0x94, 0x4d, 0xeb, 0xd7, 0xb7, 0xab, 0x7a, 0x4b, 0x95, 0xcd, 0x89, 0x8b, + 0x59, 0x3a, 0x09, 0xa6, 0x18, 0xfb, 0x7c, 0x9a, 0xa5, 0x8f, 0x91, 0xc3, 0x8d, 0x80, 0xfd, 0x1f, + 0x54, 0x7c, 0xa1, 0xce, 0x03, 0x79, 0x46, 0x31, 0x6a, 0xea, 0xb4, 0x38, 0x14, 0xea, 0x71, 0x30, + 0x14, 0x3c, 0x96, 0xb1, 0xbb, 0x50, 0x8d, 0x84, 0x33, 0x95, 0xae, 0x9a, 0x51, 0xbc, 0x9a, 0xdb, + 0x2d, 0x4a, 0x56, 0xc3, 0x23, 0x70, 0x82, 0x60, 0x77, 0xa0, 0x16, 0x09, 0x47, 0x0a, 0x25, 0xfc, + 0xe7, 0x14, 0xbf, 0xfa, 0xf6, 0xb2, 0x81, 0x4b, 0xa1, 0xba, 0xfe, 0x73, 0x9e, 0xca, 0xad, 0xaf, + 0xf3, 0x50, 0x44, 0x9b, 0x19, 0x83, 0xa2, 0x2d, 0xc7, 0xba, 0xa2, 0x6a, 0x9c, 0x68, 0xd6, 0x82, + 0x02, 0xea, 0xc8, 0x13, 0x0b, 0x49, 0xe4, 0x38, 0xe7, 0x43, 0xb3, 0xa1, 0x48, 0xe2, 0xbc, 0x69, + 0x24, 0xa4, 0xd9, 0x47, 0xa2, 0xd9, 0x6d, 0xa8, 0x85, 0x32, 0xb8, 0x98, 0x3d, 0xd3, 0x16, 0xa4, + 0x59, 0x8a, 0x4c, 0x34, 0xa0, 0x1a, 0x1a, 0x8a, 0x6d, 0x00, 0x88, 0x0b, 0x25, 0xed, 0x83, 0x20, + 0x52, 0x51, 0xbb, 0x4c, 0xd6, 0x52, 0xde, 0x23, 0xa3, 0x77, 0xc4, 0x33, 0x52, 0xb6, 0x02, 0xd5, + 0xd3, 0x20, 0x52, 0xbe, 0x3d, 0x11, 0x54, 0x21, 0x35, 0x9e, 0x8c, 0x99, 0x05, 0xe5, 0xa9, 0xe7, + 0x4e, 0x5c, 0xd5, 0xae, 0xa5, 0x3a, 0x8e, 0x89, 0xc3, 0x8d, 0x04, 0xb3, 0xd8, 0x19, 0xcb, 0x60, + 0x1a, 0x1e, 0xd9, 0x52, 0xf8, 0x8a, 0xea, 0xa7, 0xc6, 0xe7, 0x78, 0xec, 0x53, 0x78, 0x47, 0x8a, + 0x49, 0xf0, 0x5c, 0xd0, 0x46, 0x0d, 0xd4, 0xf4, 0x24, 0xe2, 0x18, 0xd8, 0xc8, 0x7d, 0x2e, 0xa8, + 0x86, 0xaa, 0xfc, 0xe5, 0x00, 0xeb, 0x2e, 0x94, 0xb5, 0xdd, 0x18, 0x16, 0xa4, 0x4c, 0xa5, 0x10, + 0x8d, 0x15, 0xd2, 0x3b, 0x8a, 0x2b, 0xa4, 0x77, 0x64, 0x75, 0xa0, 0xac, 0x2d, 0x44, 0xf4, 0x21, + 0x7a, 0x65, 0xd0, 0x48, 0x23, 0x6f, 0x10, 0x8c, 0x94, 0xce, 0x48, 0x4e, 0x34, 0x69, 0xb5, 0xa5, + 0x8e, 0x7f, 0x81, 0x13, 0x6d, 0x3d, 0x84, 0x5a, 0xb2, 0xb3, 0xb4, 0x44, 0xc7, 0xa8, 0xc9, 0xf7, + 0x3a, 0x38, 0x81, 0xc2, 0xa5, 0x17, 0x25, 0x1a, 0xc3, 0x18, 0x84, 0xca, 0x0d, 0x7c, 0xdb, 0x23, + 0x45, 0x55, 0x9e, 0x8c, 0xad, 0x3f, 0x16, 0xa0, 0x44, 0x8e, 0xb1, 0x75, 0xac, 0x88, 0x70, 0xaa, + 0x3d, 0x28, 0xec, 0x32, 0x53, 0x11, 0x40, 0xb5, 0x97, 0x14, 0x04, 0xd6, 0xe1, 0x0a, 0x66, 0xa7, + 0x27, 0x1c, 0x15, 0x48, 0xb3, 0x4e, 0x32, 0xc6, 0xf5, 0x87, 0x58, 0xa1, 0x3a, 0x61, 0x88, 0x66, + 0x77, 0xa0, 0x1c, 0x50, 0x59, 0x51, 0xce, 0xbc, 0xa4, 0xd8, 0x0c, 0x04, 0x95, 0x4b, 0x61, 0x0f, + 0x03, 0xdf, 0x9b, 0x51, 0x26, 0x55, 0x79, 0x32, 0xc6, 0x44, 0xa7, 0x3a, 0x7a, 0x32, 0x0b, 0xf5, + 0xb1, 0xda, 0xd4, 0x89, 0xfe, 0x38, 0x66, 0xf2, 0x54, 0x8e, 0x07, 0xe7, 0x93, 0x49, 0x38, 0x8a, + 0xfa, 0xa1, 0x6a, 0x5f, 0x4f, 0x53, 0x32, 0xe6, 0xf1, 0x44, 0x8a, 0x48, 0xc7, 0x76, 0x4e, 0x05, + 0x22, 0x6f, 0xa4, 0xc8, 0x3d, 0xc3, 0xe3, 0x89, 0x34, 0xad, 0x34, 0x84, 0xbe, 0x49, 0xd0, 0x4c, + 0xa5, 0x21, 0x36, 0x95, 0x63, 0x86, 0x0e, 0x06, 0x07, 0x88, 0x7c, 0x2b, 0x3d, 0xdd, 0x35, 0x87, + 0x1b, 0x89, 0xf6, 0x36, 0x9a, 0x7a, 0xaa, 0xd7, 0x69, 0xbf, 0xad, 0x43, 0x19, 0x8f, 0xd9, 0xff, + 0x43, 0x03, 0x4f, 0x32, 0xe1, 0x2b, 0xb2, 0xa4, 0xdd, 0x26, 0x87, 0xdf, 0x4c, 0x1c, 0xde, 0xcb, + 0x08, 0xf9, 0x1c, 0xd4, 0x5a, 0x4d, 0x7d, 0xc7, 0x1d, 0x89, 0xdc, 0x9f, 0xe9, 0x54, 0x2b, 0x70, + 0xa2, 0xad, 0x1e, 0x54, 0x63, 0xef, 0x2e, 0x65, 0xd0, 0x3d, 0xa8, 0x44, 0xa7, 0xb6, 0x74, 0xfd, + 0x31, 0x6d, 0x6e, 0x73, 0xfb, 0x7a, 0x12, 0x8c, 0x81, 0xe6, 0xa3, 0x03, 0x31, 0xc6, 0x0a, 0xe2, + 0x6c, 0xbc, 0x4a, 0x57, 0x0b, 0x0a, 0x53, 0x77, 0x48, 0x7a, 0x96, 0x39, 0x92, 0xc8, 0x19, 0xbb, + 0x3a, 0x9f, 0x97, 0x39, 0x92, 0x68, 0xdf, 0x24, 0x18, 0xea, 0xeb, 0x76, 0x99, 0x13, 0x3d, 0x97, + 0xb1, 0xa5, 0x85, 0x8c, 0xf5, 0xe2, 0xb0, 0xfe, 0x57, 0x56, 0xfb, 0x55, 0x0e, 0xaa, 0x71, 0x8f, + 0x80, 0x37, 0x95, 0x3b, 0x14, 0xbe, 0x72, 0x47, 0xae, 0x90, 0x66, 0xe1, 0x0c, 0x87, 0xdd, 0x83, + 0x92, 0xad, 0x94, 0x8c, 0xcf, 0xff, 0xb7, 0xb3, 0x0d, 0xc6, 0xe6, 0x0e, 0x4a, 0xba, 0xbe, 0x92, + 0x33, 0xae, 0x51, 0x2b, 0x9f, 0x00, 0xa4, 0x4c, 0xb4, 0xf5, 0x4c, 0xcc, 0x8c, 0x56, 0x24, 0xd9, + 0x0d, 0x28, 0x3d, 0xb7, 0xbd, 0x69, 0x5c, 0xcc, 0x7a, 0xf0, 0x20, 0xff, 0x49, 0xce, 0xfa, 0x43, + 0x1e, 0x2a, 0xa6, 0xe1, 0x60, 0x77, 0xa1, 0x42, 0x0d, 0x87, 0xb1, 0xe8, 0xea, 0xca, 0x8d, 0x21, + 0x6c, 0x2b, 0xe9, 0xa4, 0x32, 0x36, 0x1a, 0x55, 0xba, 0xa3, 0x32, 0x36, 0xa6, 0x7d, 0x55, 0x61, + 0x28, 0x46, 0xa6, 0x65, 0x6a, 0x52, 0x83, 0x22, 0x46, 0xae, 0xef, 0x62, 0x7c, 0x38, 0x8a, 0xd8, + 0xdd, 0xd8, 0xeb, 0x22, 0x69, 0x7c, 0x2b, 0xab, 0xf1, 0xb2, 0xd3, 0x3d, 0xa8, 0x67, 0x96, 0xb9, + 0xc2, 0xeb, 0xf7, 0xb3, 0x5e, 0x9b, 0x25, 0x49, 0x9d, 0xee, 0xf7, 0xd2, 0x28, 0xfc, 0x1b, 0xf1, + 0xfb, 0x18, 0x20, 0x55, 0xf9, 0xc3, 0x4f, 0x3e, 0xeb, 0xf7, 0x05, 0x80, 0x7e, 0x88, 0xd7, 0xe7, + 0xd0, 0xa6, 0x0b, 0xbf, 0xe1, 0x8e, 0xfd, 0x40, 0x8a, 0x67, 0x74, 0x42, 0xd0, 0xfc, 0x2a, 0xaf, + 0x6b, 0x1e, 0x55, 0x0c, 0xdb, 0x81, 0xfa, 0x50, 0x44, 0x8e, 0x74, 0x29, 0xa1, 0x4c, 0xd0, 0x6f, + 0xa1, 0x4f, 0xa9, 0x9e, 0xcd, 0x4e, 0x8a, 0xd0, 0xb1, 0xca, 0xce, 0x61, 0xdb, 0xd0, 0x10, 0x17, + 0x61, 0x20, 0x95, 0x59, 0x45, 0xf7, 0xa5, 0xd7, 0x74, 0x87, 0x8b, 0x7c, 0x7d, 0x02, 0xd4, 0x45, + 0x3a, 0x60, 0x36, 0x14, 0x1d, 0x3b, 0x8c, 0x4c, 0x37, 0xd0, 0x5e, 0x58, 0x6f, 0xcf, 0x0e, 0x75, + 0xd0, 0x76, 0x3f, 0x42, 0x5f, 0x7f, 0xf1, 0x97, 0x5b, 0x77, 0x32, 0x2d, 0xd4, 0x24, 0x38, 0x99, + 0x6d, 0x51, 0xbe, 0x9c, 0xb9, 0x6a, 0x6b, 0xaa, 0x5c, 0x6f, 0xcb, 0x0e, 0x5d, 0x54, 0x87, 0x13, + 0x7b, 0x1d, 0x4e, 0xaa, 0xd9, 0x27, 0xd0, 0x0c, 0x65, 0x30, 0x96, 0x22, 0x8a, 0x9e, 0xd1, 0x85, + 0x6a, 0x1a, 0xdd, 0x37, 0xcc, 0xc5, 0x4f, 0x92, 0xcf, 0x50, 0xc0, 0x97, 0xc3, 0xec, 0x70, 0xe5, + 0x47, 0xd0, 0x5a, 0xf4, 0xf8, 0x75, 0x76, 0x6f, 0xe5, 0x3e, 0xd4, 0x12, 0x0f, 0x5e, 0x35, 0xb1, + 0x9a, 0xdd, 0xf6, 0xdf, 0xe5, 0xa0, 0xac, 0xeb, 0x91, 0xdd, 0x87, 0x9a, 0x17, 0x38, 0x36, 0x1a, + 0x10, 0x7f, 0x54, 0xbc, 0x93, 0x96, 0xeb, 0xe6, 0xa3, 0x58, 0xa6, 0xf7, 0x23, 0xc5, 0x62, 0x7a, + 0xba, 0xfe, 0x28, 0x88, 0xeb, 0xa7, 0x99, 0x4e, 0xea, 0xf9, 0xa3, 0x80, 0x6b, 0xe1, 0xca, 0x43, + 0x68, 0xce, 0xab, 0xb8, 0xc2, 0xce, 0xf7, 0xe6, 0x13, 0x9d, 0x2e, 0x92, 0x64, 0x52, 0xd6, 0xec, + 0xfb, 0x50, 0x4b, 0xf8, 0x6c, 0xe3, 0xb2, 0xe1, 0x8d, 0xec, 0xcc, 0x8c, 0xad, 0xd6, 0x2f, 0x73, + 0x00, 0xa9, 0x6d, 0x78, 0xce, 0xe1, 0xe7, 0x8b, 0x9f, 0x36, 0x1e, 0xc9, 0x98, 0xee, 0x6d, 0x5b, + 0xd9, 0x64, 0x4b, 0x83, 0x13, 0xcd, 0x36, 0x01, 0x86, 0x49, 0xad, 0xbf, 0xe4, 0x04, 0xc8, 0x20, + 0x50, 0xbf, 0x67, 0xfb, 0xe3, 0xa9, 0x3d, 0x16, 0xa6, 0x3b, 0x4c, 0xc6, 0x56, 0x1f, 0xaa, 0xb1, + 0x85, 0x6c, 0x0d, 0xea, 0x91, 0xb1, 0x0a, 0x3b, 0x70, 0x34, 0xa5, 0xc4, 0xb3, 0x2c, 0xec, 0xa4, + 0xa5, 0xed, 0x8f, 0xc5, 0x5c, 0x27, 0xcd, 0x91, 0xc3, 0x8d, 0xc0, 0xfa, 0x02, 0x4a, 0xc4, 0xc0, + 0xea, 0x8d, 0x94, 0x2d, 0x95, 0x69, 0xca, 0x75, 0xdf, 0x19, 0x44, 0x64, 0xd2, 0x6e, 0x11, 0xf3, + 0x9b, 0x6b, 0x00, 0x7b, 0x1f, 0xbb, 0xdb, 0xa1, 0x09, 0xf7, 0x55, 0x38, 0x14, 0x5b, 0x9f, 0x42, + 0x35, 0x66, 0x63, 0x54, 0x3c, 0xd7, 0x17, 0xc6, 0x44, 0xa2, 0xf1, 0x63, 0xc6, 0x39, 0xb5, 0xa5, + 0xed, 0x28, 0xa1, 0xdb, 0x9f, 0x12, 0x4f, 0x19, 0xd6, 0x7b, 0x50, 0xcf, 0x14, 0x25, 0xe6, 0xe2, + 0x53, 0xda, 0x63, 0x7d, 0x34, 0xe8, 0x81, 0xf5, 0x19, 0x2c, 0xcf, 0x15, 0x08, 0xde, 0x64, 0xee, + 0x30, 0xbe, 0xc9, 0xf4, 0x2d, 0x75, 0xa9, 0x8b, 0x63, 0x50, 0x3c, 0x17, 0xf6, 0x99, 0xe9, 0xe0, + 0x88, 0xb6, 0x7e, 0x8b, 0xdf, 0x6c, 0x71, 0x67, 0xfd, 0xbf, 0x00, 0xa7, 0x4a, 0x85, 0xcf, 0xa8, + 0xd5, 0x36, 0xca, 0x6a, 0xc8, 0x21, 0x04, 0xbb, 0x05, 0x75, 0x1c, 0x44, 0x46, 0xae, 0x55, 0xd3, + 0x8c, 0x48, 0x03, 0xfe, 0x07, 0x6a, 0xa3, 0x64, 0x7a, 0xc1, 0xe4, 0x47, 0x3c, 0xfb, 0x1d, 0xa8, + 0xfa, 0x81, 0x91, 0xe9, 0xbd, 0xad, 0xf8, 0x41, 0x32, 0xcf, 0xf6, 0x3c, 0x23, 0x2b, 0xe9, 0x79, + 0xb6, 0xe7, 0x91, 0xd0, 0xba, 0x03, 0x6f, 0x5c, 0xfa, 0xfa, 0x64, 0x6f, 0x41, 0x79, 0xe4, 0x7a, + 0x8a, 0x6e, 0x2c, 0xfc, 0xd2, 0x30, 0x23, 0xeb, 0x1f, 0x39, 0x80, 0x34, 0xb7, 0xb0, 0x64, 0xf0, + 0xea, 0x41, 0x4c, 0x43, 0x5f, 0x35, 0x1e, 0x54, 0x27, 0xe6, 0x10, 0x33, 0x99, 0x71, 0x73, 0x3e, + 0x1f, 0x37, 0xe3, 0x33, 0x4e, 0x1f, 0x6f, 0xdb, 0xe6, 0x78, 0x7b, 0x9d, 0x2f, 0xc4, 0x64, 0x05, + 0x6a, 0xe0, 0xb2, 0x0f, 0x06, 0x90, 0xd6, 0x3a, 0x37, 0x92, 0x95, 0x87, 0xb0, 0x3c, 0xb7, 0xe4, + 0x0f, 0xbc, 0xd0, 0xd2, 0xc3, 0x38, 0x5b, 0xe8, 0xdb, 0x50, 0xd6, 0x2f, 0x0d, 0x6c, 0x1d, 0x2a, + 0xb6, 0xa3, 0x6b, 0x3c, 0x73, 0xce, 0xa0, 0x70, 0x87, 0xd8, 0x3c, 0x16, 0x5b, 0x7f, 0xca, 0x03, + 0xa4, 0xfc, 0xd7, 0xe8, 0xe2, 0x1f, 0x40, 0x33, 0x12, 0x4e, 0xe0, 0x0f, 0x6d, 0x39, 0x23, 0xa9, + 0xf9, 0x14, 0xbe, 0x6a, 0xca, 0x02, 0x32, 0xd3, 0xd1, 0x17, 0x5e, 0xdd, 0xd1, 0xaf, 0x43, 0xd1, + 0x09, 0xc2, 0x99, 0xb9, 0xb7, 0xd8, 0xbc, 0x23, 0x7b, 0x41, 0x38, 0x3b, 0x58, 0xe2, 0x84, 0x60, + 0x9b, 0x50, 0x9e, 0x9c, 0xd1, 0xdb, 0x8b, 0xfe, 0x86, 0xbc, 0x31, 0x8f, 0x7d, 0x7c, 0x86, 0xf4, + 0xc1, 0x12, 0x37, 0x28, 0x76, 0x07, 0x4a, 0x93, 0xb3, 0xa1, 0x2b, 0xcd, 0xcd, 0x73, 0x7d, 0x11, + 0xde, 0x71, 0x25, 0x3d, 0xb5, 0x20, 0x86, 0x59, 0x90, 0x97, 0x13, 0xf3, 0xd0, 0xd2, 0x5a, 0x88, + 0xe6, 0xe4, 0x60, 0x89, 0xe7, 0xe5, 0x64, 0xb7, 0x0a, 0x65, 0x1d, 0x57, 0xeb, 0xef, 0x05, 0x68, + 0xce, 0x5b, 0x89, 0x3b, 0x1b, 0x49, 0x27, 0xde, 0xd9, 0x48, 0x3a, 0xc9, 0xc7, 0x4e, 0x3e, 0xf3, + 0xb1, 0x63, 0x41, 0x29, 0x38, 0xf7, 0x85, 0xcc, 0x3e, 0x32, 0xed, 0x9d, 0x06, 0xe7, 0x3e, 0x76, + 0xcd, 0x5a, 0x34, 0xd7, 0x84, 0x96, 0x4c, 0x13, 0xfa, 0x3e, 0x2c, 0x8f, 0x02, 0xcf, 0x0b, 0xce, + 0x07, 0xb3, 0x89, 0xe7, 0xfa, 0x67, 0xa6, 0x13, 0x9d, 0x67, 0xb2, 0x75, 0xb8, 0x36, 0x74, 0x25, + 0x9a, 0x63, 0xba, 0xff, 0x88, 0x7c, 0xaf, 0xf2, 0x45, 0x36, 0xfb, 0x1c, 0xd6, 0x6c, 0xa5, 0xc4, + 0x24, 0x54, 0xc7, 0x7e, 0x68, 0x3b, 0x67, 0x9d, 0xc0, 0xa1, 0x2a, 0x9c, 0x84, 0xb6, 0x72, 0x4f, + 0x5c, 0xcf, 0x55, 0x33, 0x0a, 0x46, 0x95, 0xbf, 0x12, 0xc7, 0x3e, 0x80, 0xa6, 0x23, 0x85, 0xad, + 0x44, 0x47, 0x44, 0xea, 0xc8, 0x56, 0xa7, 0xed, 0x2a, 0xcd, 0x5c, 0xe0, 0xa2, 0x0f, 0x36, 0x5a, + 0xfb, 0x85, 0xeb, 0x0d, 0x1d, 0xfc, 0x6c, 0xad, 0x69, 0x1f, 0xe6, 0x98, 0x6c, 0x13, 0x18, 0x31, + 0xba, 0x93, 0x50, 0xcd, 0x12, 0x28, 0x10, 0xf4, 0x0a, 0x09, 0x1e, 0xb8, 0xca, 0x9d, 0x88, 0x48, + 0xd9, 0x93, 0x90, 0xbe, 0xc8, 0x0b, 0x3c, 0x65, 0xb0, 0xdb, 0xd0, 0x72, 0x7d, 0xc7, 0x9b, 0x0e, + 0xc5, 0xb3, 0x10, 0x1d, 0x91, 0x7e, 0xd4, 0x6e, 0xd0, 0xa9, 0x72, 0xcd, 0xf0, 0x8f, 0x0c, 0x1b, + 0xa1, 0xe2, 0x62, 0x01, 0xba, 0xac, 0xa1, 0x86, 0x1f, 0x43, 0xad, 0x2f, 0x73, 0xd0, 0x5a, 0x4c, + 0x3c, 0xdc, 0xb6, 0x10, 0x9d, 0x37, 0x1f, 0xed, 0x48, 0x27, 0x5b, 0x99, 0xcf, 0x6c, 0x65, 0x7c, + 0x97, 0x16, 0x32, 0x77, 0x69, 0x92, 0x16, 0xc5, 0x97, 0xa7, 0xc5, 0x9c, 0xa3, 0xa5, 0x05, 0x47, + 0xad, 0xdf, 0xe4, 0xe0, 0xda, 0x42, 0x72, 0xff, 0x60, 0x8b, 0xd6, 0xa0, 0x3e, 0xb1, 0xcf, 0x84, + 0x7e, 0xf2, 0x88, 0xcc, 0x15, 0x92, 0x65, 0xfd, 0x07, 0xec, 0xf3, 0xa1, 0x91, 0xad, 0xa8, 0x2b, + 0x6d, 0x8b, 0x13, 0xe4, 0x30, 0x50, 0xfb, 0xc1, 0xd4, 0xdc, 0xc5, 0x71, 0x82, 0xc4, 0xcc, 0xcb, + 0x69, 0x54, 0xb8, 0x22, 0x8d, 0xac, 0x43, 0xa8, 0xc6, 0x06, 0xb2, 0x5b, 0xe6, 0x4d, 0x2a, 0x97, + 0x3e, 0xb5, 0x1e, 0x47, 0x42, 0xa2, 0xed, 0xfa, 0x81, 0xea, 0x5d, 0x28, 0xe9, 0x1e, 0x35, 0x7f, + 0x19, 0xa1, 0x25, 0xd6, 0x00, 0x2a, 0x86, 0xc3, 0x36, 0xa0, 0x7c, 0x32, 0x4b, 0xde, 0x67, 0xcc, + 0x71, 0x81, 0xe3, 0xa1, 0x41, 0xe0, 0x19, 0xa4, 0x11, 0xec, 0x06, 0x14, 0x4f, 0x66, 0xbd, 0x8e, + 0xfe, 0xea, 0xc4, 0x93, 0x0c, 0x47, 0xbb, 0x65, 0x6d, 0x90, 0xf5, 0x08, 0x1a, 0xd9, 0x79, 0xc9, + 0xc5, 0x9e, 0xcb, 0x5c, 0xec, 0xc9, 0x91, 0x9d, 0x7f, 0xd5, 0xe7, 0xc7, 0xc7, 0x00, 0xf4, 0x82, + 0xfc, 0xba, 0x9f, 0x2d, 0x1f, 0x42, 0xc5, 0xbc, 0x3c, 0xb3, 0x0f, 0x16, 0x5e, 0xd2, 0x9b, 0xc9, + 0xb3, 0xf4, 0xdc, 0x73, 0xba, 0xf5, 0x00, 0x1b, 0xd8, 0x73, 0x21, 0x3b, 0xee, 0x68, 0xf4, 0xba, + 0xcb, 0x3d, 0x80, 0xe6, 0x71, 0x18, 0xfe, 0x6b, 0x73, 0x7f, 0x0a, 0x65, 0xfd, 0x00, 0x8e, 0x73, + 0x3c, 0xb4, 0xc0, 0xec, 0x01, 0xd3, 0x4d, 0x6e, 0xd6, 0x24, 0xae, 0x01, 0x88, 0x9c, 0xe2, 0x7a, + 0x66, 0x73, 0x09, 0x39, 0x6f, 0x00, 0xd7, 0x80, 0x8d, 0x75, 0xa8, 0x98, 0xb7, 0x56, 0x56, 0x83, + 0xd2, 0xf1, 0xe1, 0xa0, 0xfb, 0xa4, 0xb5, 0xc4, 0xaa, 0x50, 0x3c, 0xe8, 0x0f, 0x9e, 0xb4, 0x72, + 0x48, 0x1d, 0xf6, 0x0f, 0xbb, 0xad, 0xfc, 0xc6, 0x6d, 0x68, 0x64, 0x5f, 0x5b, 0x59, 0x1d, 0x2a, + 0x83, 0x9d, 0xc3, 0xce, 0x6e, 0xff, 0x27, 0xad, 0x25, 0xd6, 0x80, 0x6a, 0xef, 0x70, 0xd0, 0xdd, + 0x3b, 0xe6, 0xdd, 0x56, 0x6e, 0xe3, 0xc7, 0x50, 0x4b, 0x1e, 0xa0, 0x50, 0xc3, 0x6e, 0xef, 0xb0, + 0xd3, 0x5a, 0x62, 0x00, 0xe5, 0x41, 0x77, 0x8f, 0x77, 0x51, 0x6f, 0x05, 0x0a, 0x83, 0xc1, 0x41, + 0x2b, 0x8f, 0xab, 0xee, 0xed, 0xec, 0x1d, 0x74, 0x5b, 0x05, 0x24, 0x9f, 0x3c, 0x3e, 0xda, 0x1f, + 0xb4, 0x8a, 0x1b, 0x1f, 0xc2, 0x1b, 0x97, 0x5e, 0x74, 0x70, 0xc5, 0x4e, 0x77, 0x7f, 0xe7, 0xf8, + 0x11, 0x9a, 0x58, 0x86, 0x7c, 0xff, 0x50, 0x2b, 0xea, 0xef, 0xef, 0xb7, 0xf2, 0x1b, 0x1f, 0xc3, + 0xb5, 0x85, 0x27, 0x19, 0x5a, 0xf0, 0x60, 0x87, 0x77, 0x71, 0xf1, 0x3a, 0x54, 0x8e, 0x78, 0xef, + 0xe9, 0xce, 0x93, 0x6e, 0x2b, 0x87, 0x82, 0x47, 0xfd, 0xbd, 0x87, 0xdd, 0x4e, 0x2b, 0xbf, 0x7b, + 0xf3, 0xab, 0x17, 0xab, 0xb9, 0x6f, 0x5e, 0xac, 0xe6, 0xbe, 0x7d, 0xb1, 0x9a, 0xfb, 0xeb, 0x8b, + 0xd5, 0xdc, 0x97, 0xdf, 0xaf, 0x2e, 0x7d, 0xf3, 0xfd, 0xea, 0xd2, 0xb7, 0xdf, 0xaf, 0x2e, 0x9d, + 0x94, 0xe9, 0x5f, 0x97, 0x8f, 0xfe, 0x19, 0x00, 0x00, 0xff, 0xff, 0xe8, 0xd7, 0x00, 0x96, 0xb5, + 0x19, 0x00, 0x00, } func (m *Op) Marshal() (dAtA []byte, err error) { @@ -3642,6 +3687,13 @@ func (m *Mount) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContentCache != 0 { + i = encodeVarintOps(dAtA, i, uint64(m.ContentCache)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc0 + } if len(m.ResultID) > 0 { i -= len(m.ResultID) copy(dAtA[i:], m.ResultID) @@ -5865,6 +5917,9 @@ func (m *Mount) Size() (n int) { if l > 0 { n += 2 + l + sovOps(uint64(l)) } + if m.ContentCache != 0 { + n += 2 + sovOps(uint64(m.ContentCache)) + } return n } @@ -8572,6 +8627,25 @@ func (m *Mount) Unmarshal(dAtA []byte) error { } m.ResultID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 24: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ContentCache", wireType) + } + m.ContentCache = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ContentCache |= MountContentCache(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipOps(dAtA[iNdEx:]) diff --git a/vendor/github.com/moby/buildkit/solver/pb/ops.proto b/vendor/github.com/moby/buildkit/solver/pb/ops.proto index 4788c093b7ae0..a8c53e2772dab 100644 --- a/vendor/github.com/moby/buildkit/solver/pb/ops.proto +++ b/vendor/github.com/moby/buildkit/solver/pb/ops.proto @@ -10,6 +10,7 @@ option (gogoproto.stable_marshaler_all) = true; // Op represents a vertex of the LLB DAG. message Op { + // changes to this structure must be represented in json.go. // inputs is a set of input edges. repeated Input inputs = 1; oneof op { @@ -29,7 +30,7 @@ message Platform { string Architecture = 1; string OS = 2; string Variant = 3; - string OSVersion = 4; // unused + string OSVersion = 4; repeated string OSFeatures = 5; // unused } @@ -108,6 +109,7 @@ message Mount { SecretOpt secretOpt = 21; SSHOpt SSHOpt = 22; string resultID = 23; + MountContentCache contentCache = 24; } // MountType defines a type of a mount from a supported set @@ -119,6 +121,13 @@ enum MountType { TMPFS = 4; } +// MountContentCache ... +enum MountContentCache { + DEFAULT = 0; + ON = 1; + OFF = 2; +} + // TmpfsOpt defines options describing tpmfs mounts message TmpfsOpt { // Specify an upper limit on the size of the filesystem. @@ -288,6 +297,7 @@ message FileOp { } message FileAction { + // changes to this structure must be represented in json.go. int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; // could be real input or target (target index + max input index) int64 secondaryInput = 2 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; // --//-- int64 output = 3 [(gogoproto.customtype) = "OutputIndex", (gogoproto.nullable) = false]; @@ -373,6 +383,7 @@ message ChownOpt { } message UserOpt { + // changes to this structure must be represented in json.go. oneof user { NamedUserOpt byName = 1; uint32 byID = 2; @@ -393,14 +404,14 @@ message MergeOp { } message LowerDiffInput { - int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; + int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; } message UpperDiffInput { - int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; + int64 input = 1 [(gogoproto.customtype) = "InputIndex", (gogoproto.nullable) = false]; } message DiffOp { - LowerDiffInput lower = 1; - UpperDiffInput upper = 2; + LowerDiffInput lower = 1; + UpperDiffInput upper = 2; } diff --git a/vendor/github.com/moby/buildkit/solver/pb/platform.go b/vendor/github.com/moby/buildkit/solver/pb/platform.go index 0fd48a07d4369..00473a5b324bf 100644 --- a/vendor/github.com/moby/buildkit/solver/pb/platform.go +++ b/vendor/github.com/moby/buildkit/solver/pb/platform.go @@ -5,23 +5,29 @@ import ( ) func (p *Platform) Spec() ocispecs.Platform { - return ocispecs.Platform{ + result := ocispecs.Platform{ OS: p.OS, Architecture: p.Architecture, Variant: p.Variant, OSVersion: p.OSVersion, - OSFeatures: p.OSFeatures, } + if p.OSFeatures != nil { + result.OSFeatures = append([]string{}, p.OSFeatures...) + } + return result } func PlatformFromSpec(p ocispecs.Platform) Platform { - return Platform{ + result := Platform{ OS: p.OS, Architecture: p.Architecture, Variant: p.Variant, OSVersion: p.OSVersion, - OSFeatures: p.OSFeatures, } + if p.OSFeatures != nil { + result.OSFeatures = append([]string{}, p.OSFeatures...) + } + return result } func ToSpecPlatforms(p []Platform) []ocispecs.Platform { diff --git a/vendor/github.com/moby/buildkit/solver/progress.go b/vendor/github.com/moby/buildkit/solver/progress.go index 3fb954f867c42..92e2c6cb009fe 100644 --- a/vendor/github.com/moby/buildkit/solver/progress.go +++ b/vendor/github.com/moby/buildkit/solver/progress.go @@ -91,7 +91,7 @@ func (j *Job) Status(ctx context.Context, ch chan *client.SolveStatus) error { select { case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) case ch <- ss: } } diff --git a/vendor/github.com/moby/buildkit/solver/result/result.go b/vendor/github.com/moby/buildkit/solver/result/result.go index cfcfe9dcbd3ef..20224427049d7 100644 --- a/vendor/github.com/moby/buildkit/solver/result/result.go +++ b/vendor/github.com/moby/buildkit/solver/result/result.go @@ -1,6 +1,7 @@ package result import ( + "maps" "sync" "github.com/pkg/errors" @@ -14,6 +15,15 @@ type Result[T comparable] struct { Attestations map[string][]Attestation[T] } +func (r *Result[T]) Clone() *Result[T] { + return &Result[T]{ + Ref: r.Ref, + Refs: maps.Clone(r.Refs), + Metadata: maps.Clone(r.Metadata), + Attestations: maps.Clone(r.Attestations), + } +} + func (r *Result[T]) AddMeta(k string, v []byte) { r.mu.Lock() if r.Metadata == nil { @@ -142,6 +152,10 @@ func EachRef[U comparable, V comparable](a *Result[U], b *Result[V], fn func(U, return err } +// ConvertResult transforms a Result[U] into a Result[V], using a transfomer +// function that converts a U to a V. Zero values of type U are converted to +// zero values of type V directly, without passing through the transformer +// function. func ConvertResult[U comparable, V comparable](r *Result[U], fn func(U) (V, error)) (*Result[V], error) { var zero U @@ -160,6 +174,8 @@ func ConvertResult[U comparable, V comparable](r *Result[U], fn func(U) (V, erro } for k, r := range r.Refs { if r == zero { + var zero V + r2.Refs[k] = zero continue } r2.Refs[k], err = fn(r) diff --git a/vendor/github.com/moby/buildkit/solver/scheduler.go b/vendor/github.com/moby/buildkit/solver/scheduler.go index 2d0ee07afe92a..20220f73943ca 100644 --- a/vendor/github.com/moby/buildkit/solver/scheduler.go +++ b/vendor/github.com/moby/buildkit/solver/scheduler.go @@ -2,7 +2,9 @@ package solver import ( "context" + "encoding/csv" "os" + "strings" "sync" "github.com/moby/buildkit/solver/internal/pipe" @@ -12,6 +14,8 @@ import ( ) var debugScheduler = false // TODO: replace with logs in build trace +var debugSchedulerSteps []string +var debugSchedulerStepsParseOnce sync.Once func init() { if os.Getenv("BUILDKIT_SCHEDULER_DEBUG") == "1" { @@ -68,6 +72,16 @@ func (s *scheduler) Stop() { } func (s *scheduler) loop() { + debugSchedulerStepsParseOnce.Do(func() { + if s := os.Getenv("BUILDKIT_SCHEDULER_DEBUG_STEPS"); s != "" { + fields, err := csv.NewReader(strings.NewReader(s)).Read() + if err != nil { + return + } + debugSchedulerSteps = fields + } + }) + defer func() { close(s.closed) }() @@ -130,11 +144,11 @@ func (s *scheduler) dispatch(e *edge) { pf := &pipeFactory{s: s, e: e} // unpark the edge - if debugScheduler { + if e.debug { debugSchedulerPreUnpark(e, inc, updates, out) } e.unpark(inc, updates, out, pf) - if debugScheduler { + if e.debug { debugSchedulerPostUnpark(e, inc) } @@ -172,9 +186,14 @@ func (s *scheduler) dispatch(e *edge) { if e.isDep(origEdge) || origEdge.isDep(e) { bklog.G(context.TODO()).Debugf("skip merge due to dependency") } else { - bklog.G(context.TODO()).Debugf("merging edge %s to %s\n", e.edge.Vertex.Name(), origEdge.edge.Vertex.Name()) - if s.mergeTo(origEdge, e) { - s.ef.setEdge(e.edge, origEdge) + dest, src := origEdge, e + if s.ef.hasOwner(origEdge.edge, e.edge) { + dest, src = src, dest + } + + bklog.G(context.TODO()).Debugf("merging edge %s[%d] to %s[%d]\n", src.edge.Vertex.Name(), src.edge.Index, dest.edge.Vertex.Name(), dest.edge.Index) + if s.mergeTo(dest, src) { + s.ef.setEdge(src.edge, dest) } } } @@ -231,8 +250,8 @@ func (s *scheduler) build(ctx context.Context, edge Edge) (CachedResult, error) } s.mu.Unlock() - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(errors.WithStack(context.Canceled)) go func() { <-ctx.Done() @@ -337,6 +356,7 @@ func (s *scheduler) mergeTo(target, src *edge) bool { type edgeFactory interface { getEdge(Edge) *edge setEdge(Edge, *edge) + hasOwner(Edge, Edge) bool } type pipeFactory struct { @@ -352,7 +372,7 @@ func (pf *pipeFactory) NewInputRequest(ee Edge, req *edgeRequest) pipe.Receiver }) } p := pf.s.newPipe(target, pf.e, pipe.Request{Payload: req}) - if debugScheduler { + if pf.e.debug { bklog.G(context.TODO()).Debugf("> newPipe %s %p desiredState=%s", ee.Vertex.Name(), p, req.desiredState) } return p.Receiver @@ -360,7 +380,7 @@ func (pf *pipeFactory) NewInputRequest(ee Edge, req *edgeRequest) pipe.Receiver func (pf *pipeFactory) NewFuncRequest(f func(context.Context) (interface{}, error)) pipe.Receiver { p := pf.s.newRequestWithFunc(pf.e, f) - if debugScheduler { + if pf.e.debug { bklog.G(context.TODO()).Debugf("> newFunc %p", p) } return p diff --git a/vendor/github.com/moby/buildkit/solver/types.go b/vendor/github.com/moby/buildkit/solver/types.go index 01b344a3af905..8357676cda585 100644 --- a/vendor/github.com/moby/buildkit/solver/types.go +++ b/vendor/github.com/moby/buildkit/solver/types.go @@ -121,9 +121,14 @@ type CacheExporter interface { // CacheExporterTarget defines object capable of receiving exports type CacheExporterTarget interface { + // Add creates a new object record that we can then add results to and + // connect to other records. Add(dgst digest.Digest) CacheExporterRecord - Visit(interface{}) - Visited(interface{}) bool + + // Visit marks a target as having been visited. + Visit(target any) + // Vistited returns true if a target has previously been marked as visited. + Visited(target any) bool } // CacheExporterRecord is a single object being exported @@ -228,6 +233,17 @@ type CacheRecord struct { key *CacheKey } +func (ck *CacheRecord) TraceFields() map[string]any { + return map[string]any{ + "id": ck.ID, + "size": ck.Size, + "createdAt": ck.CreatedAt, + "priority": ck.Priority, + "cache_manager": ck.cacheManager.ID(), + "cache_key": ck.key.TraceFields(), + } +} + // CacheManager determines if there is a result that matches the cache keys // generated during the build that could be reused instead of fully // reevaluating the vertex and its inputs. There can be multiple cache diff --git a/vendor/github.com/moby/buildkit/source/containerimage/identifier.go b/vendor/github.com/moby/buildkit/source/containerimage/identifier.go new file mode 100644 index 0000000000000..08db503a38bef --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/containerimage/identifier.go @@ -0,0 +1,92 @@ +package containerimage + +import ( + "github.com/containerd/containerd/reference" + "github.com/moby/buildkit/client" + "github.com/moby/buildkit/solver/llbsolver/provenance" + "github.com/moby/buildkit/source" + srctypes "github.com/moby/buildkit/source/types" + "github.com/moby/buildkit/util/resolver" + digest "github.com/opencontainers/go-digest" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +type ImageIdentifier struct { + Reference reference.Spec + Platform *ocispecs.Platform + ResolveMode resolver.ResolveMode + RecordType client.UsageRecordType + LayerLimit *int +} + +func NewImageIdentifier(str string) (*ImageIdentifier, error) { + ref, err := reference.Parse(str) + if err != nil { + return nil, errors.WithStack(err) + } + + if ref.Object == "" { + return nil, errors.WithStack(reference.ErrObjectRequired) + } + return &ImageIdentifier{Reference: ref}, nil +} + +var _ source.Identifier = (*ImageIdentifier)(nil) + +func (*ImageIdentifier) Scheme() string { + return srctypes.DockerImageScheme +} + +func (id *ImageIdentifier) Capture(c *provenance.Capture, pin string) error { + dgst, err := digest.Parse(pin) + if err != nil { + return errors.Wrapf(err, "failed to parse image digest %s", pin) + } + c.AddImage(provenance.ImageSource{ + Ref: id.Reference.String(), + Platform: id.Platform, + Digest: dgst, + }) + return nil +} + +type OCIIdentifier struct { + Reference reference.Spec + Platform *ocispecs.Platform + SessionID string + StoreID string + LayerLimit *int +} + +func NewOCIIdentifier(str string) (*OCIIdentifier, error) { + ref, err := reference.Parse(str) + if err != nil { + return nil, errors.WithStack(err) + } + + if ref.Object == "" { + return nil, errors.WithStack(reference.ErrObjectRequired) + } + return &OCIIdentifier{Reference: ref}, nil +} + +var _ source.Identifier = (*OCIIdentifier)(nil) + +func (*OCIIdentifier) Scheme() string { + return srctypes.OCIScheme +} + +func (id *OCIIdentifier) Capture(c *provenance.Capture, pin string) error { + dgst, err := digest.Parse(pin) + if err != nil { + return errors.Wrapf(err, "failed to parse OCI digest %s", pin) + } + c.AddImage(provenance.ImageSource{ + Ref: id.Reference.String(), + Platform: id.Platform, + Digest: dgst, + Local: true, + }) + return nil +} diff --git a/vendor/github.com/moby/buildkit/source/containerimage/ocilayout.go b/vendor/github.com/moby/buildkit/source/containerimage/ocilayout.go index 2358b5339b7aa..7ade6af55788e 100644 --- a/vendor/github.com/moby/buildkit/source/containerimage/ocilayout.go +++ b/vendor/github.com/moby/buildkit/source/containerimage/ocilayout.go @@ -8,7 +8,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/session" sessioncontent "github.com/moby/buildkit/session/content" "github.com/moby/buildkit/util/imageutil" @@ -21,7 +21,7 @@ const ( ) // getOCILayoutResolver gets a resolver to an OCI layout for a specified store from the client using the given session. -func getOCILayoutResolver(store llb.ResolveImageConfigOptStore, sm *session.Manager, g session.Group) *ociLayoutResolver { +func getOCILayoutResolver(store sourceresolver.ResolveImageConfigOptStore, sm *session.Manager, g session.Group) *ociLayoutResolver { r := &ociLayoutResolver{ store: store, sm: sm, @@ -32,7 +32,7 @@ func getOCILayoutResolver(store llb.ResolveImageConfigOptStore, sm *session.Mana type ociLayoutResolver struct { remotes.Resolver - store llb.ResolveImageConfigOptStore + store sourceresolver.ResolveImageConfigOptStore sm *session.Manager g session.Group } @@ -123,8 +123,9 @@ func (r *ociLayoutResolver) info(ctx context.Context, ref reference.Spec) (conte func (r *ociLayoutResolver) withCaller(ctx context.Context, f func(context.Context, session.Caller) error) error { if r.store.SessionID != "" { - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) caller, err := r.sm.Get(timeoutCtx, r.store.SessionID, false) if err != nil { diff --git a/vendor/github.com/moby/buildkit/source/containerimage/pull.go b/vendor/github.com/moby/buildkit/source/containerimage/pull.go index 8792111aaa5dc..d1b72b840178e 100644 --- a/vendor/github.com/moby/buildkit/source/containerimage/pull.go +++ b/vendor/github.com/moby/buildkit/source/containerimage/pull.go @@ -7,24 +7,18 @@ import ( "time" "github.com/containerd/containerd/content" - "github.com/containerd/containerd/diff" containerderrdefs "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/leases" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/snapshots" "github.com/moby/buildkit/cache" "github.com/moby/buildkit/client" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/session" - "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver/errdefs" - "github.com/moby/buildkit/source" - srctypes "github.com/moby/buildkit/source/types" "github.com/moby/buildkit/util/estargz" "github.com/moby/buildkit/util/flightcontrol" "github.com/moby/buildkit/util/imageutil" @@ -39,171 +33,19 @@ import ( "github.com/pkg/errors" ) -// TODO: break apart containerd specifics like contentstore so the resolver -// code can be used with any implementation - -type ResolverType int - -const ( - ResolverTypeRegistry ResolverType = iota - ResolverTypeOCILayout -) - -type SourceOpt struct { - Snapshotter snapshot.Snapshotter - ContentStore content.Store - Applier diff.Applier - CacheAccessor cache.Accessor - ImageStore images.Store // optional - RegistryHosts docker.RegistryHosts - ResolverType - LeaseManager leases.Manager -} - -type resolveImageResult struct { - ref string - dgst digest.Digest - dt []byte -} - -type Source struct { - SourceOpt - g flightcontrol.Group[*resolveImageResult] -} - -var _ source.Source = &Source{} - -func NewSource(opt SourceOpt) (*Source, error) { - is := &Source{ - SourceOpt: opt, - } - - return is, nil -} - -func (is *Source) ID() string { - if is.ResolverType == ResolverTypeOCILayout { - return srctypes.OCIScheme - } - return srctypes.DockerImageScheme -} - -func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) { - key := ref - if platform := opt.Platform; platform != nil { - key += platforms.Format(*platform) - } - var ( - rm source.ResolveMode - rslvr remotes.Resolver - err error - ) - - switch is.ResolverType { - case ResolverTypeRegistry: - rm, err = source.ParseImageResolveMode(opt.ResolveMode) - if err != nil { - return "", "", nil, err - } - rslvr = resolver.DefaultPool.GetResolver(is.RegistryHosts, ref, "pull", sm, g).WithImageStore(is.ImageStore, rm) - case ResolverTypeOCILayout: - rm = source.ResolveModeForcePull - rslvr = getOCILayoutResolver(opt.Store, sm, g) - } - key += rm.String() - res, err := is.g.Do(ctx, key, func(ctx context.Context) (*resolveImageResult, error) { - newRef, dgst, dt, err := imageutil.Config(ctx, ref, rslvr, is.ContentStore, is.LeaseManager, opt.Platform, opt.SourcePolicies) - if err != nil { - return nil, err - } - return &resolveImageResult{dgst: dgst, dt: dt, ref: newRef}, nil - }) - if err != nil { - return "", "", nil, err - } - return res.ref, res.dgst, res.dt, nil -} - -func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, vtx solver.Vertex) (source.SourceInstance, error) { - var ( - p *puller - platform = platforms.DefaultSpec() - pullerUtil *pull.Puller - mode source.ResolveMode - recordType client.UsageRecordType - ref reference.Spec - store llb.ResolveImageConfigOptStore - layerLimit *int - ) - switch is.ResolverType { - case ResolverTypeRegistry: - imageIdentifier, ok := id.(*source.ImageIdentifier) - if !ok { - return nil, errors.Errorf("invalid image identifier %v", id) - } - - if imageIdentifier.Platform != nil { - platform = *imageIdentifier.Platform - } - mode = imageIdentifier.ResolveMode - recordType = imageIdentifier.RecordType - ref = imageIdentifier.Reference - layerLimit = imageIdentifier.LayerLimit - case ResolverTypeOCILayout: - ociIdentifier, ok := id.(*source.OCIIdentifier) - if !ok { - return nil, errors.Errorf("invalid OCI layout identifier %v", id) - } - - if ociIdentifier.Platform != nil { - platform = *ociIdentifier.Platform - } - mode = source.ResolveModeForcePull // with OCI layout, we always just "pull" - store = llb.ResolveImageConfigOptStore{ - SessionID: ociIdentifier.SessionID, - StoreID: ociIdentifier.StoreID, - } - ref = ociIdentifier.Reference - layerLimit = ociIdentifier.LayerLimit - default: - return nil, errors.Errorf("unknown resolver type: %v", is.ResolverType) - } - pullerUtil = &pull.Puller{ - ContentStore: is.ContentStore, - Platform: platform, - Src: ref, - } - p = &puller{ - CacheAccessor: is.CacheAccessor, - LeaseManager: is.LeaseManager, - Puller: pullerUtil, - RegistryHosts: is.RegistryHosts, - ResolverType: is.ResolverType, - ImageStore: is.ImageStore, - Mode: mode, - RecordType: recordType, - Ref: ref.String(), - SessionManager: sm, - vtx: vtx, - store: store, - layerLimit: layerLimit, - } - return p, nil -} - type puller struct { CacheAccessor cache.Accessor LeaseManager leases.Manager RegistryHosts docker.RegistryHosts ImageStore images.Store - Mode source.ResolveMode + Mode resolver.ResolveMode RecordType client.UsageRecordType Ref string SessionManager *session.Manager layerLimit *int vtx solver.Vertex ResolverType - store llb.ResolveImageConfigOptStore + store sourceresolver.ResolveImageConfigOptStore g flightcontrol.Group[struct{}] cacheKeyErr error @@ -218,17 +60,21 @@ type puller struct { func mainManifestKey(ctx context.Context, desc ocispecs.Descriptor, platform ocispecs.Platform, layerLimit *int) (digest.Digest, error) { dt, err := json.Marshal(struct { - Digest digest.Digest - OS string - Arch string - Variant string `json:",omitempty"` - Limit *int `json:",omitempty"` + Digest digest.Digest + OS string + Arch string + Variant string `json:",omitempty"` + OSVersion string `json:",omitempty"` + OSFeatures []string `json:",omitempty"` + Limit *int `json:",omitempty"` }{ - Digest: desc.Digest, - OS: platform.OS, - Arch: platform.Architecture, - Variant: platform.Variant, - Limit: layerLimit, + Digest: desc.Digest, + OS: platform.OS, + Arch: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Limit: layerLimit, }) if err != nil { return "", err diff --git a/vendor/github.com/moby/buildkit/source/containerimage/source.go b/vendor/github.com/moby/buildkit/source/containerimage/source.go new file mode 100644 index 0000000000000..ff313315ec27d --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/containerimage/source.go @@ -0,0 +1,297 @@ +package containerimage + +import ( + "context" + "strconv" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/diff" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/reference" + "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/remotes/docker" + "github.com/moby/buildkit/cache" + "github.com/moby/buildkit/client" + "github.com/moby/buildkit/client/llb/sourceresolver" + "github.com/moby/buildkit/session" + "github.com/moby/buildkit/snapshot" + "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/pb" + "github.com/moby/buildkit/source" + srctypes "github.com/moby/buildkit/source/types" + "github.com/moby/buildkit/util/flightcontrol" + "github.com/moby/buildkit/util/imageutil" + "github.com/moby/buildkit/util/pull" + "github.com/moby/buildkit/util/resolver" + digest "github.com/opencontainers/go-digest" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +// TODO: break apart containerd specifics like contentstore so the resolver +// code can be used with any implementation + +type ResolverType int + +const ( + ResolverTypeRegistry ResolverType = iota + ResolverTypeOCILayout +) + +type SourceOpt struct { + Snapshotter snapshot.Snapshotter + ContentStore content.Store + Applier diff.Applier + CacheAccessor cache.Accessor + ImageStore images.Store // optional + RegistryHosts docker.RegistryHosts + ResolverType + LeaseManager leases.Manager +} + +type Source struct { + SourceOpt + g flightcontrol.Group[*resolveImageResult] +} + +var _ source.Source = &Source{} + +func NewSource(opt SourceOpt) (*Source, error) { + is := &Source{ + SourceOpt: opt, + } + + return is, nil +} + +func (is *Source) Schemes() []string { + if is.ResolverType == ResolverTypeOCILayout { + return []string{srctypes.OCIScheme} + } + return []string{srctypes.DockerImageScheme} +} + +func (is *Source) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + if is.ResolverType == ResolverTypeOCILayout { + return is.ociIdentifier(ref, attrs, platform) + } + + return is.registryIdentifier(ref, attrs, platform) +} + +func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, vtx solver.Vertex) (source.SourceInstance, error) { + var ( + p *puller + platform = platforms.DefaultSpec() + pullerUtil *pull.Puller + mode resolver.ResolveMode + recordType client.UsageRecordType + ref reference.Spec + store sourceresolver.ResolveImageConfigOptStore + layerLimit *int + ) + switch is.ResolverType { + case ResolverTypeRegistry: + imageIdentifier, ok := id.(*ImageIdentifier) + if !ok { + return nil, errors.Errorf("invalid image identifier %v", id) + } + + if imageIdentifier.Platform != nil { + platform = *imageIdentifier.Platform + } + mode = imageIdentifier.ResolveMode + recordType = imageIdentifier.RecordType + ref = imageIdentifier.Reference + layerLimit = imageIdentifier.LayerLimit + case ResolverTypeOCILayout: + ociIdentifier, ok := id.(*OCIIdentifier) + if !ok { + return nil, errors.Errorf("invalid OCI layout identifier %v", id) + } + + if ociIdentifier.Platform != nil { + platform = *ociIdentifier.Platform + } + mode = resolver.ResolveModeForcePull // with OCI layout, we always just "pull" + store = sourceresolver.ResolveImageConfigOptStore{ + SessionID: ociIdentifier.SessionID, + StoreID: ociIdentifier.StoreID, + } + ref = ociIdentifier.Reference + layerLimit = ociIdentifier.LayerLimit + default: + return nil, errors.Errorf("unknown resolver type: %v", is.ResolverType) + } + pullerUtil = &pull.Puller{ + ContentStore: is.ContentStore, + Platform: platform, + Src: ref, + } + p = &puller{ + CacheAccessor: is.CacheAccessor, + LeaseManager: is.LeaseManager, + Puller: pullerUtil, + RegistryHosts: is.RegistryHosts, + ResolverType: is.ResolverType, + ImageStore: is.ImageStore, + Mode: mode, + RecordType: recordType, + Ref: ref.String(), + SessionManager: sm, + vtx: vtx, + store: store, + layerLimit: layerLimit, + } + return p, nil +} + +func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) { + key := ref + var ( + rm resolver.ResolveMode + rslvr remotes.Resolver + err error + ) + if platform := opt.Platform; platform != nil { + key += platforms.Format(*platform) + } + + switch is.ResolverType { + case ResolverTypeRegistry: + iopt := opt.ImageOpt + if iopt == nil { + return "", nil, errors.Errorf("missing imageopt for resolve") + } + rm, err = resolver.ParseImageResolveMode(iopt.ResolveMode) + if err != nil { + return "", nil, err + } + rslvr = resolver.DefaultPool.GetResolver(is.RegistryHosts, ref, "pull", sm, g).WithImageStore(is.ImageStore, rm) + case ResolverTypeOCILayout: + iopt := opt.OCILayoutOpt + if iopt == nil { + return "", nil, errors.Errorf("missing ocilayoutopt for resolve") + } + rm = resolver.ResolveModeForcePull + rslvr = getOCILayoutResolver(iopt.Store, sm, g) + } + key += rm.String() + res, err := is.g.Do(ctx, key, func(ctx context.Context) (*resolveImageResult, error) { + dgst, dt, err := imageutil.Config(ctx, ref, rslvr, is.ContentStore, is.LeaseManager, opt.Platform) + if err != nil { + return nil, err + } + return &resolveImageResult{dgst: dgst, dt: dt}, nil + }) + if err != nil { + return "", nil, err + } + return res.dgst, res.dt, nil +} + +type resolveImageResult struct { + dgst digest.Digest + dt []byte +} + +func (is *Source) registryIdentifier(ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := NewImageIdentifier(ref) + if err != nil { + return nil, err + } + + if platform != nil { + id.Platform = &ocispecs.Platform{ + OS: platform.OS, + Architecture: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + } + if platform.OSFeatures != nil { + id.Platform.OSFeatures = append([]string{}, platform.OSFeatures...) + } + } + + for k, v := range attrs { + switch k { + case pb.AttrImageResolveMode: + rm, err := resolver.ParseImageResolveMode(v) + if err != nil { + return nil, err + } + id.ResolveMode = rm + case pb.AttrImageRecordType: + rt, err := parseImageRecordType(v) + if err != nil { + return nil, err + } + id.RecordType = rt + case pb.AttrImageLayerLimit: + l, err := strconv.Atoi(v) + if err != nil { + return nil, errors.Wrapf(err, "invalid layer limit %s", v) + } + if l <= 0 { + return nil, errors.Errorf("invalid layer limit %s", v) + } + id.LayerLimit = &l + } + } + + return id, nil +} + +func (is *Source) ociIdentifier(ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := NewOCIIdentifier(ref) + if err != nil { + return nil, err + } + + if platform != nil { + id.Platform = &ocispecs.Platform{ + OS: platform.OS, + Architecture: platform.Architecture, + Variant: platform.Variant, + OSVersion: platform.OSVersion, + } + if platform.OSFeatures != nil { + id.Platform.OSFeatures = append([]string{}, platform.OSFeatures...) + } + } + + for k, v := range attrs { + switch k { + case pb.AttrOCILayoutSessionID: + id.SessionID = v + case pb.AttrOCILayoutStoreID: + id.StoreID = v + case pb.AttrOCILayoutLayerLimit: + l, err := strconv.Atoi(v) + if err != nil { + return nil, errors.Wrapf(err, "invalid layer limit %s", v) + } + if l <= 0 { + return nil, errors.Errorf("invalid layer limit %s", v) + } + id.LayerLimit = &l + } + } + + return id, nil +} + +func parseImageRecordType(v string) (client.UsageRecordType, error) { + switch client.UsageRecordType(v) { + case "", client.UsageRecordTypeRegular: + return client.UsageRecordTypeRegular, nil + case client.UsageRecordTypeInternal: + return client.UsageRecordTypeInternal, nil + case client.UsageRecordTypeFrontend: + return client.UsageRecordTypeFrontend, nil + default: + return "", errors.Errorf("invalid record type %s", v) + } +} diff --git a/vendor/github.com/moby/buildkit/source/git/identifier.go b/vendor/github.com/moby/buildkit/source/git/identifier.go new file mode 100644 index 0000000000000..1726fb9a7acfd --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/git/identifier.go @@ -0,0 +1,77 @@ +package git + +import ( + "path" + + "github.com/moby/buildkit/solver/llbsolver/provenance" + "github.com/moby/buildkit/source" + srctypes "github.com/moby/buildkit/source/types" + "github.com/moby/buildkit/util/gitutil" +) + +type GitIdentifier struct { + Remote string + Ref string + Subdir string + KeepGitDir bool + AuthTokenSecret string + AuthHeaderSecret string + MountSSHSock string + KnownSSHHosts string +} + +func NewGitIdentifier(remoteURL string) (*GitIdentifier, error) { + if !gitutil.IsGitTransport(remoteURL) { + remoteURL = "https://" + remoteURL + } + u, err := gitutil.ParseURL(remoteURL) + if err != nil { + return nil, err + } + + repo := GitIdentifier{Remote: u.Remote} + if u.Fragment != nil { + repo.Ref = u.Fragment.Ref + repo.Subdir = u.Fragment.Subdir + } + if sd := path.Clean(repo.Subdir); sd == "/" || sd == "." { + repo.Subdir = "" + } + return &repo, nil +} + +func (GitIdentifier) Scheme() string { + return srctypes.GitScheme +} + +var _ source.Identifier = (*GitIdentifier)(nil) + +func (id *GitIdentifier) Capture(c *provenance.Capture, pin string) error { + url := id.Remote + if id.Ref != "" { + url += "#" + id.Ref + } + c.AddGit(provenance.GitSource{ + URL: url, + Commit: pin, + }) + if id.AuthTokenSecret != "" { + c.AddSecret(provenance.Secret{ + ID: id.AuthTokenSecret, + Optional: true, + }) + } + if id.AuthHeaderSecret != "" { + c.AddSecret(provenance.Secret{ + ID: id.AuthHeaderSecret, + Optional: true, + }) + } + if id.MountSSHSock != "" { + c.AddSSH(provenance.SSH{ + ID: id.MountSSHSock, + Optional: true, + }) + } + return nil +} diff --git a/vendor/github.com/moby/buildkit/source/git/gitsource.go b/vendor/github.com/moby/buildkit/source/git/source.go similarity index 72% rename from vendor/github.com/moby/buildkit/source/git/gitsource.go rename to vendor/github.com/moby/buildkit/source/git/source.go index fdc1b50028dbc..ea3ec5821c192 100644 --- a/vendor/github.com/moby/buildkit/source/git/gitsource.go +++ b/vendor/github.com/moby/buildkit/source/git/source.go @@ -1,7 +1,6 @@ package git import ( - "bytes" "context" "encoding/base64" "fmt" @@ -24,9 +23,11 @@ import ( "github.com/moby/buildkit/session/sshforward" "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/source" srctypes "github.com/moby/buildkit/source/types" "github.com/moby/buildkit/util/bklog" + "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/progress/logs" "github.com/moby/buildkit/util/urlutil" "github.com/moby/locker" @@ -63,12 +64,43 @@ func NewSource(opt Opt) (source.Source, error) { return gs, nil } -func (gs *gitSource) ID() string { - return srctypes.GitScheme +func (gs *gitSource) Schemes() []string { + return []string{srctypes.GitScheme} +} + +func (gs *gitSource) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := NewGitIdentifier(ref) + if err != nil { + return nil, err + } + + for k, v := range attrs { + switch k { + case pb.AttrKeepGitDir: + if v == "true" { + id.KeepGitDir = true + } + case pb.AttrFullRemoteURL: + if !gitutil.IsGitTransport(v) { + v = "https://" + v + } + id.Remote = v + case pb.AttrAuthHeaderSecret: + id.AuthHeaderSecret = v + case pb.AttrAuthTokenSecret: + id.AuthTokenSecret = v + case pb.AttrKnownSSHHosts: + id.KnownSSHHosts = v + case pb.AttrMountSSHSock: + id.MountSSHSock = v + } + } + + return id, nil } // needs to be called with repo lock -func (gs *gitSource) mountRemote(ctx context.Context, remote string, auth []string, g session.Group) (target string, release func(), retErr error) { +func (gs *gitSource) mountRemote(ctx context.Context, remote string, authArgs []string, g session.Group) (target string, release func() error, retErr error) { sis, err := searchGitRemote(ctx, gs.cache, remote) if err != nil { return "", nil, errors.Wrapf(err, "failed to search metadata for %s", urlutil.RedactCredentials(remote)) @@ -97,8 +129,8 @@ func (gs *gitSource) mountRemote(ctx context.Context, remote string, auth []stri initializeRepo = true } - releaseRemoteRef := func() { - remoteRef.Release(context.TODO()) + releaseRemoteRef := func() error { + return remoteRef.Release(context.TODO()) } defer func() { @@ -124,16 +156,21 @@ func (gs *gitSource) mountRemote(ctx context.Context, remote string, auth []stri } }() + git := gitCLI( + gitutil.WithGitDir(dir), + gitutil.WithArgs(authArgs...), + ) + if initializeRepo { // Explicitly set the Git config 'init.defaultBranch' to the // implied default to suppress "hint:" output about not having a // default initial branch name set which otherwise spams unit // test logs. - if _, err := gitWithinDir(ctx, dir, "", "", "", auth, "-c", "init.defaultBranch=master", "init", "--bare"); err != nil { + if _, err := git.Run(ctx, "-c", "init.defaultBranch=master", "init", "--bare"); err != nil { return "", nil, errors.Wrapf(err, "failed to init repo at %s", dir) } - if _, err := gitWithinDir(ctx, dir, "", "", "", auth, "remote", "add", "origin", remote); err != nil { + if _, err := git.Run(ctx, "remote", "add", "origin", remote); err != nil { return "", nil, errors.Wrapf(err, "failed add origin repo at %s", dir) } @@ -143,18 +180,21 @@ func (gs *gitSource) mountRemote(ctx context.Context, remote string, auth []stri return "", nil, err } } - return dir, func() { - lm.Unmount() - releaseRemoteRef() + return dir, func() error { + err := lm.Unmount() + if err1 := releaseRemoteRef(); err == nil { + err = err1 + } + return err }, nil } type gitSourceHandler struct { *gitSource - src source.GitIdentifier + src GitIdentifier cacheKey string sm *session.Manager - auth []string + authArgs []string } func (gs *gitSourceHandler) shaToCacheKey(sha string) string { @@ -169,7 +209,7 @@ func (gs *gitSourceHandler) shaToCacheKey(sha string) string { } func (gs *gitSource) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, _ solver.Vertex) (source.SourceInstance, error) { - gitIdentifier, ok := id.(*source.GitIdentifier) + gitIdentifier, ok := id.(*GitIdentifier) if !ok { return nil, errors.Errorf("invalid git identifier %v", id) } @@ -207,7 +247,7 @@ func (gs *gitSourceHandler) authSecretNames() (sec []authSecret, _ error) { } func (gs *gitSourceHandler) getAuthToken(ctx context.Context, g session.Group) error { - if gs.auth != nil { + if gs.authArgs != nil { return nil } sec, err := gs.authSecretNames() @@ -226,7 +266,7 @@ func (gs *gitSourceHandler) getAuthToken(ctx context.Context, g session.Group) e if s.token { dt = []byte("basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("x-access-token:%s", dt)))) } - gs.auth = []string{"-c", "http." + tokenScope(gs.src.Remote) + ".extraheader=Authorization: " + string(dt)} + gs.authArgs = []string{"-c", "http." + tokenScope(gs.src.Remote) + ".extraheader=Authorization: " + string(dt)} break } return nil @@ -309,35 +349,15 @@ func (gs *gitSourceHandler) CacheKey(ctx context.Context, g session.Group, index gs.getAuthToken(ctx, g) - gitDir, unmountGitDir, err := gs.mountRemote(ctx, remote, gs.auth, g) + git, cleanup, err := gs.gitCli(ctx, g) if err != nil { return "", "", nil, false, err } - defer unmountGitDir() - - var sock string - if gs.src.MountSSHSock != "" { - var unmountSock func() error - sock, unmountSock, err = gs.mountSSHAuthSock(ctx, gs.src.MountSSHSock, g) - if err != nil { - return "", "", nil, false, err - } - defer unmountSock() - } - - var knownHosts string - if gs.src.KnownSSHHosts != "" { - var unmountKnownHosts func() error - knownHosts, unmountKnownHosts, err = gs.mountKnownHosts(ctx) - if err != nil { - return "", "", nil, false, err - } - defer unmountKnownHosts() - } + defer cleanup() ref := gs.src.Ref if ref == "" { - ref, err = getDefaultBranch(ctx, gitDir, "", sock, knownHosts, gs.auth, gs.src.Remote) + ref, err = getDefaultBranch(ctx, git, gs.src.Remote) if err != nil { return "", "", nil, false, err } @@ -345,20 +365,45 @@ func (gs *gitSourceHandler) CacheKey(ctx context.Context, g session.Group, index // TODO: should we assume that remote tag is immutable? add a timer? - buf, err := gitWithinDir(ctx, gitDir, "", sock, knownHosts, gs.auth, "ls-remote", "origin", ref) + buf, err := git.Run(ctx, "ls-remote", "origin", ref, ref+"^{}") if err != nil { return "", "", nil, false, errors.Wrapf(err, "failed to fetch remote %s", urlutil.RedactCredentials(remote)) } - out := buf.String() - idx := strings.Index(out, "\t") - if idx == -1 { - return "", "", nil, false, errors.Errorf("repository does not contain ref %s, output: %q", ref, string(out)) + lines := strings.Split(string(buf), "\n") + + var ( + partialRef = "refs/" + strings.TrimPrefix(ref, "refs/") + headRef = "refs/heads/" + strings.TrimPrefix(ref, "refs/heads/") + tagRef = "refs/tags/" + strings.TrimPrefix(ref, "refs/tags/") + annotatedTagRef = tagRef + "^{}" + ) + var sha, headSha, tagSha string + for _, line := range lines { + lineSha, lineRef, _ := strings.Cut(line, "\t") + switch lineRef { + case headRef: + headSha = lineSha + case tagRef, annotatedTagRef: + tagSha = lineSha + case partialRef: + sha = lineSha + } } - sha := string(out[:idx]) + // git-checkout prefers branches in case of ambiguity + if sha == "" { + sha = headSha + } + if sha == "" { + sha = tagSha + } + if sha == "" { + return "", "", nil, false, errors.Errorf("repository does not contain ref %s, output: %q", ref, string(buf)) + } if !isCommitSHA(sha) { return "", "", nil, false, errors.Errorf("invalid commit sha %q", sha) } + cacheKey := gs.shaToCacheKey(sha) gs.cacheKey = cacheKey return cacheKey, sha, nil, true, nil @@ -390,35 +435,23 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out gs.locker.Lock(gs.src.Remote) defer gs.locker.Unlock(gs.src.Remote) - gitDir, unmountGitDir, err := gs.mountRemote(ctx, gs.src.Remote, gs.auth, g) + + git, cleanup, err := gs.gitCli(ctx, g) if err != nil { return nil, err } - defer unmountGitDir() - - var sock string - if gs.src.MountSSHSock != "" { - var unmountSock func() error - sock, unmountSock, err = gs.mountSSHAuthSock(ctx, gs.src.MountSSHSock, g) - if err != nil { - return nil, err - } - defer unmountSock() + if err != nil { + return nil, err } - - var knownHosts string - if gs.src.KnownSSHHosts != "" { - var unmountKnownHosts func() error - knownHosts, unmountKnownHosts, err = gs.mountKnownHosts(ctx) - if err != nil { - return nil, err - } - defer unmountKnownHosts() + defer cleanup() + gitDir, err := git.GitDir(ctx) + if err != nil { + return nil, err } ref := gs.src.Ref if ref == "" { - ref, err = getDefaultBranch(ctx, gitDir, "", sock, knownHosts, gs.auth, gs.src.Remote) + ref, err = getDefaultBranch(ctx, git, gs.src.Remote) if err != nil { return nil, err } @@ -427,7 +460,7 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out doFetch := true if isCommitSHA(ref) { // skip fetch if commit already exists - if _, err := gitWithinDir(ctx, gitDir, "", sock, knownHosts, nil, "cat-file", "-e", ref+"^{commit}"); err == nil { + if _, err := git.Run(ctx, "cat-file", "-e", ref+"^{commit}"); err == nil { doFetch = false } } @@ -451,16 +484,16 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out // in case the ref is a branch and it now points to a different commit sha // TODO: is there a better way to do this? } - if _, err := gitWithinDir(ctx, gitDir, "", sock, knownHosts, gs.auth, args...); err != nil { + if _, err := git.Run(ctx, args...); err != nil { return nil, errors.Wrapf(err, "failed to fetch remote %s", urlutil.RedactCredentials(gs.src.Remote)) } - _, err = gitWithinDir(ctx, gitDir, "", sock, knownHosts, nil, "reflog", "expire", "--all", "--expire=now") + _, err = git.Run(ctx, "reflog", "expire", "--all", "--expire=now") if err != nil { return nil, errors.Wrapf(err, "failed to expire reflog for remote %s", urlutil.RedactCredentials(gs.src.Remote)) } } - checkoutRef, err := gs.cache.New(ctx, nil, g, cache.WithRecordType(client.UsageRecordTypeGitCheckout), cache.WithDescription(fmt.Sprintf("git snapshot for %s#%s", gs.src.Remote, ref))) + checkoutRef, err := gs.cache.New(ctx, nil, g, cache.WithRecordType(client.UsageRecordTypeGitCheckout), cache.WithDescription(fmt.Sprintf("git snapshot for %s#%s", urlutil.RedactCredentials(gs.src.Remote), ref))) if err != nil { return nil, errors.Wrapf(err, "failed to create new mutable for %s", urlutil.RedactCredentials(gs.src.Remote)) } @@ -496,49 +529,50 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out if err := os.MkdirAll(checkoutDir, 0711); err != nil { return nil, err } - _, err = gitWithinDir(ctx, checkoutDirGit, "", sock, knownHosts, nil, "-c", "init.defaultBranch=master", "init") + checkoutGit := git.New(gitutil.WithWorkTree(checkoutDir), gitutil.WithGitDir(checkoutDirGit)) + _, err = checkoutGit.Run(ctx, "-c", "init.defaultBranch=master", "init") if err != nil { return nil, err } // Defense-in-depth: clone using the file protocol to disable local-clone // optimizations which can be abused on some versions of Git to copy unintended // host files into the build context. - _, err = gitWithinDir(ctx, checkoutDirGit, "", sock, knownHosts, nil, "remote", "add", "origin", "file://"+gitDir) + _, err = checkoutGit.Run(ctx, "remote", "add", "origin", "file://"+gitDir) if err != nil { return nil, err } - gitCatFileBuf, err := gitWithinDir(ctx, gitDir, "", sock, knownHosts, gs.auth, "cat-file", "-t", ref) + gitCatFileBuf, err := git.Run(ctx, "cat-file", "-t", ref) if err != nil { return nil, err } - isAnnotatedTag := strings.TrimSpace(gitCatFileBuf.String()) == "tag" + isAnnotatedTag := strings.TrimSpace(string(gitCatFileBuf)) == "tag" pullref := ref if isAnnotatedTag { pullref += ":refs/tags/" + pullref } else if isCommitSHA(ref) { pullref = "refs/buildkit/" + identity.NewID() - _, err = gitWithinDir(ctx, gitDir, "", sock, knownHosts, gs.auth, "update-ref", pullref, ref) + _, err = git.Run(ctx, "update-ref", pullref, ref) if err != nil { return nil, err } } else { pullref += ":" + pullref } - _, err = gitWithinDir(ctx, checkoutDirGit, "", sock, knownHosts, gs.auth, "fetch", "-u", "--depth=1", "origin", pullref) + _, err = checkoutGit.Run(ctx, "fetch", "-u", "--depth=1", "origin", pullref) if err != nil { return nil, err } - _, err = gitWithinDir(ctx, checkoutDirGit, checkoutDir, sock, knownHosts, nil, "checkout", "FETCH_HEAD") + _, err = checkoutGit.Run(ctx, "checkout", "FETCH_HEAD") if err != nil { return nil, errors.Wrapf(err, "failed to checkout remote %s", urlutil.RedactCredentials(gs.src.Remote)) } - _, err = gitWithinDir(ctx, checkoutDirGit, "", sock, knownHosts, nil, "remote", "set-url", "origin", urlutil.RedactCredentials(gs.src.Remote)) + _, err = checkoutGit.Run(ctx, "remote", "set-url", "origin", urlutil.RedactCredentials(gs.src.Remote)) if err != nil { return nil, errors.Wrapf(err, "failed to set remote origin to %s", urlutil.RedactCredentials(gs.src.Remote)) } - _, err = gitWithinDir(ctx, checkoutDirGit, "", sock, knownHosts, nil, "reflog", "expire", "--all", "--expire=now") + _, err = checkoutGit.Run(ctx, "reflog", "expire", "--all", "--expire=now") if err != nil { return nil, errors.Wrapf(err, "failed to expire reflog for remote %s", urlutil.RedactCredentials(gs.src.Remote)) } @@ -554,7 +588,8 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out return nil, errors.Wrapf(err, "failed to create temporary checkout dir") } } - _, err = gitWithinDir(ctx, gitDir, cd, sock, knownHosts, nil, "checkout", ref, "--", ".") + checkoutGit := git.New(gitutil.WithWorkTree(cd), gitutil.WithGitDir(gitDir)) + _, err = checkoutGit.Run(ctx, "checkout", ref, "--", ".") if err != nil { return nil, errors.Wrapf(err, "failed to checkout remote %s", urlutil.RedactCredentials(gs.src.Remote)) } @@ -587,7 +622,8 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out } } - _, err = gitWithinDir(ctx, gitDir, checkoutDir, sock, knownHosts, gs.auth, "submodule", "update", "--init", "--recursive", "--depth=1") + git = git.New(gitutil.WithWorkTree(checkoutDir), gitutil.WithGitDir(gitDir)) + _, err = git.Run(ctx, "submodule", "update", "--init", "--recursive", "--depth=1") if err != nil { return nil, errors.Wrapf(err, "failed to update submodules for %s", urlutil.RedactCredentials(gs.src.Remote)) } @@ -624,81 +660,60 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out return snap, nil } -func isCommitSHA(str string) bool { - return validHex.MatchString(str) -} - -func gitWithinDir(ctx context.Context, gitDir, workDir, sshAuthSock, knownHosts string, auth []string, args ...string) (*bytes.Buffer, error) { - a := append([]string{"--git-dir", gitDir}, auth...) - if workDir != "" { - a = append(a, "--work-tree", workDir) +func (gs *gitSourceHandler) gitCli(ctx context.Context, g session.Group, opts ...gitutil.Option) (*gitutil.GitCLI, func() error, error) { + var cleanups []func() error + cleanup := func() error { + var err error + for _, c := range cleanups { + if err1 := c(); err == nil { + err = err1 + } + } + cleanups = nil + return err } - return git(ctx, workDir, sshAuthSock, knownHosts, append(a, args...)...) -} + var err error -func getGitSSHCommand(knownHosts string) string { - gitSSHCommand := "ssh -F /dev/null" - if knownHosts != "" { - gitSSHCommand += " -o UserKnownHostsFile=" + knownHosts - } else { - gitSSHCommand += " -o StrictHostKeyChecking=no" + gitDir, unmountGitDir, err := gs.mountRemote(ctx, gs.src.Remote, gs.authArgs, g) + if err != nil { + cleanup() + return nil, nil, err } - return gitSSHCommand -} + cleanups = append(cleanups, unmountGitDir) -func git(ctx context.Context, dir, sshAuthSock, knownHosts string, args ...string) (_ *bytes.Buffer, err error) { - for { - stdout, stderr, flush := logs.NewLogStreams(ctx, false) - defer stdout.Close() - defer stderr.Close() - defer func() { - if err != nil { - flush() - } - }() - args = append([]string{"-c", "protocol.file.allow=user"}, args...) // Block sneaky repositories from using repos from the filesystem as submodules. - cmd := exec.Command("git", args...) - cmd.Dir = dir // some commands like submodule require this - buf := bytes.NewBuffer(nil) - errbuf := bytes.NewBuffer(nil) - cmd.Stdin = nil - cmd.Stdout = io.MultiWriter(stdout, buf) - cmd.Stderr = io.MultiWriter(stderr, errbuf) - cmd.Env = []string{ - "PATH=" + os.Getenv("PATH"), - "GIT_TERMINAL_PROMPT=0", - "GIT_SSH_COMMAND=" + getGitSSHCommand(knownHosts), - // "GIT_TRACE=1", - "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. - "HOME=/dev/null", // Disable reading from user gitconfig. - "LC_ALL=C", // Ensure consistent output. - } - if sshAuthSock != "" { - cmd.Env = append(cmd.Env, "SSH_AUTH_SOCK="+sshAuthSock) - } - // remote git commands spawn helper processes that inherit FDs and don't - // handle parent death signal so exec.CommandContext can't be used - err := runWithStandardUmask(ctx, cmd) + var sock string + if gs.src.MountSSHSock != "" { + var unmountSock func() error + sock, unmountSock, err = gs.mountSSHAuthSock(ctx, gs.src.MountSSHSock, g) if err != nil { - if strings.Contains(errbuf.String(), "--depth") || strings.Contains(errbuf.String(), "shallow") { - if newArgs := argsNoDepth(args); len(args) > len(newArgs) { - args = newArgs - continue - } - } + cleanup() + return nil, nil, err } - return buf, err + cleanups = append(cleanups, unmountSock) } -} -func argsNoDepth(args []string) []string { - out := make([]string, 0, len(args)) - for _, a := range args { - if a != "--depth=1" { - out = append(out, a) + var knownHosts string + if gs.src.KnownSSHHosts != "" { + var unmountKnownHosts func() error + knownHosts, unmountKnownHosts, err = gs.mountKnownHosts(ctx) + if err != nil { + cleanup() + return nil, nil, err } + cleanups = append(cleanups, unmountKnownHosts) } - return out + + opts = append([]gitutil.Option{ + gitutil.WithGitDir(gitDir), + gitutil.WithArgs(gs.authArgs...), + gitutil.WithSSHAuthSock(sock), + gitutil.WithSSHKnownHosts(knownHosts), + }, opts...) + return gitCLI(opts...), cleanup, err +} + +func isCommitSHA(str string) bool { + return validHex.MatchString(str) } func tokenScope(remote string) string { @@ -713,13 +728,13 @@ func tokenScope(remote string) string { } // getDefaultBranch gets the default branch of a repository using ls-remote -func getDefaultBranch(ctx context.Context, gitDir, workDir, sshAuthSock, knownHosts string, auth []string, remoteURL string) (string, error) { - buf, err := gitWithinDir(ctx, gitDir, workDir, sshAuthSock, knownHosts, auth, "ls-remote", "--symref", remoteURL, "HEAD") +func getDefaultBranch(ctx context.Context, git *gitutil.GitCLI, remoteURL string) (string, error) { + buf, err := git.Run(ctx, "ls-remote", "--symref", remoteURL, "HEAD") if err != nil { return "", errors.Wrapf(err, "error fetching default branch for repository %s", urlutil.RedactCredentials(remoteURL)) } - ss := defaultBranch.FindAllStringSubmatch(buf.String(), -1) + ss := defaultBranch.FindAllStringSubmatch(string(buf), -1) if len(ss) == 0 || len(ss[0]) != 2 { return "", errors.Errorf("could not find default branch for repository: %s", urlutil.RedactCredentials(remoteURL)) } @@ -762,3 +777,13 @@ func (md cacheRefMetadata) setGitSnapshot(key string) error { func (md cacheRefMetadata) setGitRemote(key string) error { return md.SetString(keyGitRemote, key, gitRemoteIndex+key) } + +func gitCLI(opts ...gitutil.Option) *gitutil.GitCLI { + opts = append([]gitutil.Option{ + gitutil.WithExec(runWithStandardUmask), + gitutil.WithStreams(func(ctx context.Context) (stdout, stderr io.WriteCloser, flush func()) { + return logs.NewLogStreams(ctx, false) + }), + }, opts...) + return gitutil.NewGitCLI(opts...) +} diff --git a/vendor/github.com/moby/buildkit/source/git/source_freebsd.go b/vendor/github.com/moby/buildkit/source/git/source_freebsd.go new file mode 100644 index 0000000000000..963946d5a306a --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/git/source_freebsd.go @@ -0,0 +1,100 @@ +package git + +import ( + "context" + "os" + "os/exec" + "os/signal" + "syscall" + "time" + + "github.com/docker/docker/pkg/reexec" + "golang.org/x/sys/unix" +) + +const ( + gitCmd = "umask-git" +) + +func init() { + reexec.Register(gitCmd, gitMain) +} + +func gitMain() { + // Need standard user umask for git process. + unix.Umask(0022) + + // Reexec git command + cmd := exec.Command(os.Args[1], os.Args[2:]...) //nolint:gosec // reexec + cmd.SysProcAttr = &unix.SysProcAttr{ + Setpgid: true, + Pdeathsig: unix.SIGTERM, + } + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + // Forward all signals + sigc := make(chan os.Signal, 1) + done := make(chan struct{}) + signal.Notify(sigc) + go func() { + for { + select { + case sig := <-sigc: + if cmd.Process == nil { + continue + } + switch sig { + case unix.SIGINT, unix.SIGTERM, unix.SIGKILL: + _ = unix.Kill(-cmd.Process.Pid, sig.(unix.Signal)) + default: + _ = cmd.Process.Signal(sig) + } + case <-done: + return + } + } + }() + + err := cmd.Run() + close(done) + if err != nil { + if exiterr, ok := err.(*exec.ExitError); ok { + switch status := exiterr.Sys().(type) { + case unix.WaitStatus: + os.Exit(status.ExitStatus()) + case syscall.WaitStatus: + os.Exit(status.ExitStatus()) + } + } + os.Exit(1) + } + os.Exit(0) +} + +func runWithStandardUmask(ctx context.Context, cmd *exec.Cmd) error { + cmd.Path = reexec.Self() + cmd.Args = append([]string{gitCmd}, cmd.Args...) + if err := cmd.Start(); err != nil { + return err + } + waitDone := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + _ = unix.Kill(-cmd.Process.Pid, unix.SIGTERM) + go func() { + select { + case <-waitDone: + case <-time.After(10 * time.Second): + _ = unix.Kill(-cmd.Process.Pid, unix.SIGKILL) + } + }() + case <-waitDone: + } + }() + err := cmd.Wait() + close(waitDone) + return err +} diff --git a/vendor/github.com/moby/buildkit/source/git/gitsource_unix.go b/vendor/github.com/moby/buildkit/source/git/source_unix.go similarity index 95% rename from vendor/github.com/moby/buildkit/source/git/gitsource_unix.go rename to vendor/github.com/moby/buildkit/source/git/source_unix.go index 142ae56091400..d6e15395b98e4 100644 --- a/vendor/github.com/moby/buildkit/source/git/gitsource_unix.go +++ b/vendor/github.com/moby/buildkit/source/git/source_unix.go @@ -1,5 +1,5 @@ -//go:build !windows -// +build !windows +//go:build !windows && !freebsd +// +build !windows,!freebsd package git diff --git a/vendor/github.com/moby/buildkit/source/git/gitsource_windows.go b/vendor/github.com/moby/buildkit/source/git/source_windows.go similarity index 100% rename from vendor/github.com/moby/buildkit/source/git/gitsource_windows.go rename to vendor/github.com/moby/buildkit/source/git/source_windows.go diff --git a/vendor/github.com/moby/buildkit/source/gitidentifier.go b/vendor/github.com/moby/buildkit/source/gitidentifier.go deleted file mode 100644 index 6055c94e2f9b6..0000000000000 --- a/vendor/github.com/moby/buildkit/source/gitidentifier.go +++ /dev/null @@ -1,76 +0,0 @@ -package source - -import ( - "net/url" - "path" - "strings" - - srctypes "github.com/moby/buildkit/source/types" - "github.com/moby/buildkit/util/sshutil" -) - -type GitIdentifier struct { - Remote string - Ref string - Subdir string - KeepGitDir bool - AuthTokenSecret string - AuthHeaderSecret string - MountSSHSock string - KnownSSHHosts string -} - -func NewGitIdentifier(remoteURL string) (*GitIdentifier, error) { - repo := GitIdentifier{} - - if !isGitTransport(remoteURL) { - remoteURL = "https://" + remoteURL - } - - var fragment string - if sshutil.IsImplicitSSHTransport(remoteURL) { - // implicit ssh urls such as "git@.." are not actually a URL, so cannot be parsed as URL - parts := strings.SplitN(remoteURL, "#", 2) - - repo.Remote = parts[0] - if len(parts) == 2 { - fragment = parts[1] - } - repo.Ref, repo.Subdir = getRefAndSubdir(fragment) - } else { - u, err := url.Parse(remoteURL) - if err != nil { - return nil, err - } - - repo.Ref, repo.Subdir = getRefAndSubdir(u.Fragment) - u.Fragment = "" - repo.Remote = u.String() - } - if sd := path.Clean(repo.Subdir); sd == "/" || sd == "." { - repo.Subdir = "" - } - return &repo, nil -} - -func (i *GitIdentifier) ID() string { - return srctypes.GitScheme -} - -// isGitTransport returns true if the provided str is a git transport by inspecting -// the prefix of the string for known protocols used in git. -func isGitTransport(str string) bool { - return strings.HasPrefix(str, "http://") || strings.HasPrefix(str, "https://") || strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "ssh://") || sshutil.IsImplicitSSHTransport(str) -} - -func getRefAndSubdir(fragment string) (ref string, subdir string) { - refAndDir := strings.SplitN(fragment, ":", 2) - ref = "" - if len(refAndDir[0]) != 0 { - ref = refAndDir[0] - } - if len(refAndDir) > 1 && len(refAndDir[1]) != 0 { - subdir = refAndDir[1] - } - return -} diff --git a/vendor/github.com/moby/buildkit/source/http/identifier.go b/vendor/github.com/moby/buildkit/source/http/identifier.go new file mode 100644 index 0000000000000..f560321047fa1 --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/http/identifier.go @@ -0,0 +1,48 @@ +package http + +import ( + "github.com/moby/buildkit/solver/llbsolver/provenance" + "github.com/moby/buildkit/source" + srctypes "github.com/moby/buildkit/source/types" + digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +func NewHTTPIdentifier(str string, tls bool) (*HTTPIdentifier, error) { + proto := "https://" + if !tls { + proto = "http://" + } + return &HTTPIdentifier{TLS: tls, URL: proto + str}, nil +} + +type HTTPIdentifier struct { + TLS bool + URL string + Checksum digest.Digest + Filename string + Perm int + UID int + GID int +} + +var _ source.Identifier = (*HTTPIdentifier)(nil) + +func (id *HTTPIdentifier) Scheme() string { + if id.TLS { + return srctypes.HTTPSScheme + } + return srctypes.HTTPScheme +} + +func (id *HTTPIdentifier) Capture(c *provenance.Capture, pin string) error { + dgst, err := digest.Parse(pin) + if err != nil { + return errors.Wrapf(err, "failed to parse HTTP digest %s", pin) + } + c.AddHTTP(provenance.HTTPSource{ + URL: id.URL, + Digest: dgst, + }) + return nil +} diff --git a/vendor/github.com/moby/buildkit/source/http/httpsource.go b/vendor/github.com/moby/buildkit/source/http/source.go similarity index 91% rename from vendor/github.com/moby/buildkit/source/http/httpsource.go rename to vendor/github.com/moby/buildkit/source/http/source.go index 8e233228f8de8..5369eac3a4968 100644 --- a/vendor/github.com/moby/buildkit/source/http/httpsource.go +++ b/vendor/github.com/moby/buildkit/source/http/source.go @@ -12,6 +12,7 @@ import ( "os" "path" "path/filepath" + "strconv" "strings" "time" @@ -20,10 +21,10 @@ import ( "github.com/moby/buildkit/session" "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/source" srctypes "github.com/moby/buildkit/source/types" "github.com/moby/buildkit/util/tracing" - "github.com/moby/locker" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" ) @@ -35,7 +36,6 @@ type Opt struct { type httpSource struct { cache cache.Accessor - locker *locker.Locker transport http.RoundTripper } @@ -46,26 +46,65 @@ func NewSource(opt Opt) (source.Source, error) { } hs := &httpSource{ cache: opt.CacheAccessor, - locker: locker.New(), transport: transport, } return hs, nil } -func (hs *httpSource) ID() string { - return srctypes.HTTPSScheme +func (hs *httpSource) Schemes() []string { + return []string{srctypes.HTTPScheme, srctypes.HTTPSScheme} +} + +func (hs *httpSource) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := NewHTTPIdentifier(ref, scheme == "https") + if err != nil { + return nil, err + } + + for k, v := range attrs { + switch k { + case pb.AttrHTTPChecksum: + dgst, err := digest.Parse(v) + if err != nil { + return nil, err + } + id.Checksum = dgst + case pb.AttrHTTPFilename: + id.Filename = v + case pb.AttrHTTPPerm: + i, err := strconv.ParseInt(v, 0, 64) + if err != nil { + return nil, err + } + id.Perm = int(i) + case pb.AttrHTTPUID: + i, err := strconv.ParseInt(v, 0, 64) + if err != nil { + return nil, err + } + id.UID = int(i) + case pb.AttrHTTPGID: + i, err := strconv.ParseInt(v, 0, 64) + if err != nil { + return nil, err + } + id.GID = int(i) + } + } + + return id, nil } type httpSourceHandler struct { *httpSource - src source.HTTPIdentifier + src HTTPIdentifier refID string cacheKey digest.Digest sm *session.Manager } func (hs *httpSource) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, _ solver.Vertex) (source.SourceInstance, error) { - httpIdentifier, ok := id.(*source.HTTPIdentifier) + httpIdentifier, ok := id.(*HTTPIdentifier) if !ok { return nil, errors.Errorf("invalid http identifier %v", id) } diff --git a/vendor/github.com/moby/buildkit/source/identifier.go b/vendor/github.com/moby/buildkit/source/identifier.go index aad9f226ff6e2..f591e9e34e32e 100644 --- a/vendor/github.com/moby/buildkit/source/identifier.go +++ b/vendor/github.com/moby/buildkit/source/identifier.go @@ -1,18 +1,8 @@ package source import ( - "encoding/json" - "strconv" - "strings" - - "github.com/containerd/containerd/reference" - "github.com/moby/buildkit/client" - "github.com/moby/buildkit/solver/pb" - srctypes "github.com/moby/buildkit/source/types" - digest "github.com/opencontainers/go-digest" - ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/moby/buildkit/solver/llbsolver/provenance" "github.com/pkg/errors" - "github.com/tonistiigi/fsutil" ) var ( @@ -20,333 +10,11 @@ var ( errNotFound = errors.New("not found") ) -type ResolveMode int - -const ( - ResolveModeDefault ResolveMode = iota - ResolveModeForcePull - ResolveModePreferLocal -) - type Identifier interface { - ID() string // until sources are in process this string comparison could be avoided -} - -func FromString(s string) (Identifier, error) { - // TODO: improve this - parts := strings.SplitN(s, "://", 2) - if len(parts) != 2 { - return nil, errors.Wrapf(errInvalid, "failed to parse %s", s) - } - - switch parts[0] { - case srctypes.DockerImageScheme: - return NewImageIdentifier(parts[1]) - case srctypes.GitScheme: - return NewGitIdentifier(parts[1]) - case srctypes.LocalScheme: - return NewLocalIdentifier(parts[1]) - case srctypes.HTTPSScheme: - return NewHTTPIdentifier(parts[1], true) - case srctypes.HTTPScheme: - return NewHTTPIdentifier(parts[1], false) - case srctypes.OCIScheme: - return NewOCIIdentifier(parts[1]) - default: - return nil, errors.Wrapf(errNotFound, "unknown schema %s", parts[0]) - } -} - -func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) { - id, err := FromString(op.Source.Identifier) - if err != nil { - return nil, err - } - - if id, ok := id.(*ImageIdentifier); ok { - if platform != nil { - id.Platform = &ocispecs.Platform{ - OS: platform.OS, - Architecture: platform.Architecture, - Variant: platform.Variant, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - } - } - for k, v := range op.Source.Attrs { - switch k { - case pb.AttrImageResolveMode: - rm, err := ParseImageResolveMode(v) - if err != nil { - return nil, err - } - id.ResolveMode = rm - case pb.AttrImageRecordType: - rt, err := parseImageRecordType(v) - if err != nil { - return nil, err - } - id.RecordType = rt - case pb.AttrImageLayerLimit: - l, err := strconv.Atoi(v) - if err != nil { - return nil, errors.Wrapf(err, "invalid layer limit %s", v) - } - if l <= 0 { - return nil, errors.Errorf("invalid layer limit %s", v) - } - id.LayerLimit = &l - } - } - } - if id, ok := id.(*GitIdentifier); ok { - for k, v := range op.Source.Attrs { - switch k { - case pb.AttrKeepGitDir: - if v == "true" { - id.KeepGitDir = true - } - case pb.AttrFullRemoteURL: - if !isGitTransport(v) { - v = "https://" + v - } - id.Remote = v - case pb.AttrAuthHeaderSecret: - id.AuthHeaderSecret = v - case pb.AttrAuthTokenSecret: - id.AuthTokenSecret = v - case pb.AttrKnownSSHHosts: - id.KnownSSHHosts = v - case pb.AttrMountSSHSock: - id.MountSSHSock = v - } - } - } - if id, ok := id.(*LocalIdentifier); ok { - for k, v := range op.Source.Attrs { - switch k { - case pb.AttrLocalSessionID: - id.SessionID = v - if p := strings.SplitN(v, ":", 2); len(p) == 2 { - id.Name = p[0] + "-" + id.Name - id.SessionID = p[1] - } - case pb.AttrIncludePatterns: - var patterns []string - if err := json.Unmarshal([]byte(v), &patterns); err != nil { - return nil, err - } - id.IncludePatterns = patterns - case pb.AttrExcludePatterns: - var patterns []string - if err := json.Unmarshal([]byte(v), &patterns); err != nil { - return nil, err - } - id.ExcludePatterns = patterns - case pb.AttrFollowPaths: - var paths []string - if err := json.Unmarshal([]byte(v), &paths); err != nil { - return nil, err - } - id.FollowPaths = paths - case pb.AttrSharedKeyHint: - id.SharedKeyHint = v - case pb.AttrLocalDiffer: - switch v { - case pb.AttrLocalDifferMetadata, "": - id.Differ = fsutil.DiffMetadata - case pb.AttrLocalDifferNone: - id.Differ = fsutil.DiffNone - } - } - } - } - if id, ok := id.(*HTTPIdentifier); ok { - for k, v := range op.Source.Attrs { - switch k { - case pb.AttrHTTPChecksum: - dgst, err := digest.Parse(v) - if err != nil { - return nil, err - } - id.Checksum = dgst - case pb.AttrHTTPFilename: - id.Filename = v - case pb.AttrHTTPPerm: - i, err := strconv.ParseInt(v, 0, 64) - if err != nil { - return nil, err - } - id.Perm = int(i) - case pb.AttrHTTPUID: - i, err := strconv.ParseInt(v, 0, 64) - if err != nil { - return nil, err - } - id.UID = int(i) - case pb.AttrHTTPGID: - i, err := strconv.ParseInt(v, 0, 64) - if err != nil { - return nil, err - } - id.GID = int(i) - } - } - } - if id, ok := id.(*OCIIdentifier); ok { - if platform != nil { - id.Platform = &ocispecs.Platform{ - OS: platform.OS, - Architecture: platform.Architecture, - Variant: platform.Variant, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - } - } - for k, v := range op.Source.Attrs { - switch k { - case pb.AttrOCILayoutSessionID: - id.SessionID = v - case pb.AttrOCILayoutStoreID: - id.StoreID = v - case pb.AttrOCILayoutLayerLimit: - l, err := strconv.Atoi(v) - if err != nil { - return nil, errors.Wrapf(err, "invalid layer limit %s", v) - } - if l <= 0 { - return nil, errors.Errorf("invalid layer limit %s", v) - } - id.LayerLimit = &l - } - } - } - return id, nil -} - -type ImageIdentifier struct { - Reference reference.Spec - Platform *ocispecs.Platform - ResolveMode ResolveMode - RecordType client.UsageRecordType - LayerLimit *int -} - -func NewImageIdentifier(str string) (*ImageIdentifier, error) { - ref, err := reference.Parse(str) - if err != nil { - return nil, errors.WithStack(err) - } - - if ref.Object == "" { - return nil, errors.WithStack(reference.ErrObjectRequired) - } - return &ImageIdentifier{Reference: ref}, nil -} - -func (*ImageIdentifier) ID() string { - return srctypes.DockerImageScheme -} - -type LocalIdentifier struct { - Name string - SessionID string - IncludePatterns []string - ExcludePatterns []string - FollowPaths []string - SharedKeyHint string - Differ fsutil.DiffType -} - -func NewLocalIdentifier(str string) (*LocalIdentifier, error) { - return &LocalIdentifier{Name: str}, nil -} - -func (*LocalIdentifier) ID() string { - return srctypes.LocalScheme -} - -func NewHTTPIdentifier(str string, tls bool) (*HTTPIdentifier, error) { - proto := "https://" - if !tls { - proto = "http://" - } - return &HTTPIdentifier{TLS: tls, URL: proto + str}, nil -} - -type HTTPIdentifier struct { - TLS bool - URL string - Checksum digest.Digest - Filename string - Perm int - UID int - GID int -} - -func (*HTTPIdentifier) ID() string { - return srctypes.HTTPSScheme -} - -type OCIIdentifier struct { - Reference reference.Spec - Platform *ocispecs.Platform - SessionID string - StoreID string - LayerLimit *int -} - -func NewOCIIdentifier(str string) (*OCIIdentifier, error) { - ref, err := reference.Parse(str) - if err != nil { - return nil, errors.WithStack(err) - } - - if ref.Object == "" { - return nil, errors.WithStack(reference.ErrObjectRequired) - } - return &OCIIdentifier{Reference: ref}, nil -} - -func (*OCIIdentifier) ID() string { - return srctypes.OCIScheme -} - -func (r ResolveMode) String() string { - switch r { - case ResolveModeDefault: - return pb.AttrImageResolveModeDefault - case ResolveModeForcePull: - return pb.AttrImageResolveModeForcePull - case ResolveModePreferLocal: - return pb.AttrImageResolveModePreferLocal - default: - return "" - } -} - -func ParseImageResolveMode(v string) (ResolveMode, error) { - switch v { - case pb.AttrImageResolveModeDefault, "": - return ResolveModeDefault, nil - case pb.AttrImageResolveModeForcePull: - return ResolveModeForcePull, nil - case pb.AttrImageResolveModePreferLocal: - return ResolveModePreferLocal, nil - default: - return 0, errors.Errorf("invalid resolvemode: %s", v) - } -} + // Scheme returns the scheme of the identifier so that it can be routed back + // to an appropriate Source. + Scheme() string -func parseImageRecordType(v string) (client.UsageRecordType, error) { - switch client.UsageRecordType(v) { - case "", client.UsageRecordTypeRegular: - return client.UsageRecordTypeRegular, nil - case client.UsageRecordTypeInternal: - return client.UsageRecordTypeInternal, nil - case client.UsageRecordTypeFrontend: - return client.UsageRecordTypeFrontend, nil - default: - return "", errors.Errorf("invalid record type %s", v) - } + // Capture records the provenance of the identifier. + Capture(dest *provenance.Capture, pin string) error } diff --git a/vendor/github.com/moby/buildkit/source/local/identifier.go b/vendor/github.com/moby/buildkit/source/local/identifier.go new file mode 100644 index 0000000000000..703d66890fc35 --- /dev/null +++ b/vendor/github.com/moby/buildkit/source/local/identifier.go @@ -0,0 +1,35 @@ +package local + +import ( + "github.com/moby/buildkit/solver/llbsolver/provenance" + "github.com/moby/buildkit/source" + srctypes "github.com/moby/buildkit/source/types" + "github.com/tonistiigi/fsutil" +) + +type LocalIdentifier struct { + Name string + SessionID string + IncludePatterns []string + ExcludePatterns []string + FollowPaths []string + SharedKeyHint string + Differ fsutil.DiffType +} + +func NewLocalIdentifier(str string) (*LocalIdentifier, error) { + return &LocalIdentifier{Name: str}, nil +} + +func (*LocalIdentifier) Scheme() string { + return srctypes.LocalScheme +} + +var _ source.Identifier = (*LocalIdentifier)(nil) + +func (id *LocalIdentifier) Capture(c *provenance.Capture, pin string) error { + c.AddLocal(provenance.LocalSource{ + Name: id.Name, + }) + return nil +} diff --git a/vendor/github.com/moby/buildkit/source/local/local.go b/vendor/github.com/moby/buildkit/source/local/source.go similarity index 78% rename from vendor/github.com/moby/buildkit/source/local/local.go rename to vendor/github.com/moby/buildkit/source/local/source.go index d2cd9d989c18e..7afcbb1c562ba 100644 --- a/vendor/github.com/moby/buildkit/source/local/local.go +++ b/vendor/github.com/moby/buildkit/source/local/source.go @@ -4,8 +4,10 @@ import ( "context" "encoding/json" "fmt" + "strings" "time" + "github.com/moby/buildkit/solver/pb" srctypes "github.com/moby/buildkit/source/types" "github.com/moby/buildkit/util/bklog" @@ -41,12 +43,59 @@ type localSource struct { cm cache.Accessor } -func (ls *localSource) ID() string { - return srctypes.LocalScheme +func (ls *localSource) Schemes() []string { + return []string{srctypes.LocalScheme} +} + +func (ls *localSource) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) { + id, err := NewLocalIdentifier(ref) + if err != nil { + return nil, err + } + + for k, v := range attrs { + switch k { + case pb.AttrLocalSessionID: + id.SessionID = v + if p := strings.SplitN(v, ":", 2); len(p) == 2 { + id.Name = p[0] + "-" + id.Name + id.SessionID = p[1] + } + case pb.AttrIncludePatterns: + var patterns []string + if err := json.Unmarshal([]byte(v), &patterns); err != nil { + return nil, err + } + id.IncludePatterns = patterns + case pb.AttrExcludePatterns: + var patterns []string + if err := json.Unmarshal([]byte(v), &patterns); err != nil { + return nil, err + } + id.ExcludePatterns = patterns + case pb.AttrFollowPaths: + var paths []string + if err := json.Unmarshal([]byte(v), &paths); err != nil { + return nil, err + } + id.FollowPaths = paths + case pb.AttrSharedKeyHint: + id.SharedKeyHint = v + case pb.AttrLocalDiffer: + switch v { + case pb.AttrLocalDifferMetadata, "": + id.Differ = fsutil.DiffMetadata + case pb.AttrLocalDifferNone: + id.Differ = fsutil.DiffNone + } + } + } + + return id, nil } func (ls *localSource) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, _ solver.Vertex) (source.SourceInstance, error) { - localIdentifier, ok := id.(*source.LocalIdentifier) + localIdentifier, ok := id.(*LocalIdentifier) if !ok { return nil, errors.Errorf("invalid local identifier %v", id) } @@ -59,7 +108,7 @@ func (ls *localSource) Resolve(ctx context.Context, id source.Identifier, sm *se } type localSourceHandler struct { - src source.LocalIdentifier + src LocalIdentifier sm *session.Manager *localSource } @@ -92,8 +141,9 @@ func (ls *localSourceHandler) Snapshot(ctx context.Context, g session.Group) (ca return ls.snapshotWithAnySession(ctx, g) } - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() + timeoutCtx, cancel := context.WithCancelCause(ctx) + timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 5*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer cancel(errors.WithStack(context.Canceled)) caller, err := ls.sm.Get(timeoutCtx, sessionID, false) if err != nil { @@ -186,15 +236,14 @@ func (ls *localSourceHandler) snapshot(ctx context.Context, caller session.Calle } opt := filesync.FSSendRequestOpt{ - Name: ls.src.Name, - IncludePatterns: ls.src.IncludePatterns, - ExcludePatterns: ls.src.ExcludePatterns, - FollowPaths: ls.src.FollowPaths, - OverrideExcludes: false, - DestDir: dest, - CacheUpdater: &cacheUpdater{cc, mount.IdentityMapping()}, - ProgressCb: newProgressHandler(ctx, "transferring "+ls.src.Name+":"), - Differ: ls.src.Differ, + Name: ls.src.Name, + IncludePatterns: ls.src.IncludePatterns, + ExcludePatterns: ls.src.ExcludePatterns, + FollowPaths: ls.src.FollowPaths, + DestDir: dest, + CacheUpdater: &cacheUpdater{cc, mount.IdentityMapping()}, + ProgressCb: newProgressHandler(ctx, "transferring "+ls.src.Name+":"), + Differ: ls.src.Differ, } if idmap := mount.IdentityMapping(); idmap != nil { diff --git a/vendor/github.com/moby/buildkit/source/manager.go b/vendor/github.com/moby/buildkit/source/manager.go index 6a9c831c90482..d0d245d2f49e5 100644 --- a/vendor/github.com/moby/buildkit/source/manager.go +++ b/vendor/github.com/moby/buildkit/source/manager.go @@ -2,48 +2,83 @@ package source import ( "context" + "strings" "sync" "github.com/moby/buildkit/cache" "github.com/moby/buildkit/session" "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/pb" "github.com/pkg/errors" ) +// Source implementations provide "root" vertices in the graph that can be +// constructed from a URI-like string and arbitrary attrs. type Source interface { - ID() string + // Schemes returns a list of SourceOp identifier schemes that this source + // should match. + Schemes() []string + + // Identifier constructs an Identifier from the given scheme, ref, and attrs, + // all of which come from a SourceOp. + Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (Identifier, error) + + // Resolve constructs an instance of the source from an Identifier. Resolve(ctx context.Context, id Identifier, sm *session.Manager, vtx solver.Vertex) (SourceInstance, error) } +// SourceInstance represents a cacheable vertex created by a Source. type SourceInstance interface { + // CacheKey returns the cache key for the instance. CacheKey(ctx context.Context, g session.Group, index int) (key, pin string, opts solver.CacheOpts, done bool, err error) + + // Snapshot creates a cache ref for the instance. May return a nil ref if source points to empty content, e.g. image without any layers. Snapshot(ctx context.Context, g session.Group) (cache.ImmutableRef, error) } type Manager struct { mu sync.Mutex - sources map[string]Source + schemes map[string]Source } func NewManager() (*Manager, error) { return &Manager{ - sources: make(map[string]Source), + schemes: make(map[string]Source), }, nil } func (sm *Manager) Register(src Source) { sm.mu.Lock() - sm.sources[src.ID()] = src + for _, scheme := range src.Schemes() { + sm.schemes[scheme] = src + } + sm.mu.Unlock() +} + +func (sm *Manager) Identifier(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) { + scheme, ref, ok := strings.Cut(op.Source.Identifier, "://") + if !ok { + return nil, errors.Wrapf(errInvalid, "failed to parse %s", op.Source.Identifier) + } + + sm.mu.Lock() + source, found := sm.schemes[scheme] sm.mu.Unlock() + + if !found { + return nil, errors.Wrapf(errNotFound, "unknown scheme %s", scheme) + } + + return source.Identifier(scheme, ref, op.Source.Attrs, platform) } func (sm *Manager) Resolve(ctx context.Context, id Identifier, sessM *session.Manager, vtx solver.Vertex) (SourceInstance, error) { sm.mu.Lock() - src, ok := sm.sources[id.ID()] + src, ok := sm.schemes[id.Scheme()] sm.mu.Unlock() if !ok { - return nil, errors.Errorf("no handler for %s", id.ID()) + return nil, errors.Errorf("no handler for %s", id.Scheme()) } return src.Resolve(ctx, id, sessM, vtx) diff --git a/vendor/github.com/moby/buildkit/sourcepolicy/engine.go b/vendor/github.com/moby/buildkit/sourcepolicy/engine.go index 8515b276a416c..3b7cbddfdb30d 100644 --- a/vendor/github.com/moby/buildkit/sourcepolicy/engine.go +++ b/vendor/github.com/moby/buildkit/sourcepolicy/engine.go @@ -61,8 +61,8 @@ func (e *Engine) selectorCache(src *spb.Selector) *selectorCache { // This function may error out even if the op was mutated, in which case `true` will be returned along with the error. // // An error is returned when the source is denied by the policy. -func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) { - if len(e.pol) == 0 { +func (e *Engine) Evaluate(ctx context.Context, op *pb.SourceOp) (bool, error) { + if len(e.pol) == 0 || op == nil { return false, nil } @@ -74,15 +74,13 @@ func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) { return mutated, errors.Wrapf(ErrTooManyOps, "too many mutations on a single source") } - srcOp := op.GetSource() - if srcOp == nil { - return false, nil - } if i == 0 { - ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("orig", *srcOp).WithField("updated", op.GetSource())) + ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("orig", *op)) + } else { + ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("updated", *op)) } - mut, err := e.evaluatePolicies(ctx, srcOp) + mut, err := e.evaluatePolicies(ctx, op) if mut { mutated = true } diff --git a/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults.go b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults.go new file mode 100644 index 0000000000000..d4b6258caa29b --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults.go @@ -0,0 +1,6 @@ +package appdefaults + +const ( + BridgeName = "buildkit0" + BridgeSubnet = "10.10.0.0/16" +) diff --git a/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_unix.go b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_unix.go index 0084280c28561..618288dce07c3 100644 --- a/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_unix.go +++ b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_unix.go @@ -17,6 +17,10 @@ const ( DefaultCNIConfigPath = "/etc/buildkit/cni.json" ) +var ( + UserCNIConfigPath = filepath.Join(UserConfigDir(), "cni.json") +) + // UserAddress typically returns /run/user/$UID/buildkit/buildkitd.sock func UserAddress() string { // pam_systemd sets XDG_RUNTIME_DIR but not other dirs. @@ -70,3 +74,13 @@ func UserConfigDir() string { } return ConfigDir } + +func TraceSocketPath(inUserNS bool) string { + if inUserNS { + if xrd := os.Getenv("XDG_RUNTIME_DIR"); xrd != "" { + dirs := strings.Split(xrd, ":") + return filepath.Join(dirs[0], "buildkit", "otel-grpc.sock") + } + } + return "/run/buildkit/otel-grpc.sock" +} diff --git a/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_windows.go b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_windows.go index 058789e48aa09..323c8a98abf9c 100644 --- a/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_windows.go +++ b/vendor/github.com/moby/buildkit/util/appdefaults/appdefaults_windows.go @@ -16,6 +16,10 @@ var ( DefaultCNIConfigPath = filepath.Join(ConfigDir, "cni.json") ) +var ( + UserCNIConfigPath = DefaultCNIConfigPath +) + func UserAddress() string { return Address } @@ -31,3 +35,7 @@ func UserRoot() string { func UserConfigDir() string { return ConfigDir } + +func TraceSocketPath(inUserNS bool) string { + return `\\.\pipe\buildkit-otel-grpc` +} diff --git a/vendor/github.com/moby/buildkit/util/archutil/386_binary.go b/vendor/github.com/moby/buildkit/util/archutil/386_binary.go index 0309e1520f506..8f06a84eb1535 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/386_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/386_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binary386 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x64\x64\x64\x80\x01\x26\x06\x66\x06\x30\x6f\x02\x0b\x87\x09\x03\x03\x83\x8c\x00\x44\xdc\x84\x41\x81\x81\x99\x41\x83\x81\x99\x81\x89\x01\xae\xba\x81\x85\x03\x84\xa7\x30\x30\x30\x80\x30\x0b\x48\x4c\x80\x01\x22\x2f\x00\x31\x03\x84\x39\x19\x18\x18\x40\x98\x15\x2a\x1e\xf8\xb4\x24\x85\x01\x0b\x60\x83\x6a\x1b\x05\xa3\x60\x14\x8c\x82\x51\x30\x0a\x46\xc1\x28\x18\x05\xa3\x60\x14\x8c\x82\x51\x30\x0a\x46\x01\x75\xc1\x0e\x50\x67\xdd\xf0\xf6\xd9\x06\x06\xbd\xe2\x8c\xe2\x92\xa2\x92\xc4\x24\x06\xbd\x92\xd4\x8a\x12\x12\xcc\xe0\x66\x80\xf4\xf9\xd9\xa0\xe3\x06\xa0\x4e\x3c\x27\x92\x3c\x23\x12\xcd\x8c\x24\xce\x29\xc0\xc0\x20\x88\x45\x1d\x20\x00\x00\xff\xff\x3d\x67\xa6\x38\x94\x10\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/Dockerfile b/vendor/github.com/moby/buildkit/util/archutil/Dockerfile deleted file mode 100644 index 2b24b230b385b..0000000000000 --- a/vendor/github.com/moby/buildkit/util/archutil/Dockerfile +++ /dev/null @@ -1,73 +0,0 @@ -FROM debian:bullseye-slim AS base -RUN apt-get update && apt-get --no-install-recommends install -y \ - gcc-x86-64-linux-gnu \ - binutils-arm-linux-gnueabihf \ - binutils-aarch64-linux-gnu \ - binutils-i686-linux-gnu \ - binutils-riscv64-linux-gnu \ - binutils-s390x-linux-gnu \ - binutils-powerpc64le-linux-gnu \ - binutils-mips64el-linux-gnuabi64 \ - binutils-mips64-linux-gnuabi64 -WORKDIR /src - - -FROM base AS exit-amd64 -COPY fixtures/exit.amd64.S . -RUN x86_64-linux-gnu-gcc -static -nostdlib -o exit exit.amd64.S - -FROM base AS exit-386 -COPY fixtures/exit.386.s . -RUN i686-linux-gnu-as --noexecstack -o exit.o exit.386.s && i686-linux-gnu-ld -o exit -s exit.o - -FROM base AS exit-arm64 -COPY fixtures/exit.arm64.s . -RUN aarch64-linux-gnu-as --noexecstack -o exit.o exit.arm64.s && aarch64-linux-gnu-ld -o exit -s exit.o - -FROM base AS exit-arm -COPY fixtures/exit.arm.s . -RUN arm-linux-gnueabihf-as --noexecstack -o exit.o exit.arm.s && arm-linux-gnueabihf-ld -o exit -s exit.o - -FROM base AS exit-riscv64 -COPY fixtures/exit.riscv64.s . -RUN riscv64-linux-gnu-as --noexecstack -o exit.o exit.riscv64.s && riscv64-linux-gnu-ld -o exit -s exit.o - -FROM base AS exit-s390x -COPY fixtures/exit.s390x.s . -RUN s390x-linux-gnu-as --noexecstack -o exit.o exit.s390x.s && s390x-linux-gnu-ld -o exit -s exit.o - -FROM base AS exit-ppc64 -COPY fixtures/exit.ppc64.s . -RUN powerpc64le-linux-gnu-as -mbig --noexecstack -o exit.o exit.ppc64.s && powerpc64le-linux-gnu-ld -EB -o exit -s exit.o - -FROM base AS exit-ppc64le -COPY fixtures/exit.ppc64le.s . -RUN powerpc64le-linux-gnu-as --noexecstack -o exit.o exit.ppc64le.s && powerpc64le-linux-gnu-ld -o exit -s exit.o - -FROM base AS exit-mips64le -COPY fixtures/exit.mips64le.s . -RUN mips64el-linux-gnuabi64-as --noexecstack -o exit.o exit.mips64le.s && mips64el-linux-gnuabi64-ld -o exit -s exit.o - -FROM base AS exit-mips64 -COPY fixtures/exit.mips64.s . -RUN mips64-linux-gnuabi64-as --noexecstack -o exit.o exit.mips64.s && mips64-linux-gnuabi64-ld -o exit -s exit.o - -FROM golang:1.20-alpine AS generate -WORKDIR /src -COPY --from=exit-amd64 /src/exit amd64 -COPY --from=exit-386 /src/exit 386 -COPY --from=exit-arm64 /src/exit arm64 -COPY --from=exit-arm /src/exit arm -COPY --from=exit-riscv64 /src/exit riscv64 -COPY --from=exit-s390x /src/exit s390x -COPY --from=exit-ppc64 /src/exit ppc64 -COPY --from=exit-ppc64le /src/exit ppc64le -COPY --from=exit-mips64le /src/exit mips64le -COPY --from=exit-mips64 /src/exit mips64 -COPY generate.go . - -RUN go run generate.go amd64 386 arm64 arm riscv64 s390x ppc64 ppc64le mips64le mips64 && ls -l - - -FROM scratch -COPY --from=generate /src/*_binary.go / diff --git a/vendor/github.com/moby/buildkit/util/archutil/Makefile b/vendor/github.com/moby/buildkit/util/archutil/Makefile deleted file mode 100644 index e1cac26a291bf..0000000000000 --- a/vendor/github.com/moby/buildkit/util/archutil/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -generate: - DOCKER_BUILDKIT=1 docker build -o . . - -.PHONY: generate diff --git a/vendor/github.com/moby/buildkit/util/archutil/amd64_binary.go b/vendor/github.com/moby/buildkit/util/archutil/amd64_binary.go index 29aaba1537c34..0ecf8fc5106fc 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/amd64_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/amd64_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. -const Binaryamd64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x98\x3f\x8b\x13\x41\x18\xc6\x9f\xd9\x6c\xee\x0f\x08\xb9\xe0\x81\xc2\x59\xa8\x58\xd8\xb8\xe1\x54\x38\x05\x95\x55\x50\x07\xf1\xec\xce\xd2\x65\x93\x5d\xce\x80\x97\x5b\xb2\xb3\xe7\x0a\x07\x77\x47\xbe\x83\x58\x07\x14\x0b\x4b\xc1\x94\xa9\x5c\x2c\x6d\xac\x4d\x21\x04\xad\xec\x0c\x28\xca\x6e\xde\x49\xb2\x63\xa2\x82\xdd\x31\x3f\x08\xcf\xbc\xcf\xbe\x33\xef\x90\xa4\xd9\x67\xef\xe6\xdd\x5b\x06\x63\x90\x18\xb8\x86\xac\x5a\xb2\xb3\xda\x26\xff\x63\x79\xd4\x02\x1b\x97\x50\x80\x8d\x39\x14\xb3\x5e\x13\x93\xd8\x39\x3d\x42\x47\x4b\xc5\xd2\x50\xd2\xb2\x38\x51\xcb\x79\x52\x03\xb2\xa5\xca\x3e\x93\x3e\x7d\xb2\xfb\x34\x47\xea\x19\xf2\xa5\x9a\x13\xba\x0c\xa0\x00\xe0\xf6\xbd\x0d\xf8\xcf\xdf\x5c\xfe\xf0\xf2\xd3\xfd\xf5\x1f\x4f\x8f\x7e\x7f\xf1\x79\xef\xed\x85\xf7\xaf\xa1\xd1\x68\x34\x1a\x8d\x46\xa3\xd1\x68\x34\x1a\xcd\x21\x85\xaf\x76\x4b\x6d\xde\xfa\x36\xbf\x7b\x87\x77\x00\xec\xa7\x66\xa9\x7d\x95\x01\xfb\xbb\x6b\x3c\xe9\xb2\xac\xe9\x5d\xa9\xcd\x0f\x7a\xec\xf4\x33\xf0\x83\x41\x2a\xd1\x0a\xef\x30\x6a\x1f\x3e\x6e\xf5\x18\x6f\x0d\x58\x64\x7c\x59\xe4\x49\x72\x1d\x40\xb6\xb8\x91\x2e\xc0\x93\xee\x95\xf4\xe0\xe2\x9f\xee\x52\x00\x1b\xbd\xc7\xe7\x7d\x63\x9c\x0f\x60\x9c\x1f\x98\xf8\xfa\x53\xed\x2d\x53\x8a\xb1\xa1\xf4\x2f\x93\xff\x40\xf1\x8f\x91\xbf\xa9\xf8\xa7\xb2\xc8\xe1\xf7\xb9\x27\xa4\x7f\x32\xef\x9f\x9d\xe1\x57\x66\xf8\xa8\x88\xad\xa0\x52\xab\xc5\xb5\xb5\xc7\xcd\x75\x6b\x1b\x3b\xab\xd8\x39\x0f\x3f\xae\x0b\x38\x4e\x35\x0c\x9d\x50\xb8\x4d\x01\xc7\xf7\x5c\xe1\xc2\xf1\x1b\x1e\x60\x85\x4f\xb6\x84\x5b\x85\x15\x8a\xe6\x50\x1f\xca\x55\x63\x5b\xf8\xd6\x66\x23\xb2\xaa\x51\xfd\x91\x77\xae\xee\xc1\x12\x7e\x2c\xfe\xfb\xff\xb1\x02\x60\x3e\xfb\x86\xd4\xbc\x25\x9f\xb3\x40\xc9\x5b\x24\x16\xfd\x56\x73\xa3\x1c\xc7\xce\xe5\x39\x81\xd2\xcf\xa6\xd4\xc6\x94\x7b\x05\xb4\x7f\x81\x8d\xe7\xa6\xf7\x5c\xa0\xe7\xc7\x49\x17\x29\xf3\x51\x89\x29\xcf\xba\xf8\x97\xf9\xe5\x19\xfb\x5f\xfd\xe3\xfe\x5f\x01\x00\x00\xff\xff\xa5\x58\xb1\x16\x60\x13\x00\x00" +const Binaryamd64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x98\x3f\x4b\xc3\x40\x18\xc6\x9f\x6b\x53\x8b\x38\x34\x83\x9b\x20\xad\xb8\x89\x01\x27\x1d\x54\x4e\xf1\xcf\x21\x55\x28\xe8\x07\xb0\xb4\x68\x51\x6a\xb1\x17\xe8\x50\xb0\xa5\x93\xdf\xa0\x73\xbe\x84\x1d\xb3\x05\xbf\x82\x5b\x07\x5d\x5c\x1c\xad\x20\x48\xce\xbb\x98\x84\x0e\x0e\x0e\x0e\xef\x0f\xc2\x73\xef\x9b\xe7\xde\xbb\x5b\x9f\xbb\xfd\xf2\x41\x86\x31\x18\x32\xd8\x86\xaa\x6c\xae\x6a\xae\xfb\x43\x3b\xb2\x80\x63\x03\x16\x38\x2c\x64\x95\xd7\x42\x1c\x9e\xd0\x3d\x3d\xda\x28\xf4\x9c\xb0\xcc\xc5\x6a\x73\x9e\xd1\x96\x6e\x1b\x35\x3e\x4b\x7f\x45\x3d\xaf\xc8\x78\x42\x97\xb5\xdd\xa8\xb9\x5b\xe5\x59\xd6\x66\xf0\x7b\xec\xd8\xfe\x79\x00\x59\x00\x87\x27\x67\x78\x7a\x6b\xad\xd4\xcb\xbd\xd3\xfb\xd2\x55\xe7\xe1\xe3\xf3\xf8\xa5\x52\x2a\x83\x20\x08\x82\x20\x08\x82\x20\x08\x82\x20\xfe\x39\x62\xcd\x2f\x78\x62\xf0\x9e\xef\x1e\x89\x11\x80\x5e\xd8\x2c\x78\x5b\x0c\xe8\x75\xd7\x45\xe0\x33\x65\x7a\x2c\x78\xa2\x3f\x66\x4b\x43\x88\xfe\x24\x14\x77\x41\x8c\x98\xb6\x7f\xff\x1e\x8c\x99\x18\x4c\x98\x9b\x79\x9d\x15\x41\xb0\x03\x40\x2d\x76\xc3\x05\x44\xe0\x6f\x86\x83\x73\x70\xda\x97\x6d\x79\x2b\xcf\xab\x70\x9a\x37\xb2\xee\x5c\x34\x5d\xa7\xea\x36\xae\x6b\xab\x8d\x1a\x1c\x59\xef\xc8\x3f\x79\xd7\x1c\x80\xbc\xca\x33\xd2\x39\x41\x32\x1f\x40\x2a\x27\x30\x2c\xea\x8c\x22\xca\x0c\xa2\x7c\x22\x95\x4b\xe0\x27\xcf\x48\xd7\xd9\x29\xf7\x6a\xd9\xd3\xcf\x4f\xef\xff\x0a\x00\x00\xff\xff\x79\x37\x55\x39\x98\x11\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/arm64_binary.go b/vendor/github.com/moby/buildkit/util/archutil/arm64_binary.go index 74ee3885352ed..3ef0d104783a0 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/arm64_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/arm64_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binaryarm64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x86\xed\x0c\x20\xde\x06\x06\x07\x30\xdf\x01\x2a\x7e\x81\x01\x01\x1c\x18\x2c\x18\x98\x18\x1c\x18\x98\x19\x98\xc0\x6a\x59\x19\x18\x50\x64\x91\xe9\x3d\x50\xde\x1e\xb8\x3c\xc4\xae\xc0\xa7\x25\x29\x6c\x0c\xc4\x03\x01\x38\xab\xe1\xd2\x0a\xee\x86\x4b\x8c\x0c\x0c\x57\x18\xf4\x8a\x33\x8a\x4b\x8a\x4a\x12\x93\x18\xf4\x4a\x52\x2b\x4a\x18\xa8\x00\xb8\xa1\x2e\x84\xb9\x0d\x16\x0e\x1b\xa0\x7c\x1e\x34\xf5\x2c\x68\x7c\x90\x5e\x66\x2c\xe6\xc2\xfc\x2f\x88\x45\x3d\x32\x00\x04\x00\x00\xff\xff\xbb\x46\x88\x1e\x90\x01\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/arm_binary.go b/vendor/github.com/moby/buildkit/util/archutil/arm_binary.go index 5fdaa577a6155..19a9298c0aec9 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/arm_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/arm_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. -const Binaryarm = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\x8c\x8f\x3d\x6e\xc2\x40\x10\x85\xbf\x89\x7f\x12\x29\x29\x92\x9c\x20\xe9\xa8\xb6\xf2\x05\x5c\x40\x05\x05\xdc\x60\x2d\x2c\xe1\xce\xb2\x07\x89\x0e\xce\xc0\x09\x7c\x08\x6e\x64\x51\x73\x05\xe4\x65\x2d\xb6\x70\xc1\x93\x46\xb3\xfb\xcd\x2b\xde\x3b\xce\x97\x0b\x11\x61\xd4\x1b\x33\x86\x9f\x22\x64\xc0\xe5\x01\x93\x8c\x3f\x77\x8b\x89\x78\xba\xc5\xcd\x09\xdc\x24\x9e\xad\xaf\xba\x65\x42\x29\xf0\xed\x5e\x5d\x2f\x75\xd7\x03\xb7\xfc\x07\xb0\xa5\x2d\x2a\xe4\x1d\xf8\x10\x4c\xbb\x6b\xb5\x51\x5b\x60\xb4\x3c\x28\x26\xdf\xac\x8c\x55\x6d\xaa\x62\xaf\x65\xcb\xcb\xfa\xf4\x09\x53\xdf\x47\x81\xaf\xe0\x1e\xfb\x3d\x44\x88\xa0\x1e\xf9\xd0\xe5\x37\xf0\x49\xb0\xa3\x80\x9f\x81\xff\x09\xdf\x3d\x00\x00\xff\xff\x0b\x8f\xbf\xbd\x54\x01\x00\x00" +const Binaryarm = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\x8c\x8f\xbd\x8d\xc2\x40\x10\x85\xbf\x39\xff\xdc\x49\x77\xc1\xdd\x55\x00\x19\xd1\x46\x6e\xc0\x01\x44\x10\x40\x07\x6b\x61\x09\x67\x96\x3d\x48\x64\x50\x03\x15\xb8\x08\x3a\xb2\x88\x69\x01\xad\x7f\xc4\x06\x0e\x78\xd2\x68\x34\xdf\x7b\xc1\xbc\xf3\x72\xbd\x12\x11\x46\x7d\xb0\xc0\x5d\x8a\x90\x00\xb7\x1e\x46\x09\xb3\xce\x0b\x09\x78\xa5\xa5\x9b\x0b\x74\x13\x39\xf4\x0b\xdb\xbb\xee\x99\x50\xdc\xdb\x40\xd3\x4a\xd9\xb4\xc0\x23\xfd\x03\x6c\x6e\xb3\x02\xf9\x04\xbe\x04\x53\x1f\x6a\xad\xd4\x66\x18\xcd\x4f\x8a\x49\x77\x1b\x63\x55\xab\x22\x3b\x6a\x5e\xf3\xb6\xbe\x87\x0f\xe3\xa1\x8f\x02\x3f\x9e\x1f\x0e\xdb\xbd\x10\x40\x39\x72\xd7\xe5\xdf\xcb\x89\xb7\x03\x8f\x5f\x81\xf9\x44\xee\x19\x00\x00\xff\xff\xb6\x04\x27\x29\x54\x01\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/check_windows.go b/vendor/github.com/moby/buildkit/util/archutil/check_windows.go index 6a656011406c9..736f2216ba31f 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/check_windows.go +++ b/vendor/github.com/moby/buildkit/util/archutil/check_windows.go @@ -5,12 +5,8 @@ package archutil import ( "errors" - "os/exec" ) -func withChroot(cmd *exec.Cmd, dir string) { -} - func check(arch, bin string) (string, error) { return "", errors.New("binfmt is not supported on Windows") } diff --git a/vendor/github.com/moby/buildkit/util/archutil/mips64_binary.go b/vendor/github.com/moby/buildkit/util/archutil/mips64_binary.go index 585afc3ff0572..28e3aba35e15d 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/mips64_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/mips64_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binarymips64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xac\x92\xb1\x4a\xf4\x40\x14\x85\xbf\x99\xcd\xe6\xff\x41\xc5\x05\x2d\xc4\x2a\xc5\x16\x8b\xc5\x60\x69\x25\xb1\x50\x10\x14\x56\x7c\x82\x04\xd7\x18\x90\x24\x6c\x26\x60\x27\xbe\x81\xcf\xe4\xbb\x08\xbe\x80\xf5\xca\x24\x93\x98\x44\xa6\x10\x3c\x45\xce\xdc\x93\x7b\x72\xc3\x9c\xfb\x7c\x7e\x75\x21\xa5\xa0\x83\xe4\x3f\x60\x04\x11\x20\x8e\xad\x1a\x36\x24\x5e\x83\xa6\x3a\x61\x42\x88\xcf\xb4\x80\x09\xe0\xd9\xbe\x8f\xc6\x37\x60\x83\x83\x11\xb7\x33\xa6\xdf\x83\xeb\xfe\x3e\x9b\x63\x38\x60\x01\x77\xfa\xfd\x06\xf0\xf9\x1d\x66\xe6\x37\xa5\x44\xf4\xe7\xd5\x8f\x45\x57\xef\x3b\xbc\x22\x10\x2f\xed\x3d\x30\xf7\x60\x2e\xf7\xde\x80\x6d\x53\x9f\x01\xbb\x49\x56\xd5\x5f\xfb\xe7\x09\x54\xf9\x50\xea\xb5\x8e\x62\xd4\xf5\xe5\xf2\x56\x45\x71\x7a\xff\x18\x25\xa5\x2d\xf3\x42\xa7\x79\x56\xa2\xf4\xea\x49\xa3\x92\xac\x52\x91\xd6\xeb\x34\xae\xf4\xaa\xe4\x4f\xb0\x55\xc0\x51\x97\xe6\x30\x87\x71\x1e\xf4\xf2\x68\xf5\xc3\x02\x76\xac\x68\xfd\xa2\x7f\x65\x06\x0b\x87\x5f\xd8\x77\x6d\xa3\x3f\xdc\xa3\x6e\x9f\x66\x3f\xf3\xe9\xa0\xf2\xcd\xe6\xd3\x11\x45\xe8\xf0\x8f\x73\x9d\x38\xfc\x4b\x7b\x38\x75\xf9\xbf\x02\x00\x00\xff\xff\x61\x89\x8d\x22\x10\x03\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/mips64le_binary.go b/vendor/github.com/moby/buildkit/util/archutil/mips64le_binary.go index e56bdb07a5773..5d939d76a1b31 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/mips64le_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/mips64le_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binarymips64le = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xa4\x92\xb1\x4a\xf4\x40\x14\x85\xbf\x99\xec\xee\xbf\xf0\x2b\x0a\x5a\x88\x55\x8a\x2d\x82\xc5\x90\xd2\x4a\xc6\x42\x41\x50\x58\xf1\x09\x12\x5c\x63\x40\x92\xb0\x99\x80\x9d\xf8\x06\x3e\x93\xef\x22\xec\x0b\x58\xaf\x84\xcc\xac\x26\x26\x28\x78\x9b\x73\xcf\xbd\x73\x12\xe6\x9c\x79\x3a\xbb\x3c\x97\x42\xe0\x4a\x32\xa5\x66\xa1\xc0\xaf\x51\xdb\xf9\xcb\xe7\x11\x5f\x73\x8c\x87\x66\xc2\x18\x0f\x8a\x11\xb0\xb2\xcb\x15\x8d\xce\xe1\x81\x9d\x3b\x9c\x5a\xac\x77\x63\x5a\xe5\x8b\x2f\xa8\x2d\xd1\x9b\xff\x36\xcd\xf5\x9b\xb9\x9d\xf0\xfb\xda\xdd\x74\x1e\x52\xd2\xf9\x1a\x88\xa0\xc1\xfd\x01\x7d\xf8\x2c\x7c\xd1\x9a\x8c\x66\xaf\x7b\x72\xb6\x65\xd9\xe9\x0e\x90\x64\x15\xe2\x5f\xbd\x13\xa8\xf2\xbe\x34\x4b\x13\xc5\xa8\xab\x8b\xf9\x8d\x8a\xe2\xf4\xee\x21\x4a\x4a\x4b\xf3\xc2\xa4\x79\x56\xa2\xcc\xe2\xd1\xa0\x92\xac\x52\x91\x31\xcb\x34\xae\xcc\xa2\xe4\xef\xf5\x1f\x38\x82\x42\x7e\xcf\xa3\x95\x03\x9d\x3c\xdc\xfc\x10\xd8\x6e\xf4\x53\x6b\x54\x73\x7f\x6b\x42\x30\xa0\x77\x1e\x05\xb6\x77\x19\xb9\x77\x14\x8a\x6e\x1e\xfd\x5c\x01\xef\xeb\x75\xde\xbd\x97\x1e\xd0\x8b\x1e\xee\xf5\xf8\x32\xb7\x07\x4f\x7e\xd0\x7f\x04\x00\x00\xff\xff\xd1\x67\xf7\xcd\x10\x03\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/ppc64_binary.go b/vendor/github.com/moby/buildkit/util/archutil/ppc64_binary.go index d0c197c20d504..6158d92b9f74a 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/ppc64_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/ppc64_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binaryppc64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\xd0\xb1\x8a\x13\x51\x14\x06\xe0\xff\x8e\xd9\x45\xd0\x62\x2c\x84\x05\x9b\x3c\x40\x98\x7a\xcb\x14\x6a\x65\xa3\x2f\xa0\x2b\x89\x6c\x23\xca\xee\x14\x76\xfb\xb4\x81\xbc\x45\x24\x93\xc9\x64\x12\x89\xa4\xb0\x92\xef\x83\xdc\x73\x72\x66\x7e\xce\x65\x9e\xde\x7d\x78\x5f\x55\x25\x83\x2a\xaf\x93\x74\x83\xba\x6c\xd6\xfd\x74\xde\x9d\x25\xd3\xee\x9c\xe7\x36\x93\xcc\x73\x95\x49\xff\xee\x55\x46\xea\x93\x9a\x94\xd9\x51\x2d\xc3\x79\xbd\x9b\xef\xf6\xec\xf7\x8d\xf6\xde\x1c\xd5\x92\x2c\xda\xd5\xc7\x43\xee\x62\xf5\xa2\x5d\x7d\x4a\xba\xfb\x5e\xbe\x2f\x29\xb7\xdb\xdf\x97\xe4\xed\xf6\xcb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x27\xea\x94\x69\x57\xab\xa7\xc3\xb0\x79\xbc\x7f\x6c\x1f\xda\xbb\xaf\x69\xda\xe5\xaf\x36\xcd\xf2\xfe\xf3\xb7\x87\xbb\xef\xcb\x34\x3f\x7e\x2e\xfe\xc5\xda\x17\x49\x4a\xdf\x5f\x8f\xef\x91\xa1\xe6\xe5\x49\xe6\xf9\xa8\x7f\x35\xca\x57\x7d\x7e\xd6\xe7\x67\x67\x76\x4e\x46\xfd\x9b\x51\xfe\x59\x97\x2f\x9b\xf5\xee\xef\xbe\xe6\xe6\x2f\xfb\xcb\x3e\xf7\x87\x32\x74\xd3\x73\x4f\x7e\x07\x00\x00\xff\xff\x5e\xe4\x1d\xbd\x60\x01\x01\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/ppc64le_binary.go b/vendor/github.com/moby/buildkit/util/archutil/ppc64le_binary.go index 1be429cc40f0f..b9254b730868b 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/ppc64le_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/ppc64le_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binaryppc64le = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x51\x06\x10\x6f\x03\x03\x83\x00\x88\xef\x00\x15\xbf\x01\x97\x07\x89\x59\x30\x30\x31\x38\x30\xb0\x30\x30\x83\xd5\xb2\x32\xa0\x00\x01\x64\x7a\x0f\x94\xb3\x07\x2e\x0d\xb1\x2b\xf0\x69\x49\x0a\x1b\x03\xf1\x40\x00\xa1\xdb\x82\x81\x21\xc1\x82\x89\x81\xc1\x85\x41\xaf\x38\xa3\xb8\xa4\xa8\x24\x31\x89\x41\xaf\x24\xb5\xa2\x84\x41\x2f\x35\x23\x3e\xad\x28\x31\x37\x95\x81\x62\xc0\x0d\x75\x29\xcc\x8d\xb0\xf0\xd8\x00\xe5\xf3\xa0\xa9\xe7\x40\xe3\x0b\x42\xf5\x33\x21\xfc\x2f\x80\x1a\x0e\xa8\x80\x05\x8d\x0f\xd2\xcb\x8c\x45\x1d\x4c\xbf\x34\x16\xf5\xc8\x00\x10\x00\x00\xff\xff\x59\x3e\xf6\x64\xd8\x01\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/riscv64_binary.go b/vendor/github.com/moby/buildkit/util/archutil/riscv64_binary.go index 69864eee324eb..2db29cf0b3a1f 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/riscv64_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/riscv64_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. -const Binaryriscv64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x86\xcf\x0c\x20\xde\x06\x06\x88\x98\x03\x54\xfc\x02\x94\x66\x01\x8b\x59\x30\x30\x31\x38\x30\x30\x33\x30\x81\x55\xb1\x32\x20\x03\x46\x14\x7a\x0f\x94\x07\xa3\x19\x04\x20\x54\xe0\xd3\x92\x14\x36\x06\xe2\x01\x54\x1b\x83\x30\x2b\x03\xc3\x64\x8e\x0b\xac\xc5\x20\x8e\x5e\x71\x46\x71\x49\x51\x49\x62\x12\x83\x5e\x49\x6a\x45\x09\x03\x15\x00\x37\xd4\xe5\x30\xb7\xc1\xc2\x61\x03\x94\xcf\x83\xa6\x9e\x05\x8d\x0f\x52\xcd\x8c\xc5\x5c\x98\xff\x05\xb1\xa8\x47\x06\x80\x00\x00\x00\xff\xff\x34\x4f\x05\xf7\x90\x01\x00\x00" +const Binaryriscv64 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x86\xcf\x0c\x20\xde\x0b\x06\x88\x98\x03\x54\x3c\x00\xaa\x84\x05\x2c\x66\xc1\xc0\xcc\xe0\xc0\xc0\xc2\xc0\xcc\xc0\xcc\xc0\x50\x00\x12\xfb\xc2\x80\x1d\x98\xa3\xf1\x19\x91\x68\x56\x9c\x32\x08\xf3\xe0\xe6\x0a\x40\xa8\xc0\xa7\x25\x29\x6c\x0c\xc4\x03\xa8\x36\x06\x61\x56\x06\x86\xc9\x1c\x17\x58\x8b\x19\x18\x18\x1c\xcd\x18\x18\x18\x8a\x32\x8b\x93\xcb\x18\x18\x75\x40\xee\x28\x2a\x33\x33\xc9\x34\x2a\x30\x88\xcf\x05\x11\x89\x20\x22\x0d\x44\xa4\x80\x88\xaa\xdc\xdc\xd2\x1c\xc3\x02\x03\x06\x06\xbd\xe2\x8c\xe2\x92\xa2\x92\xc4\x24\x06\xbd\x92\xd4\x8a\x12\x06\x3d\xb0\x19\x7a\x89\x25\x25\x45\x99\x49\xa5\x25\xa9\xc5\x0c\x94\x03\x6e\x68\x08\xc0\xfc\x08\x8b\x87\x17\x50\x3e\x0f\x9a\x7a\x16\x34\xbe\x20\x03\x03\x38\x4e\xd0\xcd\xfd\x42\x20\x3e\x90\xf9\xcc\x58\xdc\xa5\x0d\x55\xa8\x4c\x40\x3f\x20\x00\x00\xff\xff\xfa\x60\xf3\x5e\x50\x02\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/archutil/s390x_binary.go b/vendor/github.com/moby/buildkit/util/archutil/s390x_binary.go index 17b7e8a257c4e..4e0474e57b6af 100644 --- a/vendor/github.com/moby/buildkit/util/archutil/s390x_binary.go +++ b/vendor/github.com/moby/buildkit/util/archutil/s390x_binary.go @@ -3,7 +3,7 @@ package archutil -// This file is generated by running make inside the archutil package. +// This file is generated by running "make archutil". // Do not edit manually. const Binarys390x = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x62\x64\x80\x03\x26\x06\x31\x06\x06\x06\xb0\x00\x23\x03\xc3\x06\xa8\xa8\x03\x94\xbe\x00\xe5\x59\x30\x30\x31\x38\x30\x30\x33\x30\x41\xd5\xb2\x32\x20\x01\x46\x34\x9a\x81\x81\x61\x07\x2a\x2d\xc0\x90\x52\xf2\x34\x90\x81\x81\x81\x8d\x81\x34\x20\xb0\x5c\x93\x81\x81\x8b\x91\x9d\x9d\x41\xaf\x38\xa3\xb8\xa4\xa8\x24\x31\x89\x41\xaf\x24\xb5\xa2\x84\x81\x7a\x80\x1b\xc9\xe9\x6c\x68\xe1\x00\xa3\x39\xd0\xf4\xb0\xa0\x79\x9f\x19\x87\xd9\xb0\x70\x10\x44\x13\x87\x07\x15\x20\x00\x00\xff\xff\x28\x7b\x76\xee\x90\x01\x00\x00" diff --git a/vendor/github.com/moby/buildkit/util/bklog/log.go b/vendor/github.com/moby/buildkit/util/bklog/log.go index 7d0b1d90df0b8..cf6630de19af8 100644 --- a/vendor/github.com/moby/buildkit/util/bklog/log.go +++ b/vendor/github.com/moby/buildkit/util/bklog/log.go @@ -4,7 +4,7 @@ import ( "context" "runtime/debug" - "github.com/containerd/containerd/log" + "github.com/containerd/log" "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/trace" ) @@ -63,14 +63,13 @@ func GetLogger(ctx context.Context) (l *logrus.Entry) { return l } -// LazyStackTrace lets you include a stack trace as a field's value in a log but only -// call it when the log level is actually enabled. -type LazyStackTrace struct{} - -func (LazyStackTrace) String() string { - return string(debug.Stack()) -} - -func (LazyStackTrace) MarshalText() ([]byte, error) { - return debug.Stack(), nil +// TraceLevelOnlyStack returns a stack trace for the current goroutine only if +// trace level logs are enabled; otherwise it returns an empty string. This ensure +// we only pay the cost of generating a stack trace when the log entry will actually +// be emitted. +func TraceLevelOnlyStack() string { + if logrus.GetLevel() == logrus.TraceLevel { + return string(debug.Stack()) + } + return "" } diff --git a/vendor/github.com/moby/buildkit/util/compression/compression.go b/vendor/github.com/moby/buildkit/util/compression/compression.go index 8398bfb299907..2155db4d5715f 100644 --- a/vendor/github.com/moby/buildkit/util/compression/compression.go +++ b/vendor/github.com/moby/buildkit/util/compression/compression.go @@ -26,9 +26,8 @@ type Type interface { Compress(ctx context.Context, comp Config) (compressorFunc Compressor, finalize Finalizer) Decompress(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (io.ReadCloser, error) NeedsConversion(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (bool, error) - NeedsComputeDiffBySelf() bool + NeedsComputeDiffBySelf(comp Config) bool OnlySupportOCITypes() bool - NeedsForceCompression() bool MediaType() string String() string } diff --git a/vendor/github.com/moby/buildkit/util/compression/estargz.go b/vendor/github.com/moby/buildkit/util/compression/estargz.go index 9d44d940486c1..ef6f853a7511f 100644 --- a/vendor/github.com/moby/buildkit/util/compression/estargz.go +++ b/vendor/github.com/moby/buildkit/util/compression/estargz.go @@ -12,6 +12,7 @@ import ( cdcompression "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" "github.com/containerd/stargz-snapshotter/estargz" "github.com/moby/buildkit/util/iohelper" digest "github.com/opencontainers/go-digest" @@ -21,7 +22,6 @@ import ( var EStargzAnnotations = []string{estargz.TOCJSONDigestAnnotation, estargz.StoreUncompressedSizeAnnotation} -const containerdUncompressed = "containerd.io/uncompressed" const estargzLabel = "buildkit.io/compression/estargz" func (c estargzType) Compress(ctx context.Context, comp Config) (compressorFunc Compressor, finalize Finalizer) { @@ -105,8 +105,8 @@ func (c estargzType) Compress(ctx context.Context, comp Config) (compressorFunc if info.Labels == nil { info.Labels = make(map[string]string) } - info.Labels[containerdUncompressed] = cInfo.uncompressedDigest.String() - if _, err := cs.Update(ctx, info, "labels."+containerdUncompressed); err != nil { + info.Labels[labels.LabelUncompressed] = cInfo.uncompressedDigest.String() + if _, err := cs.Update(ctx, info, "labels."+labels.LabelUncompressed); err != nil { return nil, err } @@ -114,7 +114,7 @@ func (c estargzType) Compress(ctx context.Context, comp Config) (compressorFunc a := make(map[string]string) a[estargz.TOCJSONDigestAnnotation] = cInfo.tocDigest.String() a[estargz.StoreUncompressedSizeAnnotation] = fmt.Sprintf("%d", cInfo.uncompressedSize) - a[containerdUncompressed] = cInfo.uncompressedDigest.String() + a[labels.LabelUncompressed] = cInfo.uncompressedDigest.String() return a, nil } } @@ -134,7 +134,7 @@ func (c estargzType) NeedsConversion(ctx context.Context, cs content.Store, desc return true, nil } -func (c estargzType) NeedsComputeDiffBySelf() bool { +func (c estargzType) NeedsComputeDiffBySelf(comp Config) bool { return true } @@ -142,10 +142,6 @@ func (c estargzType) OnlySupportOCITypes() bool { return true } -func (c estargzType) NeedsForceCompression() bool { - return false -} - func (c estargzType) MediaType() string { return ocispecs.MediaTypeImageLayerGzip } diff --git a/vendor/github.com/moby/buildkit/util/compression/gzip.go b/vendor/github.com/moby/buildkit/util/compression/gzip.go index 7120ba35e38da..aafded866f3a8 100644 --- a/vendor/github.com/moby/buildkit/util/compression/gzip.go +++ b/vendor/github.com/moby/buildkit/util/compression/gzip.go @@ -38,18 +38,15 @@ func (c gzipType) NeedsConversion(ctx context.Context, cs content.Store, desc oc return true, nil } -func (c gzipType) NeedsComputeDiffBySelf() bool { - return false +func (c gzipType) NeedsComputeDiffBySelf(comp Config) bool { + // we allow compressing it with a customized compression level that containerd differ doesn't support so we compress it by self. + return comp.Level != nil } func (c gzipType) OnlySupportOCITypes() bool { return false } -func (c gzipType) NeedsForceCompression() bool { - return false -} - func (c gzipType) MediaType() string { return ocispecs.MediaTypeImageLayerGzip } diff --git a/vendor/github.com/moby/buildkit/util/compression/nydus.go b/vendor/github.com/moby/buildkit/util/compression/nydus.go index 4e04be70b7ab2..a80be43debe81 100644 --- a/vendor/github.com/moby/buildkit/util/compression/nydus.go +++ b/vendor/github.com/moby/buildkit/util/compression/nydus.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -56,14 +57,14 @@ func (c nydusType) Compress(ctx context.Context, comp Config) (compressorFunc Co if info.Labels == nil { info.Labels = make(map[string]string) } - info.Labels[containerdUncompressed] = uncompressedDgst - if _, err := cs.Update(ctx, info, "labels."+containerdUncompressed); err != nil { + info.Labels[labels.LabelUncompressed] = uncompressedDgst + if _, err := cs.Update(ctx, info, "labels."+labels.LabelUncompressed); err != nil { return nil, errors.Wrap(err, "update info to content store") } // Fill annotations annotations := map[string]string{ - containerdUncompressed: uncompressedDgst, + labels.LabelUncompressed: uncompressedDgst, // Use this annotation to identify nydus blob layer. nydusify.LayerAnnotationNydusBlob: "true", } @@ -103,7 +104,7 @@ func (c nydusType) NeedsConversion(ctx context.Context, cs content.Store, desc o return true, nil } -func (c nydusType) NeedsComputeDiffBySelf() bool { +func (c nydusType) NeedsComputeDiffBySelf(comp Config) bool { return true } @@ -111,10 +112,6 @@ func (c nydusType) OnlySupportOCITypes() bool { return true } -func (c nydusType) NeedsForceCompression() bool { - return true -} - func (c nydusType) MediaType() string { return nydusify.MediaTypeNydusBlob } diff --git a/vendor/github.com/moby/buildkit/util/compression/uncompressed.go b/vendor/github.com/moby/buildkit/util/compression/uncompressed.go index 5fc5b8e92a196..9242154854b60 100644 --- a/vendor/github.com/moby/buildkit/util/compression/uncompressed.go +++ b/vendor/github.com/moby/buildkit/util/compression/uncompressed.go @@ -40,7 +40,7 @@ func (c uncompressedType) NeedsConversion(ctx context.Context, cs content.Store, return true, nil } -func (c uncompressedType) NeedsComputeDiffBySelf() bool { +func (c uncompressedType) NeedsComputeDiffBySelf(comp Config) bool { return false } @@ -48,10 +48,6 @@ func (c uncompressedType) OnlySupportOCITypes() bool { return false } -func (c uncompressedType) NeedsForceCompression() bool { - return false -} - func (c uncompressedType) MediaType() string { return ocispecs.MediaTypeImageLayer } diff --git a/vendor/github.com/moby/buildkit/util/compression/zstd.go b/vendor/github.com/moby/buildkit/util/compression/zstd.go index e7de6a21c30ef..3ef056e5de40f 100644 --- a/vendor/github.com/moby/buildkit/util/compression/zstd.go +++ b/vendor/github.com/moby/buildkit/util/compression/zstd.go @@ -34,7 +34,7 @@ func (c zstdType) NeedsConversion(ctx context.Context, cs content.Store, desc oc return true, nil } -func (c zstdType) NeedsComputeDiffBySelf() bool { +func (c zstdType) NeedsComputeDiffBySelf(comp Config) bool { return true } @@ -42,10 +42,6 @@ func (c zstdType) OnlySupportOCITypes() bool { return false } -func (c zstdType) NeedsForceCompression() bool { - return false -} - func (c zstdType) MediaType() string { return ocispecs.MediaTypeImageLayerZstd } diff --git a/vendor/github.com/moby/buildkit/util/contentutil/storewithprovider.go b/vendor/github.com/moby/buildkit/util/contentutil/storewithprovider.go new file mode 100644 index 0000000000000..0b5df244f15a6 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/contentutil/storewithprovider.go @@ -0,0 +1,24 @@ +package contentutil + +import ( + "context" + + "github.com/containerd/containerd/content" + ocispecs "github.com/opencontainers/image-spec/specs-go/v1" +) + +func NewStoreWithProvider(cs content.Store, p content.Provider) content.Store { + return &storeWithProvider{Store: cs, p: p} +} + +type storeWithProvider struct { + content.Store + p content.Provider +} + +func (cs *storeWithProvider) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (content.ReaderAt, error) { + if ra, err := cs.p.ReaderAt(ctx, desc); err == nil { + return ra, nil + } + return cs.Store.ReaderAt(ctx, desc) +} diff --git a/vendor/github.com/moby/buildkit/cache/converter.go b/vendor/github.com/moby/buildkit/util/converter/converter.go similarity index 57% rename from vendor/github.com/moby/buildkit/cache/converter.go rename to vendor/github.com/moby/buildkit/util/converter/converter.go index f19412b7086a4..4b956f02f1060 100644 --- a/vendor/github.com/moby/buildkit/cache/converter.go +++ b/vendor/github.com/moby/buildkit/util/converter/converter.go @@ -1,11 +1,13 @@ -package cache +package converter import ( + "archive/tar" "bufio" "context" "fmt" "io" "sync" + "time" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" @@ -14,18 +16,30 @@ import ( "github.com/moby/buildkit/identity" "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/compression" + "github.com/moby/buildkit/util/converter/tarconverter" "github.com/moby/buildkit/util/iohelper" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) -// getConverter returns converter function according to the specified compression type. +// New returns converter function according to the specified compression type. // If no conversion is needed, this returns nil without error. -func getConverter(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config) (converter.ConvertFunc, error) { - if needs, err := comp.Type.NeedsConversion(ctx, cs, desc); err != nil { +func New(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config) (converter.ConvertFunc, error) { + return NewWithRewriteTimestamp(ctx, cs, desc, comp, nil, nil) +} + +// NewWithRewriteTimestamp returns converter function according to the specified compression type and the epoch. +// If no conversion is needed, this returns nil without error. +func NewWithRewriteTimestamp(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config, rewriteTimestamp *time.Time, immDiffIDs map[digest.Digest]struct{}) (converter.ConvertFunc, error) { + needs, err := comp.Type.NeedsConversion(ctx, cs, desc) + if err != nil { return nil, errors.Wrapf(err, "failed to determine conversion needs") - } else if !needs { + } + if !needs && rewriteTimestamp != nil { + needs = desc.Annotations[labelRewrittenTimestamp] != fmt.Sprintf("%d", rewriteTimestamp.UTC().Unix()) + } + if !needs { // No conversion. No need to return an error here. return nil, nil } @@ -38,15 +52,19 @@ func getConverter(ctx context.Context, cs content.Store, desc ocispecs.Descripto c := conversion{target: comp} c.compress, c.finalize = comp.Type.Compress(ctx, comp) c.decompress = from.Decompress + c.rewriteTimestamp = rewriteTimestamp + c.immDiffIDs = immDiffIDs return (&c).convert, nil } type conversion struct { - target compression.Config - decompress compression.Decompressor - compress compression.Compressor - finalize compression.Finalizer + target compression.Config + decompress compression.Decompressor + compress compression.Compressor + finalize compression.Finalizer + rewriteTimestamp *time.Time + immDiffIDs map[digest.Digest]struct{} // diffIDs of immutable layers } var bufioPool = sync.Pool{ @@ -55,6 +73,20 @@ var bufioPool = sync.Pool{ }, } +func rewriteTimestampInTarHeader(epoch time.Time) tarconverter.HeaderConverter { + return func(hdr *tar.Header) { + if hdr.ModTime.After(epoch) { + hdr.ModTime = epoch + } + if hdr.AccessTime.After(epoch) { + hdr.AccessTime = epoch + } + if hdr.ChangeTime.After(epoch) { + hdr.ChangeTime = epoch + } + } +} + func (c *conversion) convert(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (*ocispecs.Descriptor, error) { bklog.G(ctx).WithField("blob", desc).WithField("target", c.target).Debugf("converting blob to the target compression") // prepare the source and destination @@ -86,11 +118,18 @@ func (c *conversion) convert(ctx context.Context, cs content.Store, desc ocispec // convert this layer diffID := digest.Canonical.Digester() - rdr, err := c.decompress(ctx, cs, desc) + origDiffID := digest.Canonical.Digester() + decR, err := c.decompress(ctx, cs, desc) if err != nil { return nil, err } - defer rdr.Close() + defer decR.Close() + rdr := decR + if c.rewriteTimestamp != nil { + tcR := tarconverter.NewReader(io.TeeReader(decR, origDiffID.Hash()), rewriteTimestampInTarHeader(*c.rewriteTimestamp)) + defer tcR.Close() + rdr = tcR + } if _, err := io.Copy(zw, io.TeeReader(rdr, diffID.Hash())); err != nil { return nil, err } @@ -100,7 +139,15 @@ func (c *conversion) convert(ctx context.Context, cs content.Store, desc ocispec if err := bufW.Flush(); err != nil { // Flush the buffer return nil, errors.Wrap(err, "failed to flush diff during conversion") } + origDiffIDVal := origDiffID.Digest() + if _, ok := c.immDiffIDs[origDiffIDVal]; ok { + bklog.G(ctx).WithField("blob", desc).Debugf("Not rewriting to apply epoch (immutable diffID %q, computed during conversion)", origDiffIDVal) + return &desc, nil + } labelz[labels.LabelUncompressed] = diffID.Digest().String() // update diffID label + if c.rewriteTimestamp != nil { + labelz[labelRewrittenTimestamp] = fmt.Sprintf("%d", c.rewriteTimestamp.UTC().Unix()) + } if err = w.Commit(ctx, 0, "", content.WithLabels(labelz)); err != nil && !errdefs.IsAlreadyExists(err) { return nil, err } @@ -117,6 +164,9 @@ func (c *conversion) convert(ctx context.Context, cs content.Store, desc ocispec newDesc.Digest = info.Digest newDesc.Size = info.Size newDesc.Annotations = map[string]string{labels.LabelUncompressed: diffID.Digest().String()} + if c.rewriteTimestamp != nil { + newDesc.Annotations[labelRewrittenTimestamp] = fmt.Sprintf("%d", c.rewriteTimestamp.UTC().Unix()) + } if c.finalize != nil { a, err := c.finalize(ctx, cs) if err != nil { @@ -140,3 +190,5 @@ func (w *onceWriteCloser) Close() (err error) { }) return } + +const labelRewrittenTimestamp = "buildkit/rewritten-timestamp" diff --git a/vendor/github.com/moby/buildkit/util/converter/tarconverter/tarconverter.go b/vendor/github.com/moby/buildkit/util/converter/tarconverter/tarconverter.go new file mode 100644 index 0000000000000..6942be8417716 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/converter/tarconverter/tarconverter.go @@ -0,0 +1,49 @@ +package tarconverter + +import ( + "archive/tar" + "io" +) + +type HeaderConverter func(*tar.Header) + +// NewReader returns a reader that applies headerConverter. +// Forked from https://github.com/moby/moby/blob/v24.0.6/pkg/archive/copy.go#L308-L373 . +func NewReader(srcContent io.Reader, headerConverter HeaderConverter) io.ReadCloser { + rebased, w := io.Pipe() + + go func() { + srcTar := tar.NewReader(srcContent) + rebasedTar := tar.NewWriter(w) + + for { + hdr, err := srcTar.Next() + if err == io.EOF { + // Signals end of archive. + rebasedTar.Close() + w.Close() + return + } + if err != nil { + w.CloseWithError(err) + return + } + if headerConverter != nil { + headerConverter(hdr) + } + if err = rebasedTar.WriteHeader(hdr); err != nil { + w.CloseWithError(err) + return + } + + // Ignoring GoSec G110. See https://github.com/moby/moby/blob/v24.0.6/pkg/archive/copy.go#L355-L363 + //nolint:gosec // G110: Potential DoS vulnerability via decompression bomb (gosec) + if _, err = io.Copy(rebasedTar, srcTar); err != nil { + w.CloseWithError(err) + return + } + } + }() + + return rebased +} diff --git a/vendor/github.com/moby/buildkit/util/flightcontrol/flightcontrol.go b/vendor/github.com/moby/buildkit/util/flightcontrol/flightcontrol.go index 82ed25205fe42..42cb23678f1bd 100644 --- a/vendor/github.com/moby/buildkit/util/flightcontrol/flightcontrol.go +++ b/vendor/github.com/moby/buildkit/util/flightcontrol/flightcontrol.go @@ -90,7 +90,7 @@ type call[T any] struct { fn func(ctx context.Context) (T, error) once sync.Once - closeProgressWriter func() + closeProgressWriter func(error) progressState *progressState progressCtx context.Context } @@ -115,9 +115,9 @@ func newCall[T any](fn func(ctx context.Context) (T, error)) *call[T] { } func (c *call[T]) run() { - defer c.closeProgressWriter() - ctx, cancel := context.WithCancel(c.ctx) - defer cancel() + defer c.closeProgressWriter(errors.WithStack(context.Canceled)) + ctx, cancel := context.WithCancelCause(c.ctx) + defer cancel(errors.WithStack(context.Canceled)) v, err := c.fn(ctx) c.mu.Lock() c.result = v @@ -155,8 +155,8 @@ func (c *call[T]) wait(ctx context.Context) (v T, err error) { c.progressState.add(pw) } - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(errors.WithStack(context.Canceled)) c.ctxs = append(c.ctxs, ctx) @@ -175,7 +175,7 @@ func (c *call[T]) wait(ctx context.Context) (v T, err error) { if ok { c.progressState.close(pw) } - return empty, ctx.Err() + return empty, context.Cause(ctx) case <-c.ready: return c.result, c.err // shared not implemented yet } @@ -262,7 +262,9 @@ func (sc *sharedContext[T]) checkDone() bool { for _, ctx := range sc.ctxs { select { case <-ctx.Done(): - err = ctx.Err() + // Cause can't be used here because this error is returned for Err() in custom context + // implementation and unfortunately stdlib does not allow defining Cause() for custom contexts + err = ctx.Err() //nolint: forbidigo default: sc.mu.Unlock() return false diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go b/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go new file mode 100644 index 0000000000000..dac803f85da56 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go @@ -0,0 +1,243 @@ +package gitutil + +import ( + "bytes" + "context" + "io" + "os" + "os/exec" + "strings" + + "github.com/pkg/errors" +) + +// GitCLI carries config to pass to the git cli to make running multiple +// commands less repetitive. +type GitCLI struct { + git string + exec func(context.Context, *exec.Cmd) error + + args []string + dir string + streams StreamFunc + + workTree string + gitDir string + + sshAuthSock string + sshKnownHosts string +} + +// Option provides a variadic option for configuring the git client. +type Option func(b *GitCLI) + +// WithGitBinary sets the git binary path. +func WithGitBinary(path string) Option { + return func(b *GitCLI) { + b.git = path + } +} + +// WithExec sets the command exec function. +func WithExec(exec func(context.Context, *exec.Cmd) error) Option { + return func(b *GitCLI) { + b.exec = exec + } +} + +// WithArgs sets extra args. +func WithArgs(args ...string) Option { + return func(b *GitCLI) { + b.args = append(b.args, args...) + } +} + +// WithDir sets working directory. +// +// This should be a path to any directory within a standard git repository. +func WithDir(dir string) Option { + return func(b *GitCLI) { + b.dir = dir + } +} + +// WithWorkTree sets the --work-tree arg. +// +// This should be the path to the top-level directory of the checkout. When +// setting this, you also likely need to set WithGitDir. +func WithWorkTree(workTree string) Option { + return func(b *GitCLI) { + b.workTree = workTree + } +} + +// WithGitDir sets the --git-dir arg. +// +// This should be the path to the .git directory. When setting this, you may +// also need to set WithWorkTree, unless you are working with a bare +// repository. +func WithGitDir(gitDir string) Option { + return func(b *GitCLI) { + b.gitDir = gitDir + } +} + +// WithSSHAuthSock sets the ssh auth sock. +func WithSSHAuthSock(sshAuthSock string) Option { + return func(b *GitCLI) { + b.sshAuthSock = sshAuthSock + } +} + +// WithSSHKnownHosts sets the known hosts file. +func WithSSHKnownHosts(sshKnownHosts string) Option { + return func(b *GitCLI) { + b.sshKnownHosts = sshKnownHosts + } +} + +type StreamFunc func(context.Context) (io.WriteCloser, io.WriteCloser, func()) + +// WithStreams configures a callback for getting the streams for a command. The +// stream callback will be called once for each command, and both writers will +// be closed after the command has finished. +func WithStreams(streams StreamFunc) Option { + return func(b *GitCLI) { + b.streams = streams + } +} + +// New initializes a new git client +func NewGitCLI(opts ...Option) *GitCLI { + c := &GitCLI{} + for _, opt := range opts { + opt(c) + } + return c +} + +// New returns a new git client with the same config as the current one, but +// with the given options applied on top. +func (cli *GitCLI) New(opts ...Option) *GitCLI { + c := &GitCLI{ + git: cli.git, + dir: cli.dir, + workTree: cli.workTree, + gitDir: cli.gitDir, + args: append([]string{}, cli.args...), + streams: cli.streams, + sshAuthSock: cli.sshAuthSock, + sshKnownHosts: cli.sshKnownHosts, + } + for _, opt := range opts { + opt(c) + } + return c +} + +// Run executes a git command with the given args. +func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error) { + gitBinary := "git" + if cli.git != "" { + gitBinary = cli.git + } + + for { + var cmd *exec.Cmd + if cli.exec == nil { + cmd = exec.CommandContext(ctx, gitBinary) + } else { + cmd = exec.Command(gitBinary) + } + + cmd.Dir = cli.dir + if cmd.Dir == "" { + cmd.Dir = cli.workTree + } + + // Block sneaky repositories from using repos from the filesystem as submodules. + cmd.Args = append(cmd.Args, "-c", "protocol.file.allow=user") + if cli.workTree != "" { + cmd.Args = append(cmd.Args, "--work-tree", cli.workTree) + } + if cli.gitDir != "" { + cmd.Args = append(cmd.Args, "--git-dir", cli.gitDir) + } + cmd.Args = append(cmd.Args, cli.args...) + cmd.Args = append(cmd.Args, args...) + + buf := bytes.NewBuffer(nil) + errbuf := bytes.NewBuffer(nil) + cmd.Stdin = nil + cmd.Stdout = buf + cmd.Stderr = errbuf + if cli.streams != nil { + stdout, stderr, flush := cli.streams(ctx) + if stdout != nil { + cmd.Stdout = io.MultiWriter(stdout, cmd.Stdout) + } + if stderr != nil { + cmd.Stderr = io.MultiWriter(stderr, cmd.Stderr) + } + defer stdout.Close() + defer stderr.Close() + defer func() { + if err != nil { + flush() + } + }() + } + + cmd.Env = []string{ + "PATH=" + os.Getenv("PATH"), + "GIT_TERMINAL_PROMPT=0", + "GIT_SSH_COMMAND=" + getGitSSHCommand(cli.sshKnownHosts), + // "GIT_TRACE=1", + "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. + "HOME=/dev/null", // Disable reading from user gitconfig. + "LC_ALL=C", // Ensure consistent output. + } + if cli.sshAuthSock != "" { + cmd.Env = append(cmd.Env, "SSH_AUTH_SOCK="+cli.sshAuthSock) + } + + if cli.exec != nil { + // remote git commands spawn helper processes that inherit FDs and don't + // handle parent death signal so exec.CommandContext can't be used + err = cli.exec(ctx, cmd) + } else { + err = cmd.Run() + } + + if err != nil { + if strings.Contains(errbuf.String(), "--depth") || strings.Contains(errbuf.String(), "shallow") { + if newArgs := argsNoDepth(args); len(args) > len(newArgs) { + args = newArgs + continue + } + } + return buf.Bytes(), errors.Errorf("git error: %s\nstderr:\n%s", err, errbuf.String()) + } + return buf.Bytes(), nil + } +} + +func getGitSSHCommand(knownHosts string) string { + gitSSHCommand := "ssh -F /dev/null" + if knownHosts != "" { + gitSSHCommand += " -o UserKnownHostsFile=" + knownHosts + } else { + gitSSHCommand += " -o StrictHostKeyChecking=no" + } + return gitSSHCommand +} + +func argsNoDepth(args []string) []string { + out := make([]string, 0, len(args)) + for _, a := range args { + if a != "--depth=1" { + out = append(out, a) + } + } + return out +} diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_cli_helpers.go b/vendor/github.com/moby/buildkit/util/gitutil/git_cli_helpers.go new file mode 100644 index 0000000000000..8238783ddf3a8 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_cli_helpers.go @@ -0,0 +1,44 @@ +package gitutil + +import ( + "context" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +func (cli *GitCLI) Dir() string { + if cli.dir != "" { + return cli.dir + } + return cli.workTree +} + +func (cli *GitCLI) WorkTree(ctx context.Context) (string, error) { + if cli.workTree != "" { + return cli.workTree, nil + } + return cli.clean(cli.Run(ctx, "rev-parse", "--show-toplevel")) +} + +func (cli *GitCLI) GitDir(ctx context.Context) (string, error) { + if cli.gitDir != "" { + return cli.gitDir, nil + } + + dir, err := cli.WorkTree(ctx) + if err != nil { + return "", err + } + return filepath.Join(dir, ".git"), nil +} + +func (cli *GitCLI) clean(dt []byte, err error) (string, error) { + out := string(dt) + out = strings.ReplaceAll(strings.Split(out, "\n")[0], "'", "") + if err != nil { + err = errors.New(strings.TrimSuffix(err.Error(), "\n")) + } + return out, err +} diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_protocol.go b/vendor/github.com/moby/buildkit/util/gitutil/git_protocol.go deleted file mode 100644 index 3b9df83920b79..0000000000000 --- a/vendor/github.com/moby/buildkit/util/gitutil/git_protocol.go +++ /dev/null @@ -1,46 +0,0 @@ -package gitutil - -import ( - "strings" - - "github.com/moby/buildkit/util/sshutil" -) - -const ( - HTTPProtocol = iota + 1 - HTTPSProtocol - SSHProtocol - GitProtocol - UnknownProtocol -) - -// ParseProtocol parses a git URL and returns the remote url and protocol type -func ParseProtocol(remote string) (string, int) { - prefixes := map[string]int{ - "http://": HTTPProtocol, - "https://": HTTPSProtocol, - "git://": GitProtocol, - "ssh://": SSHProtocol, - } - protocolType := UnknownProtocol - for prefix, potentialType := range prefixes { - if strings.HasPrefix(remote, prefix) { - remote = strings.TrimPrefix(remote, prefix) - protocolType = potentialType - } - } - - if protocolType == UnknownProtocol && sshutil.IsImplicitSSHTransport(remote) { - protocolType = SSHProtocol - } - - // remove name from ssh - if protocolType == SSHProtocol { - parts := strings.SplitN(remote, "@", 2) - if len(parts) == 2 { - remote = parts[1] - } - } - - return remote, protocolType -} diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go b/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go index da15b8aaf3a93..6d058f2d5bdd8 100644 --- a/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_ref.go @@ -1,10 +1,11 @@ package gitutil import ( - "regexp" + "net/url" "strings" "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" ) // GitRef represents a git ref. @@ -51,35 +52,51 @@ type GitRef struct { func ParseGitRef(ref string) (*GitRef, error) { res := &GitRef{} + var ( + remote *GitURL + err error + ) + if strings.HasPrefix(ref, "github.com/") { res.IndistinguishableFromLocal = true // Deprecated + remote = fromURL(&url.URL{ + Scheme: "https", + Host: "github.com", + Path: strings.TrimPrefix(ref, "github.com/"), + }) } else { - _, proto := ParseProtocol(ref) - switch proto { - case UnknownProtocol: - return nil, errdefs.ErrInvalidArgument + remote, err = ParseURL(ref) + if errors.Is(err, ErrUnknownProtocol) { + remote, err = ParseURL("https://" + ref) + } + if err != nil { + return nil, err } - switch proto { + + switch remote.Scheme { case HTTPProtocol, GitProtocol: res.UnencryptedTCP = true // Discouraged, but not deprecated } - switch proto { + + switch remote.Scheme { // An HTTP(S) URL is considered to be a valid git ref only when it has the ".git[...]" suffix. case HTTPProtocol, HTTPSProtocol: - var gitURLPathWithFragmentSuffix = regexp.MustCompile(`\.git(?:#.+)?$`) - if !gitURLPathWithFragmentSuffix.MatchString(ref) { + if !strings.HasSuffix(remote.Path, ".git") { return nil, errdefs.ErrInvalidArgument } } } - var fragment string - res.Remote, fragment, _ = strings.Cut(ref, "#") - if len(res.Remote) == 0 { - return res, errdefs.ErrInvalidArgument + res.Remote = remote.Remote + if res.IndistinguishableFromLocal { + _, res.Remote, _ = strings.Cut(res.Remote, "://") } - res.Commit, res.SubDir, _ = strings.Cut(fragment, ":") + if remote.Fragment != nil { + res.Commit, res.SubDir = remote.Fragment.Ref, remote.Fragment.Subdir + } + repoSplitBySlash := strings.Split(res.Remote, "/") res.ShortName = strings.TrimSuffix(repoSplitBySlash[len(repoSplitBySlash)-1], ".git") + return res, nil } diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_url.go b/vendor/github.com/moby/buildkit/util/gitutil/git_url.go new file mode 100644 index 0000000000000..0f1ff505c7650 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_url.go @@ -0,0 +1,132 @@ +package gitutil + +import ( + "net/url" + "regexp" + "strings" + + "github.com/moby/buildkit/util/sshutil" + "github.com/pkg/errors" +) + +const ( + HTTPProtocol string = "http" + HTTPSProtocol string = "https" + SSHProtocol string = "ssh" + GitProtocol string = "git" +) + +var ( + ErrUnknownProtocol = errors.New("unknown protocol") + ErrInvalidProtocol = errors.New("invalid protocol") +) + +var supportedProtos = map[string]struct{}{ + HTTPProtocol: {}, + HTTPSProtocol: {}, + SSHProtocol: {}, + GitProtocol: {}, +} + +var protoRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+://`) + +// URL is a custom URL type that points to a remote Git repository. +// +// URLs can be parsed from both standard URLs (e.g. +// "https://github.com/moby/buildkit.git"), as well as SCP-like URLs (e.g. +// "git@github.com:moby/buildkit.git"). +// +// See https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols +type GitURL struct { + // Scheme is the protocol over which the git repo can be accessed + Scheme string + + // Host is the remote host that hosts the git repo + Host string + // Path is the path on the host to access the repo + Path string + // User is the username/password to access the host + User *url.Userinfo + // Fragment can contain additional metadata + Fragment *GitURLFragment + + // Remote is a valid URL remote to pass into the Git CLI tooling (i.e. + // without the fragment metadata) + Remote string +} + +// GitURLFragment is the buildkit-specific metadata extracted from the fragment +// of a remote URL. +type GitURLFragment struct { + // Ref is the git reference + Ref string + // Subdir is the sub-directory inside the git repository to use + Subdir string +} + +// splitGitFragment splits a git URL fragment into its respective git +// reference and subdirectory components. +func splitGitFragment(fragment string) *GitURLFragment { + if fragment == "" { + return nil + } + ref, subdir, _ := strings.Cut(fragment, ":") + return &GitURLFragment{Ref: ref, Subdir: subdir} +} + +// ParseURL parses a BuildKit-style Git URL (that may contain additional +// fragment metadata) and returns a parsed GitURL object. +func ParseURL(remote string) (*GitURL, error) { + if proto := protoRegexp.FindString(remote); proto != "" { + proto = strings.ToLower(strings.TrimSuffix(proto, "://")) + if _, ok := supportedProtos[proto]; !ok { + return nil, errors.Wrap(ErrInvalidProtocol, proto) + } + url, err := url.Parse(remote) + if err != nil { + return nil, err + } + return fromURL(url), nil + } + + if url, err := sshutil.ParseSCPStyleURL(remote); err == nil { + return fromSCPStyleURL(url), nil + } + + return nil, ErrUnknownProtocol +} + +func IsGitTransport(remote string) bool { + if proto := protoRegexp.FindString(remote); proto != "" { + proto = strings.ToLower(strings.TrimSuffix(proto, "://")) + _, ok := supportedProtos[proto] + return ok + } + return sshutil.IsImplicitSSHTransport(remote) +} + +func fromURL(url *url.URL) *GitURL { + withoutFragment := *url + withoutFragment.Fragment = "" + return &GitURL{ + Scheme: url.Scheme, + User: url.User, + Host: url.Host, + Path: url.Path, + Fragment: splitGitFragment(url.Fragment), + Remote: withoutFragment.String(), + } +} + +func fromSCPStyleURL(url *sshutil.SCPStyleURL) *GitURL { + withoutFragment := *url + withoutFragment.Fragment = "" + return &GitURL{ + Scheme: SSHProtocol, + User: url.User, + Host: url.Host, + Path: url.Path, + Fragment: splitGitFragment(url.Fragment), + Remote: withoutFragment.String(), + } +} diff --git a/vendor/github.com/moby/buildkit/util/imageutil/config.go b/vendor/github.com/moby/buildkit/util/imageutil/config.go index f7c4182efd6b2..2202a5173eeed 100644 --- a/vendor/github.com/moby/buildkit/util/imageutil/config.go +++ b/vendor/github.com/moby/buildkit/util/imageutil/config.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "strings" "sync" "time" @@ -16,10 +15,7 @@ import ( "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" intoto "github.com/in-toto/in-toto-golang/in_toto" - "github.com/moby/buildkit/solver/pb" srctypes "github.com/moby/buildkit/source/types" - "github.com/moby/buildkit/sourcepolicy" - spb "github.com/moby/buildkit/sourcepolicy/pb" "github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/leaseutil" "github.com/moby/buildkit/util/resolver/limited" @@ -63,8 +59,7 @@ func (e ResolveToNonImageError) Error() string { return fmt.Sprintf("ref mutated by policy to non-image: %s://%s -> %s", srctypes.DockerImageScheme, e.Ref, e.Updated) } -func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, leaseManager leases.Manager, p *ocispecs.Platform, spls []*spb.Policy) (string, digest.Digest, []byte, error) { - // TODO: fix buildkit to take interface instead of struct +func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, leaseManager leases.Manager, p *ocispecs.Platform) (digest.Digest, []byte, error) { var platform platforms.MatchComparer if p != nil { platform = platforms.Only(*p) @@ -73,44 +68,13 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, cache Co } ref, err := reference.Parse(str) if err != nil { - return "", "", nil, errors.WithStack(err) - } - - op := &pb.Op{ - Op: &pb.Op_Source{ - Source: &pb.SourceOp{ - Identifier: srctypes.DockerImageScheme + "://" + ref.String(), - }, - }, - } - - mut, err := sourcepolicy.NewEngine(spls).Evaluate(ctx, op) - if err != nil { - return "", "", nil, errors.Wrap(err, "could not resolve image due to policy") - } - - if mut { - var ( - t string - ok bool - ) - t, newRef, ok := strings.Cut(op.GetSource().GetIdentifier(), "://") - if !ok { - return "", "", nil, errors.Errorf("could not parse ref: %s", op.GetSource().GetIdentifier()) - } - if ok && t != srctypes.DockerImageScheme { - return "", "", nil, &ResolveToNonImageError{Ref: str, Updated: newRef} - } - ref, err = reference.Parse(newRef) - if err != nil { - return "", "", nil, errors.WithStack(err) - } + return "", nil, errors.WithStack(err) } if leaseManager != nil { ctx2, done, err := leaseutil.WithLease(ctx, leaseManager, leases.WithExpiration(5*time.Minute), leaseutil.MakeTemporary) if err != nil { - return "", "", nil, errors.WithStack(err) + return "", nil, errors.WithStack(err) } ctx = ctx2 defer func() { @@ -141,18 +105,18 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, cache Co if desc.MediaType == "" { _, desc, err = resolver.Resolve(ctx, ref.String()) if err != nil { - return "", "", nil, err + return "", nil, err } } fetcher, err := resolver.Fetcher(ctx, ref.String()) if err != nil { - return "", "", nil, err + return "", nil, err } if desc.MediaType == images.MediaTypeDockerSchema1Manifest { dgst, dt, err := readSchema1Config(ctx, ref.String(), desc, fetcher, cache) - return ref.String(), dgst, dt, err + return dgst, dt, err } children := childrenConfigHandler(cache, platform) @@ -160,7 +124,7 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, cache Co dslHandler, err := docker.AppendDistributionSourceLabel(cache, ref.String()) if err != nil { - return "", "", nil, err + return "", nil, err } handlers := []images.Handler{ @@ -169,19 +133,19 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, cache Co children, } if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil { - return "", "", nil, err + return "", nil, err } config, err := images.Config(ctx, cache, desc, platform) if err != nil { - return "", "", nil, err + return "", nil, err } dt, err := content.ReadBlob(ctx, cache, config) if err != nil { - return "", "", nil, err + return "", nil, err } - return ref.String(), desc.Digest, dt, nil + return desc.Digest, dt, nil } func childrenConfigHandler(provider content.Provider, platform platforms.MatchComparer) images.HandlerFunc { diff --git a/vendor/github.com/moby/buildkit/util/imageutil/schema1.go b/vendor/github.com/moby/buildkit/util/imageutil/schema1.go index cd66d9123ea70..fde33421dc965 100644 --- a/vendor/github.com/moby/buildkit/util/imageutil/schema1.go +++ b/vendor/github.com/moby/buildkit/util/imageutil/schema1.go @@ -8,7 +8,7 @@ import ( "time" "github.com/containerd/containerd/remotes" - "github.com/moby/buildkit/exporter/containerimage/image" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -45,7 +45,7 @@ func convertSchema1ConfigMeta(in []byte) ([]byte, error) { return nil, errors.Errorf("invalid schema1 manifest") } - var img image.Image + var img dockerspec.DockerOCIImage if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), &img); err != nil { return nil, errors.Wrap(err, "failed to unmarshal image from schema 1 history") } diff --git a/vendor/github.com/moby/buildkit/util/leaseutil/manager.go b/vendor/github.com/moby/buildkit/util/leaseutil/manager.go index a02fb9613c2d3..42381b6d07ac9 100644 --- a/vendor/github.com/moby/buildkit/util/leaseutil/manager.go +++ b/vendor/github.com/moby/buildkit/util/leaseutil/manager.go @@ -2,10 +2,12 @@ package leaseutil import ( "context" + "sync" "time" "github.com/containerd/containerd/leases" "github.com/containerd/containerd/namespaces" + "github.com/pkg/errors" ) func WithLease(ctx context.Context, ls leases.Manager, opts ...leases.Opt) (context.Context, func(context.Context) error, error) { @@ -16,17 +18,68 @@ func WithLease(ctx context.Context, ls leases.Manager, opts ...leases.Opt) (cont }, nil } - l, err := ls.Create(ctx, append([]leases.Opt{leases.WithRandomID(), leases.WithExpiration(time.Hour)}, opts...)...) + lr, ctx, err := NewLease(ctx, ls, opts...) if err != nil { return nil, nil, err } - ctx = leases.WithLease(ctx, l.ID) return ctx, func(ctx context.Context) error { - return ls.Delete(ctx, l) + return ls.Delete(ctx, lr.l) }, nil } +func NewLease(ctx context.Context, lm leases.Manager, opts ...leases.Opt) (*LeaseRef, context.Context, error) { + l, err := lm.Create(ctx, append([]leases.Opt{leases.WithRandomID(), leases.WithExpiration(time.Hour)}, opts...)...) + if err != nil { + return nil, nil, err + } + + ctx = leases.WithLease(ctx, l.ID) + return &LeaseRef{lm: lm, l: l}, ctx, nil +} + +type LeaseRef struct { + lm leases.Manager + l leases.Lease + + once sync.Once + resources []leases.Resource + err error +} + +func (l *LeaseRef) Discard() error { + return l.lm.Delete(context.Background(), l.l) +} + +func (l *LeaseRef) Adopt(ctx context.Context) error { + l.once.Do(func() { + resources, err := l.lm.ListResources(ctx, l.l) + if err != nil { + l.err = err + return + } + l.resources = resources + }) + if l.err != nil { + return l.err + } + currentID, ok := leases.FromContext(ctx) + if !ok { + return errors.Errorf("missing lease requirement for adopt") + } + for _, r := range l.resources { + if err := l.lm.AddResource(ctx, leases.Lease{ID: currentID}, r); err != nil { + return err + } + } + if len(l.resources) == 0 { + l.Discard() + return nil + } + go l.Discard() + return nil +} + func MakeTemporary(l *leases.Lease) error { if l.Labels == nil { l.Labels = map[string]string{} diff --git a/vendor/github.com/moby/buildkit/util/network/cniprovider/bridge.go b/vendor/github.com/moby/buildkit/util/network/cniprovider/bridge.go new file mode 100644 index 0000000000000..476da9cc5d1b1 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/network/cniprovider/bridge.go @@ -0,0 +1,182 @@ +//go:build linux +// +build linux + +package cniprovider + +import ( + "context" + "fmt" + "os" + "os/exec" + "path/filepath" + + cni "github.com/containerd/go-cni" + "github.com/moby/buildkit/util/bklog" + "github.com/moby/buildkit/util/network" + "github.com/pkg/errors" + "github.com/vishvananda/netlink" +) + +func NewBridge(opt Opt) (network.Provider, error) { + cniOptions := []cni.Opt{cni.WithInterfacePrefix("eth")} + bridgeBinName := "bridge" + loopbackBinName := "loopback" + hostLocalBinName := "host-local" + firewallBinName := "firewall" + var setup bool + // binaries shipping with buildkit + for { + var dirs []string + + bridgePath, err := exec.LookPath("buildkit-cni-bridge") + if err != nil { + break + } + var bridgeDir string + bridgeDir, bridgeBinName = filepath.Split(bridgePath) + dirs = append(dirs, bridgeDir) + + loopbackPath, err := exec.LookPath("buildkit-cni-loopback") + if err != nil { + break + } + var loopbackDir string + loopbackDir, loopbackBinName = filepath.Split(loopbackPath) + if loopbackDir != bridgeDir { + dirs = append(dirs, loopbackDir) + } + + hostLocalPath, err := exec.LookPath("buildkit-cni-host-local") + if err != nil { + break + } + var hostLocalDir string + hostLocalDir, hostLocalBinName = filepath.Split(hostLocalPath) + if hostLocalDir != bridgeDir && hostLocalDir != loopbackDir { + dirs = append(dirs, hostLocalDir) + } + + firewallPath, err := exec.LookPath("buildkit-cni-firewall") + if err != nil { + break + } + var firewallDir string + firewallDir, firewallBinName = filepath.Split(firewallPath) + if firewallDir != bridgeDir && firewallDir != loopbackDir && firewallDir != hostLocalDir { + dirs = append(dirs, firewallDir) + } + + cniOptions = append(cniOptions, cni.WithPluginDir(dirs)) + setup = true + break //nolint: staticcheck + } + + if !setup { + fn := filepath.Join(opt.BinaryDir, "bridge") + if _, err := os.Stat(fn); err != nil { + return nil, errors.Wrapf(err, "failed to find CNI bridge %q or buildkit-cni-bridge", fn) + } + + cniOptions = append(cniOptions, cni.WithPluginDir([]string{opt.BinaryDir})) + } + + var firewallBackend string // empty value defaults to firewalld or iptables + if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" { + // firewalld backend is incompatible with Rootless + // https://github.com/containerd/nerdctl/issues/2818 + firewallBackend = "iptables" + } + + cniOptions = append(cniOptions, cni.WithConfListBytes([]byte(fmt.Sprintf(`{ + "cniVersion": "1.0.0", + "name": "buildkit", + "plugins": [ + { + "type": "%s" + }, + { + "type": "%s", + "bridge": "%s", + "isDefaultGateway": true, + "ipMasq": true, + "ipam": { + "type": "%s", + "ranges": [ + [ + { "subnet": "%s" } + ] + ] + } + }, + { + "type": "%s", + "backend": "%s", + "ingressPolicy": "same-bridge" + } + ] + }`, loopbackBinName, bridgeBinName, opt.BridgeName, hostLocalBinName, opt.BridgeSubnet, firewallBinName, firewallBackend)))) + + unlock, err := initLock() + if err != nil { + return nil, err + } + defer unlock() + + createBridge := true + if err := withDetachedNetNSIfAny(context.TODO(), + func(_ context.Context) error { + _, err2 := bridgeByName(opt.BridgeName) + return err2 + }); err == nil { + createBridge = false + } + + cniHandle, err := cni.New(cniOptions...) + if err != nil { + return nil, err + } + cp := &cniProvider{ + CNI: cniHandle, + root: opt.Root, + } + + if createBridge { + cp.release = func() error { + if err := withDetachedNetNSIfAny(context.TODO(), func(_ context.Context) error { + return removeBridge(opt.BridgeName) + }); err != nil { + bklog.L.Errorf("failed to remove bridge %q: %v", opt.BridgeName, err) + } + return nil + } + } + + cleanOldNamespaces(cp) + + cp.nsPool = &cniPool{targetSize: opt.PoolSize, provider: cp} + if err := cp.initNetwork(false); err != nil { + return nil, err + } + go cp.nsPool.fillPool(context.TODO()) + return cp, nil +} + +func bridgeByName(name string) (*netlink.Bridge, error) { + l, err := netlink.LinkByName(name) + if err != nil { + return nil, errors.Wrapf(err, "could not lookup %q", name) + } + br, ok := l.(*netlink.Bridge) + if !ok { + return nil, errors.Errorf("%q already exists but is not a bridge", name) + } + return br, nil +} + +func removeBridge(name string) error { + br, err := bridgeByName(name) + if err != nil { + return err + } + return netlink.LinkDel(br) +} diff --git a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni.go b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni.go index 2d37aa94a18ce..d3e106b8dee57 100644 --- a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni.go +++ b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni.go @@ -21,10 +21,12 @@ import ( const aboveTargetGracePeriod = 5 * time.Minute type Opt struct { - Root string - ConfigPath string - BinaryDir string - PoolSize int + Root string + ConfigPath string + BinaryDir string + PoolSize int + BridgeName string + BridgeSubnet string } func New(opt Opt) (network.Provider, error) { @@ -49,8 +51,13 @@ func New(opt Opt) (network.Provider, error) { cniOptions = append(cniOptions, cni.WithConfFile(opt.ConfigPath)) } - cniHandle, err := cni.New(cniOptions...) - if err != nil { + var cniHandle cni.CNI + fn := func(_ context.Context) error { + var err error + cniHandle, err = cni.New(cniOptions...) + return err + } + if err := withDetachedNetNSIfAny(context.TODO(), fn); err != nil { return nil, err } @@ -61,7 +68,7 @@ func New(opt Opt) (network.Provider, error) { cleanOldNamespaces(cp) cp.nsPool = &cniPool{targetSize: opt.PoolSize, provider: cp} - if err := cp.initNetwork(); err != nil { + if err := cp.initNetwork(true); err != nil { return nil, err } go cp.nsPool.fillPool(context.TODO()) @@ -70,17 +77,18 @@ func New(opt Opt) (network.Provider, error) { type cniProvider struct { cni.CNI - root string - nsPool *cniPool + root string + nsPool *cniPool + release func() error } -func (c *cniProvider) initNetwork() error { - if v := os.Getenv("BUILDKIT_CNI_INIT_LOCK_PATH"); v != "" { - l := flock.New(v) - if err := l.Lock(); err != nil { +func (c *cniProvider) initNetwork(lock bool) error { + if lock { + unlock, err := initLock() + if err != nil { return err } - defer l.Unlock() + defer unlock() } ns, err := c.New(context.TODO(), "") if err != nil { @@ -91,9 +99,23 @@ func (c *cniProvider) initNetwork() error { func (c *cniProvider) Close() error { c.nsPool.close() + if c.release != nil { + return c.release() + } return nil } +func initLock() (func() error, error) { + if v := os.Getenv("BUILDKIT_CNI_INIT_LOCK_PATH"); v != "" { + l := flock.New(v) + if err := l.Lock(); err != nil { + return nil, err + } + return l.Unlock, nil + } + return func() error { return nil }, nil +} + type cniPool struct { provider *cniProvider mu sync.Mutex @@ -154,7 +176,13 @@ func (pool *cniPool) get(ctx context.Context) (*cniNS, error) { } func (pool *cniPool) getNew(ctx context.Context) (*cniNS, error) { - ns, err := pool.provider.newNS(ctx, "") + var ns *cniNS + fn := func(ctx context.Context) error { + var err error + ns, err = pool.provider.newNS(ctx, "") + return err + } + err := withDetachedNetNSIfAny(ctx, fn) if err != nil { return nil, err } @@ -216,7 +244,16 @@ func (c *cniProvider) New(ctx context.Context, hostname string) (network.Namespa if hostname == "" || runtime.GOOS == "windows" { return c.nsPool.get(ctx) } - return c.newNS(ctx, hostname) + var res network.Namespace + fn := func(ctx context.Context) error { + var err error + res, err = c.newNS(ctx, hostname) + return err + } + if err := withDetachedNetNSIfAny(ctx, fn); err != nil { + return nil, err + } + return res, nil } func (c *cniProvider) newNS(ctx context.Context, hostname string) (*cniNS, error) { @@ -242,7 +279,13 @@ func (c *cniProvider) newNS(ctx context.Context, hostname string) (*cniNS, error cni.WithArgs("IgnoreUnknown", "1")) } - cniRes, err := c.CNI.Setup(context.TODO(), id, nativeID, nsOpts...) + var cniRes *cni.Result + if ctx.Value(contextKeyDetachedNetNS) == nil { + cniRes, err = c.CNI.Setup(context.TODO(), id, nativeID, nsOpts...) + } else { + // Parallel Setup cannot be used, apparently due to the goroutine issue with setns + cniRes, err = c.CNI.SetupSerially(context.TODO(), id, nativeID, nsOpts...) + } if err != nil { deleteNetNS(nativeID) return nil, errors.Wrap(err, "CNI setup error") @@ -313,7 +356,13 @@ func (ns *cniNS) Sample() (*network.Sample, error) { if !ns.canSample { return nil, nil } - s, err := ns.sample() + var s *network.Sample + fn := func(_ context.Context) error { + var err error + s, err = ns.sample() + return err + } + err := withDetachedNetNSIfAny(context.TODO(), fn) if err != nil { return nil, err } @@ -344,3 +393,8 @@ func (ns *cniNS) release() error { } return err } + +type contextKeyT string + +// contextKeyDetachedNetNS is associated with a string value that denotes RootlessKit's detached-netns. +var contextKeyDetachedNetNS = contextKeyT("buildkit/util/network/cniprovider/detached-netns") diff --git a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_linux.go b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_linux.go index 8c4ac437e1c32..56b9a127d69f4 100644 --- a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_linux.go +++ b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_linux.go @@ -1,11 +1,15 @@ package cniprovider import ( + "context" + "os" "path/filepath" "strconv" "strings" "syscall" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/util/network" "github.com/pkg/errors" ) @@ -68,3 +72,27 @@ func readFileAt(dirfd int, filename string, buf []byte) (int64, error) { } return nn, nil } + +// withDetachedNetNSIfAny executes fn in $ROOTLESSKIT_STATE_DIR/netns if it exists. +// Otherwise it executes fn in the current netns. +// +// $ROOTLESSKIT_STATE_DIR/netns exists when we are running with RootlessKit >= 2.0 with --detach-netns. +// Since we are left in the host netns, we have to join the "detached" netns that is associated with slirp +// to create CNI namespaces inside it. +// https://github.com/rootless-containers/rootlesskit/pull/379 +// https://github.com/containerd/nerdctl/pull/2723 +func withDetachedNetNSIfAny(ctx context.Context, fn func(context.Context) error) error { + if stateDir := os.Getenv("ROOTLESSKIT_STATE_DIR"); stateDir != "" { + detachedNetNS := filepath.Join(stateDir, "netns") + if _, err := os.Lstat(detachedNetNS); !errors.Is(err, os.ErrNotExist) { + return ns.WithNetNSPath(detachedNetNS, func(_ ns.NetNS) error { + ctx = context.WithValue(ctx, contextKeyDetachedNetNS, detachedNetNS) + bklog.G(ctx).Debugf("Entering RootlessKit's detached netns %q", detachedNetNS) + err2 := fn(ctx) + bklog.G(ctx).WithError(err2).Debugf("Leaving RootlessKit's detached netns %q", detachedNetNS) + return err2 + }) + } + } + return fn(ctx) +} diff --git a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_nolinux.go b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_nolinux.go index 383798b9624b7..4c7e678e0431d 100644 --- a/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_nolinux.go +++ b/vendor/github.com/moby/buildkit/util/network/cniprovider/cni_nolinux.go @@ -4,9 +4,15 @@ package cniprovider import ( + "context" + "github.com/moby/buildkit/util/network" ) func (ns *cniNS) sample() (*network.Sample, error) { return nil, nil } + +func withDetachedNetNSIfAny(ctx context.Context, fn func(context.Context) error) error { + return fn(ctx) +} diff --git a/vendor/github.com/moby/buildkit/util/network/netproviders/network.go b/vendor/github.com/moby/buildkit/util/network/netproviders/network.go index 4265b7b29b5e2..4564782bd88e6 100644 --- a/vendor/github.com/moby/buildkit/util/network/netproviders/network.go +++ b/vendor/github.com/moby/buildkit/util/network/netproviders/network.go @@ -2,6 +2,7 @@ package netproviders import ( "os" + "strconv" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/network" @@ -33,8 +34,22 @@ func Providers(opt Opt) (providers map[pb.NetMode]network.Provider, resolvedMode } defaultProvider = hostProvider resolvedMode = opt.Mode + case "bridge": + bridgeProvider, err := getBridgeProvider(opt.CNI) + if err != nil { + return nil, resolvedMode, err + } + defaultProvider = bridgeProvider + resolvedMode = "cni" case "auto", "": - if _, err := os.Stat(opt.CNI.ConfigPath); err == nil { + if v, err := strconv.ParseBool(os.Getenv("BUILDKIT_NETWORK_BRIDGE_AUTO")); v && err == nil { + bridgeProvider, err := getBridgeProvider(opt.CNI) + if err != nil { + return nil, resolvedMode, err + } + defaultProvider = bridgeProvider + resolvedMode = "cni" + } else if _, err := os.Stat(opt.CNI.ConfigPath); err == nil { cniProvider, err := cniprovider.New(opt.CNI) if err != nil { return nil, resolvedMode, err diff --git a/vendor/github.com/moby/buildkit/util/network/netproviders/network_linux.go b/vendor/github.com/moby/buildkit/util/network/netproviders/network_linux.go new file mode 100644 index 0000000000000..8ce861e34bf38 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/network/netproviders/network_linux.go @@ -0,0 +1,13 @@ +//go:build linux +// +build linux + +package netproviders + +import ( + "github.com/moby/buildkit/util/network" + "github.com/moby/buildkit/util/network/cniprovider" +) + +func getBridgeProvider(opt cniprovider.Opt) (network.Provider, error) { + return cniprovider.NewBridge(opt) +} diff --git a/vendor/github.com/moby/buildkit/util/network/netproviders/network_nobridge.go b/vendor/github.com/moby/buildkit/util/network/netproviders/network_nobridge.go new file mode 100644 index 0000000000000..8941e29dae9fd --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/network/netproviders/network_nobridge.go @@ -0,0 +1,16 @@ +//go:build freebsd || windows +// +build freebsd windows + +package netproviders + +import ( + "runtime" + + "github.com/moby/buildkit/util/network" + "github.com/moby/buildkit/util/network/cniprovider" + "github.com/pkg/errors" +) + +func getBridgeProvider(opt cniprovider.Opt) (network.Provider, error) { + return nil, errors.Errorf("bridge network is not supported on %s yet", runtime.GOOS) +} diff --git a/vendor/github.com/moby/buildkit/util/overlay/overlay_linux.go b/vendor/github.com/moby/buildkit/util/overlay/overlay_linux.go index 62179f9ce825b..8c018dfcef1f8 100644 --- a/vendor/github.com/moby/buildkit/util/overlay/overlay_linux.go +++ b/vendor/github.com/moby/buildkit/util/overlay/overlay_linux.go @@ -161,8 +161,10 @@ func Changes(ctx context.Context, changeFn fs.ChangeFunc, upperdir, upperdirView if err != nil { return err } - if ctx.Err() != nil { - return ctx.Err() + select { + case <-ctx.Done(): + return context.Cause(ctx) + default: } // Rebase path diff --git a/vendor/github.com/moby/buildkit/util/progress/multireader.go b/vendor/github.com/moby/buildkit/util/progress/multireader.go index b0d92dde8f252..d6d3fb7c79a9a 100644 --- a/vendor/github.com/moby/buildkit/util/progress/multireader.go +++ b/vendor/github.com/moby/buildkit/util/progress/multireader.go @@ -11,14 +11,15 @@ type MultiReader struct { main Reader initialized bool done chan struct{} - writers map[*progressWriter]func() + doneCause error + writers map[*progressWriter]func(error) sent []*Progress } func NewMultiReader(pr Reader) *MultiReader { mr := &MultiReader{ main: pr, - writers: make(map[*progressWriter]func()), + writers: make(map[*progressWriter]func(error)), done: make(chan struct{}), } return mr @@ -46,9 +47,9 @@ func (mr *MultiReader) Reader(ctx context.Context) Reader { go func() { if isBehind { - close := func() { + close := func(err error) { w.Close() - closeWriter() + closeWriter(err) } i := 0 for { @@ -58,11 +59,11 @@ func (mr *MultiReader) Reader(ctx context.Context) Reader { if count == 0 { select { case <-ctx.Done(): - close() + close(context.Cause(ctx)) mr.mu.Unlock() return case <-mr.done: - close() + close(mr.doneCause) mr.mu.Unlock() return default: @@ -77,7 +78,7 @@ func (mr *MultiReader) Reader(ctx context.Context) Reader { if i%100 == 0 { select { case <-ctx.Done(): - close() + close(context.Cause(ctx)) return default: } @@ -110,10 +111,12 @@ func (mr *MultiReader) handle() error { if err != nil { if err == io.EOF { mr.mu.Lock() + cancelErr := context.Canceled for w, c := range mr.writers { w.Close() - c() + c(cancelErr) } + mr.doneCause = cancelErr close(mr.done) mr.mu.Unlock() return nil diff --git a/vendor/github.com/moby/buildkit/util/progress/multiwriter.go b/vendor/github.com/moby/buildkit/util/progress/multiwriter.go index 7cce8a7ca7d2a..6810ad68b51fc 100644 --- a/vendor/github.com/moby/buildkit/util/progress/multiwriter.go +++ b/vendor/github.com/moby/buildkit/util/progress/multiwriter.go @@ -18,6 +18,8 @@ type MultiWriter struct { meta map[string]interface{} } +var _ rawProgressWriter = &MultiWriter{} + func NewMultiWriter(opts ...WriterOption) *MultiWriter { mw := &MultiWriter{ writers: map[rawProgressWriter]struct{}{}, @@ -34,6 +36,15 @@ func (ps *MultiWriter) Add(pw Writer) { if !ok { return } + if pws, ok := rw.(*MultiWriter); ok { + if pws.contains(ps) { + // this would cause a deadlock, so we should panic instead + // NOTE: this can be caused by a cycle in the scheduler states, + // which is created by a series of unfortunate edge merges + panic("multiwriter loop detected") + } + } + ps.mu.Lock() plist := make([]*Progress, 0, len(ps.items)) plist = append(plist, ps.items...) @@ -100,3 +111,24 @@ func (ps *MultiWriter) writeRawProgress(p *Progress) error { func (ps *MultiWriter) Close() error { return nil } + +func (ps *MultiWriter) contains(pw rawProgressWriter) bool { + ps.mu.Lock() + defer ps.mu.Unlock() + _, ok := ps.writers[pw] + if ok { + return true + } + + for w := range ps.writers { + w, ok := w.(*MultiWriter) + if !ok { + continue + } + if w.contains(pw) { + return true + } + } + + return false +} diff --git a/vendor/github.com/moby/buildkit/util/progress/progress.go b/vendor/github.com/moby/buildkit/util/progress/progress.go index fbbb22de071ee..fb193113a766c 100644 --- a/vendor/github.com/moby/buildkit/util/progress/progress.go +++ b/vendor/github.com/moby/buildkit/util/progress/progress.go @@ -56,7 +56,7 @@ type WriterOption func(Writer) // NewContext returns a new context and a progress reader that captures all // progress items writtern to this context. Last returned parameter is a closer // function to signal that no new writes will happen to this context. -func NewContext(ctx context.Context) (Reader, context.Context, func()) { +func NewContext(ctx context.Context) (Reader, context.Context, func(error)) { pr, pw, cancel := pipe() ctx = WithProgress(ctx, pw) return pr, ctx, cancel @@ -141,7 +141,7 @@ func (pr *progressReader) Read(ctx context.Context) ([]*Progress, error) { select { case <-ctx.Done(): pr.mu.Unlock() - return nil, ctx.Err() + return nil, context.Cause(ctx) default: } dmap := pr.dirty @@ -185,8 +185,8 @@ func (pr *progressReader) append(pw *progressWriter) { } } -func pipe() (*progressReader, *progressWriter, func()) { - ctx, cancel := context.WithCancel(context.Background()) +func pipe() (*progressReader, *progressWriter, func(error)) { + ctx, cancel := context.WithCancelCause(context.Background()) pr := &progressReader{ ctx: ctx, writers: make(map[*progressWriter]struct{}), diff --git a/vendor/github.com/moby/buildkit/util/progress/progressui/display.go b/vendor/github.com/moby/buildkit/util/progress/progressui/display.go index 4ceb4f5264e66..722fb77c64143 100644 --- a/vendor/github.com/moby/buildkit/util/progress/progressui/display.go +++ b/vendor/github.com/moby/buildkit/util/progress/progressui/display.go @@ -4,6 +4,7 @@ import ( "bytes" "container/ring" "context" + "encoding/json" "fmt" "io" "os" @@ -16,49 +17,67 @@ import ( "github.com/moby/buildkit/client" "github.com/morikuni/aec" digest "github.com/opencontainers/go-digest" + "github.com/pkg/errors" "github.com/tonistiigi/units" "github.com/tonistiigi/vt100" "golang.org/x/time/rate" ) -type displaySolveStatusOpts struct { +type displayOpts struct { phase string textDesc string consoleDesc string } -type DisplaySolveStatusOpt func(b *displaySolveStatusOpts) +func newDisplayOpts(opts ...DisplayOpt) *displayOpts { + dsso := &displayOpts{} + for _, opt := range opts { + opt(dsso) + } + return dsso +} + +type DisplayOpt func(b *displayOpts) -func WithPhase(phase string) DisplaySolveStatusOpt { - return func(b *displaySolveStatusOpts) { +func WithPhase(phase string) DisplayOpt { + return func(b *displayOpts) { b.phase = phase } } -func WithDesc(text string, console string) DisplaySolveStatusOpt { - return func(b *displaySolveStatusOpts) { +func WithDesc(text string, console string) DisplayOpt { + return func(b *displayOpts) { b.textDesc = text b.consoleDesc = console } } -func DisplaySolveStatus(ctx context.Context, c console.Console, w io.Writer, ch chan *client.SolveStatus, opts ...DisplaySolveStatusOpt) ([]client.VertexWarning, error) { - modeConsole := c != nil - - dsso := &displaySolveStatusOpts{} - for _, opt := range opts { - opt(dsso) - } - - disp := &display{c: c, phase: dsso.phase, desc: dsso.consoleDesc} - printer := &textMux{w: w, desc: dsso.textDesc} - - if disp.phase == "" { - disp.phase = "Building" - } +type Display struct { + disp display +} - t := newTrace(w, modeConsole) +type display interface { + // init initializes the display and opens any resources + // that are required. + init(displayLimiter *rate.Limiter) + + // update sends the signal to update the display. + // Some displays will have buffered output and will not + // display changes for every status update. + update(ss *client.SolveStatus) + + // refresh updates the display with the latest state. + // This method only does something with displays that + // have buffered output. + refresh() + + // done is invoked when the display will be closed. + // This method should flush any buffers and close any open + // resources that were opened by init. + done() +} +func (d Display) UpdateFrom(ctx context.Context, ch chan *client.SolveStatus) ([]client.VertexWarning, error) { tickerTimeout := 150 * time.Millisecond displayTimeout := 100 * time.Millisecond @@ -69,56 +88,228 @@ func DisplaySolveStatus(ctx context.Context, c console.Console, w io.Writer, ch } } - var done bool - ticker := time.NewTicker(tickerTimeout) - // implemented as closure because "ticker" can change - defer func() { - ticker.Stop() - }() - displayLimiter := rate.NewLimiter(rate.Every(displayTimeout), 1) + d.disp.init(displayLimiter) + defer d.disp.done() - var height int - width, _ := disp.getSize() + ticker := time.NewTicker(tickerTimeout) + defer ticker.Stop() + + var warnings []client.VertexWarning for { select { case <-ctx.Done(): - return nil, ctx.Err() + return nil, context.Cause(ctx) case <-ticker.C: + d.disp.refresh() case ss, ok := <-ch: - if ok { - t.update(ss, width) - } else { - done = true + if !ok { + return warnings, nil } - } - if modeConsole { - width, height = disp.getSize() - if done { - disp.print(t.displayInfo(), width, height, true) - t.printErrorLogs(c) - return t.warnings(), nil - } else if displayLimiter.Allow() { - ticker.Stop() - ticker = time.NewTicker(tickerTimeout) - disp.print(t.displayInfo(), width, height, false) - } - } else { - if done || displayLimiter.Allow() { - printer.print(t) - if done { - t.printErrorLogs(w) - return t.warnings(), nil - } - ticker.Stop() - ticker = time.NewTicker(tickerTimeout) + d.disp.update(ss) + for _, w := range ss.Warnings { + warnings = append(warnings, *w) } + ticker.Reset(tickerTimeout) } } } -const termHeight = 6 +type DisplayMode string + +const ( + // DefaultMode is the default value for the DisplayMode. + // This is effectively the same as AutoMode. + DefaultMode DisplayMode = "" + // AutoMode will choose TtyMode or PlainMode depending on if the output is + // a tty. + AutoMode DisplayMode = "auto" + // QuietMode discards all output. + QuietMode DisplayMode = "quiet" + // TtyMode enforces the output is a tty and will otherwise cause an error if it isn't. + TtyMode DisplayMode = "tty" + // PlainMode is the human-readable plain text output. This mode is not meant to be read + // by machines. + PlainMode DisplayMode = "plain" + // RawJSONMode is the raw JSON text output. It will marshal the various solve status events + // to JSON to be read by an external program. + RawJSONMode DisplayMode = "rawjson" +) + +// NewDisplay constructs a Display that outputs to the given io.Writer with the given DisplayMode. +// +// This method will return an error when the DisplayMode is invalid or if TtyMode is used but the io.Writer +// does not refer to a tty. AutoMode will choose TtyMode or PlainMode depending on if the output is a tty or not. +// +// For TtyMode to work, the io.Writer should also implement console.File. +func NewDisplay(out io.Writer, mode DisplayMode, opts ...DisplayOpt) (Display, error) { + switch mode { + case AutoMode, TtyMode, DefaultMode: + if c, err := consoleFromWriter(out); err == nil { + return newConsoleDisplay(c, opts...), nil + } else if mode == "tty" { + return Display{}, errors.Wrap(err, "failed to get console") + } + fallthrough + case PlainMode: + return newPlainDisplay(out, opts...), nil + case RawJSONMode: + return newRawJSONDisplay(out, opts...), nil + case QuietMode: + return newDiscardDisplay(), nil + default: + return Display{}, errors.Errorf("invalid progress mode %s", mode) + } +} + +// consoleFromWriter retrieves a console.Console from an io.Writer. +func consoleFromWriter(out io.Writer) (console.Console, error) { + f, ok := out.(console.File) + if !ok { + return nil, errors.New("output is not a file") + } + return console.ConsoleFromFile(f) +} + +type discardDisplay struct{} + +func newDiscardDisplay() Display { + return Display{disp: &discardDisplay{}} +} + +func (d *discardDisplay) init(displayLimiter *rate.Limiter) {} +func (d *discardDisplay) update(ss *client.SolveStatus) {} +func (d *discardDisplay) refresh() {} +func (d *discardDisplay) done() {} + +type consoleDisplay struct { + t *trace + disp *ttyDisplay + width, height int + displayLimiter *rate.Limiter +} + +// newConsoleDisplay creates a new Display that prints a TTY +// friendly output. +func newConsoleDisplay(c console.Console, opts ...DisplayOpt) Display { + dsso := newDisplayOpts(opts...) + if dsso.phase == "" { + dsso.phase = "Building" + } + return Display{ + disp: &consoleDisplay{ + t: newTrace(c, true), + disp: &ttyDisplay{c: c, phase: dsso.phase, desc: dsso.consoleDesc}, + }, + } +} + +func (d *consoleDisplay) init(displayLimiter *rate.Limiter) { + d.displayLimiter = displayLimiter +} + +func (d *consoleDisplay) update(ss *client.SolveStatus) { + d.width, d.height = d.disp.getSize() + d.t.update(ss, d.width) + if !d.displayLimiter.Allow() { + // Exit early as we are not allowed to update the display. + return + } + d.refresh() +} + +func (d *consoleDisplay) refresh() { + d.disp.print(d.t.displayInfo(), d.width, d.height, false) +} + +func (d *consoleDisplay) done() { + d.width, d.height = d.disp.getSize() + d.disp.print(d.t.displayInfo(), d.width, d.height, true) + d.t.printErrorLogs(d.t.w) +} + +type plainDisplay struct { + t *trace + printer *textMux + displayLimiter *rate.Limiter +} + +// newPlainDisplay creates a new Display that outputs the status +// in a human-readable plain-text format. +func newPlainDisplay(w io.Writer, opts ...DisplayOpt) Display { + dsso := newDisplayOpts(opts...) + return Display{ + disp: &plainDisplay{ + t: newTrace(w, false), + printer: &textMux{ + w: w, + desc: dsso.textDesc, + }, + }, + } +} + +func (d *plainDisplay) init(displayLimiter *rate.Limiter) { + d.displayLimiter = displayLimiter +} + +func (d *plainDisplay) update(ss *client.SolveStatus) { + if ss != nil { + d.t.update(ss, 80) + if !d.displayLimiter.Allow() { + // Exit early as we are not allowed to update the display. + return + } + } + d.refresh() +} + +func (d *plainDisplay) refresh() { + d.printer.print(d.t) +} + +func (d *plainDisplay) done() { + // Force the display to refresh. + d.refresh() + // Print error logs. + d.t.printErrorLogs(d.t.w) +} + +type rawJSONDisplay struct { + enc *json.Encoder + w io.Writer +} + +// newRawJSONDisplay creates a new Display that outputs an unbuffered +// output of status update events. +func newRawJSONDisplay(w io.Writer, opts ...DisplayOpt) Display { + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + return Display{ + disp: &rawJSONDisplay{ + enc: enc, + w: w, + }, + } +} + +func (d *rawJSONDisplay) init(displayLimiter *rate.Limiter) { + // Initialization parameters are ignored for this display. +} + +func (d *rawJSONDisplay) update(ss *client.SolveStatus) { + _ = d.enc.Encode(ss) +} + +func (d *rawJSONDisplay) refresh() { + // Unbuffered display doesn't have anything to refresh. +} + +func (d *rawJSONDisplay) done() { + // No actions needed. +} + const termPad = 10 type displayInfo struct { @@ -386,14 +577,6 @@ func newTrace(w io.Writer, modeConsole bool) *trace { } } -func (t *trace) warnings() []client.VertexWarning { - var out []client.VertexWarning - for _, v := range t.vertexes { - out = append(out, v.warnings...) - } - return out -} - func (t *trace) triggerVertexEvent(v *client.Vertex) { if v.Started == nil { return @@ -734,7 +917,7 @@ func addTime(tm *time.Time, d time.Duration) *time.Time { return &t } -type display struct { +type ttyDisplay struct { c console.Console phase string desc string @@ -742,7 +925,7 @@ type display struct { repeated bool } -func (disp *display) getSize() (int, int) { +func (disp *ttyDisplay) getSize() (int, int) { width := 80 height := 10 if disp.c != nil { @@ -789,7 +972,7 @@ func setupTerminals(jobs []*job, height int, all bool) []*job { return jobs } -func (disp *display) print(d displayInfo, width, height int, all bool) { +func (disp *ttyDisplay) print(d displayInfo, width, height int, all bool) { // this output is inspired by Buck d.jobs = setupTerminals(d.jobs, height, all) b := aec.EmptyBuilder diff --git a/vendor/github.com/moby/buildkit/util/progress/progressui/init.go b/vendor/github.com/moby/buildkit/util/progress/progressui/init.go index 75f0cb83d1dea..0bef2e23a427e 100644 --- a/vendor/github.com/moby/buildkit/util/progress/progressui/init.go +++ b/vendor/github.com/moby/buildkit/util/progress/progressui/init.go @@ -3,6 +3,7 @@ package progressui import ( "os" "runtime" + "strconv" "github.com/morikuni/aec" ) @@ -12,6 +13,8 @@ var colorCancel aec.ANSI var colorWarning aec.ANSI var colorError aec.ANSI +var termHeight = 6 + func init() { // As recommended on https://no-color.org/ if v := os.Getenv("NO_COLOR"); v != "" { @@ -34,4 +37,13 @@ func init() { envColorString := os.Getenv("BUILDKIT_COLORS") setUserDefinedTermColors(envColorString) } + + // Make the terminal height configurable at runtime. + termHeightStr := os.Getenv("BUILDKIT_TTY_LOG_LINES") + if termHeightStr != "" { + termHeightVal, err := strconv.Atoi(termHeightStr) + if err == nil && termHeightVal > 0 { + termHeight = termHeightVal + } + } } diff --git a/vendor/github.com/moby/buildkit/util/pull/pull.go b/vendor/github.com/moby/buildkit/util/pull/pull.go index 9527953c48e36..4317249f8d71a 100644 --- a/vendor/github.com/moby/buildkit/util/pull/pull.go +++ b/vendor/github.com/moby/buildkit/util/pull/pull.go @@ -6,6 +6,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" @@ -273,7 +274,7 @@ func getLayers(ctx context.Context, provider content.Provider, desc ocispecs.Des if desc.Annotations == nil { desc.Annotations = map[string]string{} } - desc.Annotations["containerd.io/uncompressed"] = diffIDs[i].String() + desc.Annotations[labels.LabelUncompressed] = diffIDs[i].String() layers[i] = desc } return layers, nil diff --git a/vendor/github.com/moby/buildkit/util/pull/pullprogress/progress.go b/vendor/github.com/moby/buildkit/util/pull/pullprogress/progress.go index 5ae047dbf549b..479a65016037e 100644 --- a/vendor/github.com/moby/buildkit/util/pull/pullprogress/progress.go +++ b/vendor/github.com/moby/buildkit/util/pull/pullprogress/progress.go @@ -31,7 +31,7 @@ func (p *ProviderWithProgress) ReaderAt(ctx context.Context, desc ocispecs.Descr return nil, err } - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) doneCh := make(chan struct{}) go trackProgress(ctx, desc, p.Manager, doneCh) return readerAtWithCancel{ReaderAt: ra, cancel: cancel, doneCh: doneCh, logger: bklog.G(ctx)}, nil @@ -39,13 +39,13 @@ func (p *ProviderWithProgress) ReaderAt(ctx context.Context, desc ocispecs.Descr type readerAtWithCancel struct { content.ReaderAt - cancel func() + cancel func(error) doneCh <-chan struct{} logger *logrus.Entry } func (ra readerAtWithCancel) Close() error { - ra.cancel() + ra.cancel(errors.WithStack(context.Canceled)) select { case <-ra.doneCh: case <-time.After(time.Second): @@ -65,7 +65,7 @@ func (f *FetcherWithProgress) Fetch(ctx context.Context, desc ocispecs.Descripto return nil, err } - ctx, cancel := context.WithCancel(ctx) + ctx, cancel := context.WithCancelCause(ctx) doneCh := make(chan struct{}) go trackProgress(ctx, desc, f.Manager, doneCh) return readerWithCancel{ReadCloser: rc, cancel: cancel, doneCh: doneCh, logger: bklog.G(ctx)}, nil @@ -73,13 +73,13 @@ func (f *FetcherWithProgress) Fetch(ctx context.Context, desc ocispecs.Descripto type readerWithCancel struct { io.ReadCloser - cancel func() + cancel func(error) doneCh <-chan struct{} logger *logrus.Entry } func (r readerWithCancel) Close() error { - r.cancel() + r.cancel(errors.WithStack(context.Canceled)) select { case <-r.doneCh: case <-time.After(time.Second): diff --git a/vendor/github.com/moby/buildkit/util/purl/image.go b/vendor/github.com/moby/buildkit/util/purl/image.go index 9eb53f6840e15..3babdba15dda3 100644 --- a/vendor/github.com/moby/buildkit/util/purl/image.go +++ b/vendor/github.com/moby/buildkit/util/purl/image.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/containerd/containerd/platforms" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" packageurl "github.com/package-url/packageurl-go" @@ -86,6 +86,21 @@ func PURLToRef(purl string) (string, *ocispecs.Platform, error) { if err != nil { return "", nil, err } + + // OS-version and OS-features are not included when serializing a + // platform as a string, however, containerd platforms.Parse appends + // missing information (including os-version) based on the host's + // platform. + // + // Given that this information is not obtained from the package-URL, + // we're resetting this information. Ideally, we'd do the same for + // "OS" and "architecture" (when not included in the URL). + // + // See: + // - https://github.com/containerd/containerd/commit/cfb30a31a8507e4417d42d38c9a99b04fc8af8a9 (https://github.com/containerd/containerd/pull/8778) + // - https://github.com/moby/buildkit/pull/4315#discussion_r1355141241 + p.OSVersion = "" + p.OSFeatures = nil platform = &p } if q.Key == "digest" { diff --git a/vendor/github.com/moby/buildkit/util/push/push.go b/vendor/github.com/moby/buildkit/util/push/push.go index bef56e5ba33c8..fcbc011d2788c 100644 --- a/vendor/github.com/moby/buildkit/util/push/push.go +++ b/vendor/github.com/moby/buildkit/util/push/push.go @@ -10,10 +10,10 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" - "github.com/containerd/containerd/log" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" - "github.com/docker/distribution/reference" + "github.com/containerd/log" + "github.com/distribution/reference" intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/moby/buildkit/session" "github.com/moby/buildkit/util/bklog" diff --git a/vendor/github.com/moby/buildkit/util/resolver/limited/group.go b/vendor/github.com/moby/buildkit/util/resolver/limited/group.go index 934bd4f4eb17c..2ab325ec561e6 100644 --- a/vendor/github.com/moby/buildkit/util/resolver/limited/group.go +++ b/vendor/github.com/moby/buildkit/util/resolver/limited/group.go @@ -10,7 +10,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" "github.com/containerd/containerd/remotes" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/moby/buildkit/util/bklog" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/sync/semaphore" diff --git a/vendor/github.com/moby/buildkit/util/resolver/pool.go b/vendor/github.com/moby/buildkit/util/resolver/pool.go index 7b6a2ef50d1f0..60bd8b04ea152 100644 --- a/vendor/github.com/moby/buildkit/util/resolver/pool.go +++ b/vendor/github.com/moby/buildkit/util/resolver/pool.go @@ -12,11 +12,14 @@ import ( "github.com/containerd/containerd/images" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" - distreference "github.com/docker/distribution/reference" + distreference "github.com/distribution/reference" "github.com/moby/buildkit/session" - "github.com/moby/buildkit/source" + "github.com/moby/buildkit/solver/pb" + log "github.com/moby/buildkit/util/bklog" "github.com/moby/buildkit/version" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // DefaultPool is the default shared resolver pool instance @@ -81,15 +84,37 @@ func (p *Pool) GetResolver(hosts docker.RegistryHosts, ref, scope string, sm *se name = named.Name() } - key := fmt.Sprintf("%s::%s", name, scope) + var key string + if strings.Contains(scope, "push") { + // When scope includes "push", index the authHandlerNS cache by session + // id(s) as well to prevent tokens with potential write access to third + // party registries from leaking between client sessions. The key will end + // up looking something like: + // 'wujskoey891qc5cv1edd3yj3p::repository:foo/bar::pull,push' + key = fmt.Sprintf("%s::%s::%s", strings.Join(session.AllSessionIDs(g), ":"), name, scope) + } else { + // The authHandlerNS is not isolated for pull-only scopes since LLB + // verticies from pulls all end up in the cache anyway and all + // requests/clients have access to the same cache + key = fmt.Sprintf("%s::%s", name, scope) + } p.mu.Lock() defer p.mu.Unlock() h, ok := p.m[key] + if !ok { h = newAuthHandlerNS(sm) p.m[key] = h } + + log.G(context.TODO()).WithFields(logrus.Fields{ + "name": name, + "scope": scope, + "key": key, + "cached": ok, + }).Debugf("checked for cached auth handler namespace") + return newResolver(hosts, h, sm, g) } @@ -125,7 +150,7 @@ type Resolver struct { auth *dockerAuthorizer is images.Store - mode source.ResolveMode + mode ResolveMode } // HostsFunc implements registry configuration of this Resolver @@ -177,7 +202,7 @@ func (r *Resolver) WithSession(s session.Group) *Resolver { } // WithImageStore returns new resolver that can also resolve from local images store -func (r *Resolver) WithImageStore(is images.Store, mode source.ResolveMode) *Resolver { +func (r *Resolver) WithImageStore(is images.Store, mode ResolveMode) *Resolver { r2 := *r r2.Resolver = r.Resolver r2.is = is @@ -195,7 +220,7 @@ func (r *Resolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, er // Resolve attempts to resolve the reference into a name and descriptor. func (r *Resolver) Resolve(ctx context.Context, ref string) (string, ocispecs.Descriptor, error) { - if r.mode == source.ResolveModePreferLocal && r.is != nil { + if r.mode == ResolveModePreferLocal && r.is != nil { if img, err := r.is.Get(ctx, ref); err == nil { return ref, img.Target, nil } @@ -207,7 +232,7 @@ func (r *Resolver) Resolve(ctx context.Context, ref string) (string, ocispecs.De return n, desc, nil } - if r.mode == source.ResolveModeDefault && r.is != nil { + if r.mode == ResolveModeDefault && r.is != nil { if img, err := r.is.Get(ctx, ref); err == nil { return ref, img.Target, nil } @@ -215,3 +240,37 @@ func (r *Resolver) Resolve(ctx context.Context, ref string) (string, ocispecs.De return "", ocispecs.Descriptor{}, err } + +type ResolveMode int + +const ( + ResolveModeDefault ResolveMode = iota + ResolveModeForcePull + ResolveModePreferLocal +) + +func (r ResolveMode) String() string { + switch r { + case ResolveModeDefault: + return pb.AttrImageResolveModeDefault + case ResolveModeForcePull: + return pb.AttrImageResolveModeForcePull + case ResolveModePreferLocal: + return pb.AttrImageResolveModePreferLocal + default: + return "" + } +} + +func ParseImageResolveMode(v string) (ResolveMode, error) { + switch v { + case pb.AttrImageResolveModeDefault, "": + return ResolveModeDefault, nil + case pb.AttrImageResolveModeForcePull: + return ResolveModeForcePull, nil + case pb.AttrImageResolveModePreferLocal: + return ResolveModePreferLocal, nil + default: + return 0, errors.Errorf("invalid resolvemode: %s", v) + } +} diff --git a/vendor/github.com/moby/buildkit/util/resolver/resolver.go b/vendor/github.com/moby/buildkit/util/resolver/resolver.go index a3327214632de..d7f0d9d0b2703 100644 --- a/vendor/github.com/moby/buildkit/util/resolver/resolver.go +++ b/vendor/github.com/moby/buildkit/util/resolver/resolver.go @@ -209,17 +209,17 @@ func newDefaultTransport() *http.Transport { } type httpFallback struct { - super http.RoundTripper - fallback bool + super http.RoundTripper + host string } func (f *httpFallback) RoundTrip(r *http.Request) (*http.Response, error) { - if !f.fallback { + // only fall back if the same host had previously fell back + if f.host != r.URL.Host { resp, err := f.super.RoundTrip(r) var tlsErr tls.RecordHeaderError if errors.As(err, &tlsErr) && string(tlsErr.RecordHeader[:]) == "HTTP/" { - // Server gave HTTP response to HTTPS client - f.fallback = true + f.host = r.URL.Host } else { return resp, err } diff --git a/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go b/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go new file mode 100644 index 0000000000000..10491f32f08e3 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/sshutil/scpurl.go @@ -0,0 +1,43 @@ +package sshutil + +import ( + "errors" + "fmt" + "net/url" + "regexp" +) + +var gitSSHRegex = regexp.MustCompile("^([a-zA-Z0-9-_]+)@([a-zA-Z0-9-.]+):(.*?)(?:#(.*))?$") + +func IsImplicitSSHTransport(s string) bool { + return gitSSHRegex.MatchString(s) +} + +type SCPStyleURL struct { + User *url.Userinfo + Host string + + Path string + Fragment string +} + +func ParseSCPStyleURL(raw string) (*SCPStyleURL, error) { + matches := gitSSHRegex.FindStringSubmatch(raw) + if matches == nil { + return nil, errors.New("invalid scp-style url") + } + return &SCPStyleURL{ + User: url.User(matches[1]), + Host: matches[2], + Path: matches[3], + Fragment: matches[4], + }, nil +} + +func (url *SCPStyleURL) String() string { + base := fmt.Sprintf("%s@%s:%s", url.User.String(), url.Host, url.Path) + if url.Fragment == "" { + return base + } + return base + "#" + url.Fragment +} diff --git a/vendor/github.com/moby/buildkit/util/sshutil/transport_validation.go b/vendor/github.com/moby/buildkit/util/sshutil/transport_validation.go deleted file mode 100644 index c50a2cc7f95da..0000000000000 --- a/vendor/github.com/moby/buildkit/util/sshutil/transport_validation.go +++ /dev/null @@ -1,11 +0,0 @@ -package sshutil - -import ( - "regexp" -) - -var gitSSHRegex = regexp.MustCompile("^[a-zA-Z0-9-_]+@[a-zA-Z0-9-.]+:.*$") - -func IsImplicitSSHTransport(s string) bool { - return gitSSHRegex.MatchString(s) -} diff --git a/vendor/github.com/moby/buildkit/util/stack/stack.pb.go b/vendor/github.com/moby/buildkit/util/stack/stack.pb.go index 43809d4876101..ad4a903c07c67 100644 --- a/vendor/github.com/moby/buildkit/util/stack/stack.pb.go +++ b/vendor/github.com/moby/buildkit/util/stack/stack.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.11.4 // source: stack.proto diff --git a/vendor/github.com/moby/buildkit/util/stack/stack.proto b/vendor/github.com/moby/buildkit/util/stack/stack.proto index 9c63bc3626c19..56a696d20cb3d 100644 --- a/vendor/github.com/moby/buildkit/util/stack/stack.proto +++ b/vendor/github.com/moby/buildkit/util/stack/stack.proto @@ -3,15 +3,15 @@ syntax = "proto3"; package stack; message Stack { - repeated Frame frames = 1; - repeated string cmdline = 2; - int32 pid = 3; - string version = 4; - string revision = 5; + repeated Frame frames = 1; + repeated string cmdline = 2; + int32 pid = 3; + string version = 4; + string revision = 5; } message Frame { - string Name = 1; - string File = 2; - int32 Line = 3; + string Name = 1; + string File = 2; + int32 Line = 3; } \ No newline at end of file diff --git a/vendor/github.com/moby/buildkit/util/staticfs/merge.go b/vendor/github.com/moby/buildkit/util/staticfs/merge.go index d680b80cfcce1..c5a582a5ffe5a 100644 --- a/vendor/github.com/moby/buildkit/util/staticfs/merge.go +++ b/vendor/github.com/moby/buildkit/util/staticfs/merge.go @@ -5,7 +5,6 @@ import ( "io" "io/fs" "os" - "path/filepath" "github.com/tonistiigi/fsutil" "golang.org/x/sync/errgroup" @@ -26,9 +25,9 @@ func NewMergeFS(lower, upper fsutil.FS) *MergeFS { } type record struct { - path string - fi fs.FileInfo - err error + path string + entry fs.DirEntry + err error } func (r *record) key() string { @@ -38,29 +37,29 @@ func (r *record) key() string { return convertPathToKey(r.path) } -func (mfs *MergeFS) Walk(ctx context.Context, fn filepath.WalkFunc) error { +func (mfs *MergeFS) Walk(ctx context.Context, target string, fn fs.WalkDirFunc) error { ch1 := make(chan *record, 10) ch2 := make(chan *record, 10) eg, ctx := errgroup.WithContext(ctx) eg.Go(func() error { defer close(ch1) - return mfs.Lower.Walk(ctx, func(path string, info fs.FileInfo, err error) error { + return mfs.Lower.Walk(ctx, target, func(path string, entry fs.DirEntry, err error) error { select { - case ch1 <- &record{path: path, fi: info, err: err}: + case ch1 <- &record{path: path, entry: entry, err: err}: case <-ctx.Done(): } - return ctx.Err() + return context.Cause(ctx) }) }) eg.Go(func() error { defer close(ch2) - return mfs.Upper.Walk(ctx, func(path string, info fs.FileInfo, err error) error { + return mfs.Upper.Walk(ctx, target, func(path string, entry fs.DirEntry, err error) error { select { - case ch2 <- &record{path: path, fi: info, err: err}: + case ch2 <- &record{path: path, entry: entry, err: err}: case <-ctx.Done(): } - return ctx.Err() + return context.Cause(ctx) }) }) @@ -75,13 +74,13 @@ func (mfs *MergeFS) Walk(ctx context.Context, fn filepath.WalkFunc) error { break } if !ok2 || ok1 && key1 < key2 { - if err := fn(next1.path, next1.fi, next1.err); err != nil { + if err := fn(next1.path, next1.entry, next1.err); err != nil { return err } next1, ok1 = <-ch1 key1 = next1.key() } else if !ok1 || ok2 && key1 >= key2 { - if err := fn(next2.path, next2.fi, next2.err); err != nil { + if err := fn(next2.path, next2.entry, next2.err); err != nil { return err } if ok1 && key1 == key2 { diff --git a/vendor/github.com/moby/buildkit/util/staticfs/static.go b/vendor/github.com/moby/buildkit/util/staticfs/static.go index 3b00060688f0a..3cfc501692182 100644 --- a/vendor/github.com/moby/buildkit/util/staticfs/static.go +++ b/vendor/github.com/moby/buildkit/util/staticfs/static.go @@ -4,8 +4,8 @@ import ( "bytes" "context" "io" + "io/fs" "os" - "path/filepath" "sort" "strings" @@ -31,6 +31,7 @@ func NewFS() *FS { } func (fs *FS) Add(p string, stat types.Stat, data []byte) { + p = strings.TrimPrefix(p, "/") stat.Size_ = int64(len(data)) if stat.Mode == 0 { stat.Mode = 0644 @@ -42,16 +43,20 @@ func (fs *FS) Add(p string, stat types.Stat, data []byte) { } } -func (fs *FS) Walk(ctx context.Context, fn filepath.WalkFunc) error { +func (fs *FS) Walk(ctx context.Context, target string, fn fs.WalkDirFunc) error { + target = strings.TrimPrefix(target, "/") keys := make([]string, 0, len(fs.files)) for k := range fs.files { + if !strings.HasPrefix(k, target) { + continue + } keys = append(keys, convertPathToKey(k)) } sort.Strings(keys) for _, k := range keys { p := convertKeyToPath(k) st := fs.files[p].Stat - if err := fn(p, &fsutil.StatInfo{Stat: &st}, nil); err != nil { + if err := fn(p, &fsutil.DirEntryInfo{Stat: &st}, nil); err != nil { return err } } diff --git a/vendor/github.com/moby/buildkit/util/system/atime_windows.go b/vendor/github.com/moby/buildkit/util/system/atime_windows.go index 808408b613cfb..cd5190fceb4c3 100644 --- a/vendor/github.com/moby/buildkit/util/system/atime_windows.go +++ b/vendor/github.com/moby/buildkit/util/system/atime_windows.go @@ -1,16 +1,17 @@ package system import ( - "fmt" iofs "io/fs" "syscall" "time" + + "github.com/pkg/errors" ) func Atime(st iofs.FileInfo) (time.Time, error) { stSys, ok := st.Sys().(*syscall.Win32FileAttributeData) if !ok { - return time.Time{}, fmt.Errorf("expected st.Sys() to be *syscall.Win32FileAttributeData, got %T", st.Sys()) + return time.Time{}, errors.Errorf("expected st.Sys() to be *syscall.Win32FileAttributeData, got %T", st.Sys()) } // ref: https://github.com/golang/go/blob/go1.19.2/src/os/types_windows.go#L230 return time.Unix(0, stSys.LastAccessTime.Nanoseconds()), nil diff --git a/vendor/github.com/moby/buildkit/util/tracing/detect/detect.go b/vendor/github.com/moby/buildkit/util/tracing/detect/detect.go index f05c51d67002a..ef6989312722b 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/detect/detect.go +++ b/vendor/github.com/moby/buildkit/util/tracing/detect/detect.go @@ -10,13 +10,18 @@ import ( "github.com/moby/buildkit/util/bklog" "github.com/pkg/errors" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/prometheus" + "go.opentelemetry.io/otel/metric" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.17.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) -type ExporterDetector func() (sdktrace.SpanExporter, error) +type ExporterDetector func() (sdktrace.SpanExporter, sdkmetric.Exporter, error) type detector struct { f ExporterDetector @@ -26,12 +31,14 @@ type detector struct { var ServiceName string var Recorder *TraceRecorder -var Resource *resource.Resource - var detectors map[string]detector var once sync.Once var tp trace.TracerProvider -var exporter sdktrace.SpanExporter +var mp metric.MeterProvider +var exporter struct { + SpanExporter sdktrace.SpanExporter + MetricExporter sdkmetric.Exporter +} var closers []func(context.Context) error var err error @@ -45,14 +52,14 @@ func Register(name string, exp ExporterDetector, priority int) { } } -func detectExporter() (sdktrace.SpanExporter, error) { +func detectExporter() (texp sdktrace.SpanExporter, mexp sdkmetric.Exporter, err error) { if n := os.Getenv("OTEL_TRACES_EXPORTER"); n != "" { d, ok := detectors[n] if !ok { if n == "none" { - return nil, nil + return nil, nil, nil } - return nil, errors.Errorf("unsupported opentelemetry tracer %v", n) + return nil, nil, errors.Errorf("unsupported opentelemetry tracer %v", n) } return d.f() } @@ -63,90 +70,135 @@ func detectExporter() (sdktrace.SpanExporter, error) { sort.Slice(arr, func(i, j int) bool { return arr[i].priority < arr[j].priority }) + for _, d := range arr { - exp, err := d.f() + t, m, err := d.f() if err != nil { - return nil, err + return nil, nil, err } - if exp != nil { - return exp, nil + if texp == nil { + texp = t + } + if mexp == nil { + mexp = m + } + + // Found a candidate for both exporters so just return now. + if texp != nil && mexp != nil { + return texp, mexp, nil } } - return nil, nil + return texp, mexp, nil } -func getExporter() (sdktrace.SpanExporter, error) { - exp, err := detectExporter() +func getExporters() (sdktrace.SpanExporter, sdkmetric.Exporter, error) { + texp, mexp, err := detectExporter() if err != nil { - return nil, err + return nil, nil, err } if Recorder != nil { - Recorder.SpanExporter = exp - exp = Recorder + Recorder.SpanExporter = texp + texp = Recorder } - return exp, nil + + return texp, mexp, nil } func detect() error { - tp = trace.NewNoopTracerProvider() + tp = noop.NewTracerProvider() + mp = sdkmetric.NewMeterProvider() - exp, err := getExporter() - if err != nil || exp == nil { + texp, mexp, err := getExporters() + if err != nil || (texp == nil && mexp == nil) { return err } + res := Resource() + // enable log with traceID when valid exporter - bklog.EnableLogWithTraceID(true) + if texp != nil { + bklog.EnableLogWithTraceID(true) - if Resource == nil { - res, err := resource.Detect(context.Background(), serviceNameDetector{}) - if err != nil { - return err - } - res, err = resource.Merge(resource.Default(), res) - if err != nil { - return err + sp := sdktrace.NewBatchSpanProcessor(texp) + + if Recorder != nil { + Recorder.flush = sp.ForceFlush } - Resource = res + + sdktp := sdktrace.NewTracerProvider( + sdktrace.WithSpanProcessor(sp), + sdktrace.WithResource(res), + ) + closers = append(closers, sdktp.Shutdown) + + exporter.SpanExporter = texp + tp = sdktp } - sp := sdktrace.NewBatchSpanProcessor(exp) + var readers []sdkmetric.Reader + if mexp != nil { + // Create a new periodic reader using any configured metric exporter. + readers = append(readers, sdkmetric.NewPeriodicReader(mexp)) + } - if Recorder != nil { - Recorder.flush = sp.ForceFlush + if r, err := prometheus.New(); err != nil { + // Log the error but do not fail if we could not configure the prometheus metrics. + bklog.G(context.Background()). + WithError(err). + Error("failed prometheus metrics configuration") + } else { + // Register the prometheus reader if there was no error. + readers = append(readers, r) } - sdktp := sdktrace.NewTracerProvider( - sdktrace.WithSpanProcessor(sp), - sdktrace.WithResource(Resource), - ) - closers = append(closers, sdktp.Shutdown) + if len(readers) > 0 { + opts := make([]sdkmetric.Option, 0, len(readers)+1) + opts = append(opts, sdkmetric.WithResource(res)) + for _, r := range readers { + opts = append(opts, sdkmetric.WithReader(r)) + } + sdkmp := sdkmetric.NewMeterProvider(opts...) + closers = append(closers, sdkmp.Shutdown) - exporter = exp - tp = sdktp + exporter.MetricExporter = mexp + mp = sdkmp + } return nil } func TracerProvider() (trace.TracerProvider, error) { + if err := detectOnce(); err != nil { + return nil, err + } + return tp, nil +} + +func MeterProvider() (metric.MeterProvider, error) { + if err := detectOnce(); err != nil { + return nil, err + } + return mp, nil +} + +func detectOnce() error { once.Do(func() { if err1 := detect(); err1 != nil { - err = err1 + b, _ := strconv.ParseBool(os.Getenv("OTEL_IGNORE_ERROR")) + if !b { + err = err1 + } } }) - b, _ := strconv.ParseBool(os.Getenv("OTEL_IGNORE_ERROR")) - if err != nil && !b { - return nil, err - } - return tp, nil + return err } -func Exporter() (sdktrace.SpanExporter, error) { +func Exporter() (sdktrace.SpanExporter, sdkmetric.Exporter, error) { _, err := TracerProvider() if err != nil { - return nil, err + return nil, nil, err } - return exporter, nil + return exporter.SpanExporter, exporter.MetricExporter, nil } func Shutdown(ctx context.Context) error { @@ -158,6 +210,35 @@ func Shutdown(ctx context.Context) error { return nil } +var ( + detectedResource *resource.Resource + detectedResourceOnce sync.Once +) + +func Resource() *resource.Resource { + detectedResourceOnce.Do(func() { + res, err := resource.New(context.Background(), + resource.WithDetectors(serviceNameDetector{}), + resource.WithFromEnv(), + resource.WithTelemetrySDK(), + ) + if err != nil { + otel.Handle(err) + } + detectedResource = res + }) + return detectedResource +} + +// OverrideResource overrides the resource returned from Resource. +// +// This must be invoked before Resource is called otherwise it is a no-op. +func OverrideResource(res *resource.Resource) { + detectedResourceOnce.Do(func() { + detectedResource = res + }) +} + type serviceNameDetector struct{} func (serviceNameDetector) Detect(ctx context.Context) (*resource.Resource, error) { @@ -165,9 +246,6 @@ func (serviceNameDetector) Detect(ctx context.Context) (*resource.Resource, erro semconv.SchemaURL, semconv.ServiceNameKey, func() (string, error) { - if n := os.Getenv("OTEL_SERVICE_NAME"); n != "" { - return n, nil - } if ServiceName != "" { return ServiceName, nil } diff --git a/vendor/github.com/moby/buildkit/util/tracing/detect/otlp.go b/vendor/github.com/moby/buildkit/util/tracing/detect/otlp.go index aa68f876ef208..4cb49ed8b5fd0 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/detect/otlp.go +++ b/vendor/github.com/moby/buildkit/util/tracing/detect/otlp.go @@ -5,9 +5,13 @@ import ( "os" "github.com/pkg/errors" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -15,7 +19,20 @@ func init() { Register("otlp", otlpExporter, 10) } -func otlpExporter() (sdktrace.SpanExporter, error) { +func otlpExporter() (sdktrace.SpanExporter, sdkmetric.Exporter, error) { + texp, err := otlpSpanExporter() + if err != nil { + return nil, nil, err + } + + mexp, err := otlpMetricExporter() + if err != nil { + return nil, nil, err + } + return texp, mexp, nil +} + +func otlpSpanExporter() (sdktrace.SpanExporter, error) { set := os.Getenv("OTEL_TRACES_EXPORTER") == "otlp" || os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") != "" || os.Getenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") != "" if !set { return nil, nil @@ -43,3 +60,36 @@ func otlpExporter() (sdktrace.SpanExporter, error) { return otlptrace.New(context.Background(), c) } + +func otlpMetricExporter() (sdkmetric.Exporter, error) { + set := os.Getenv("OTEL_METRICS_EXPORTER") == "otlp" || os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") != "" || os.Getenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT") != "" + if !set { + return nil, nil + } + + proto := os.Getenv("OTEL_EXPORTER_OTLP_METRICS_PROTOCOL") + if proto == "" { + proto = os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL") + } + if proto == "" { + proto = "grpc" + } + + switch proto { + case "grpc": + return otlpmetricgrpc.New(context.Background(), + otlpmetricgrpc.WithTemporalitySelector(deltaTemporality), + ) + case "http/protobuf": + return otlpmetrichttp.New(context.Background(), + otlpmetrichttp.WithTemporalitySelector(deltaTemporality), + ) + // case "http/json": // unsupported by library + default: + return nil, errors.Errorf("unsupported otlp protocol %v", proto) + } +} + +func deltaTemporality(_ sdkmetric.InstrumentKind) metricdata.Temporality { + return metricdata.DeltaTemporality +} diff --git a/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/client.go b/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/client.go index e8d13301f3d53..5d54b14129445 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/client.go +++ b/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/client.go @@ -70,9 +70,10 @@ func (c *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc } ctx, cancel := c.connection.ContextWithStop(ctx) - defer cancel() - ctx, tCancel := context.WithTimeout(ctx, 30*time.Second) - defer tCancel() + defer cancel(errors.WithStack(context.Canceled)) + ctx, tCancel := context.WithCancelCause(ctx) + ctx, _ = context.WithTimeoutCause(ctx, 30*time.Second, errors.WithStack(context.DeadlineExceeded)) + defer tCancel(errors.WithStack(context.Canceled)) ctx = c.connection.ContextWithMetadata(ctx) err := func() error { diff --git a/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/connection.go b/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/connection.go index dbb0fcd39f476..6b52d3594e93a 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/connection.go +++ b/vendor/github.com/moby/buildkit/util/tracing/otlptracegrpc/connection.go @@ -22,6 +22,7 @@ import ( "time" "unsafe" + "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) @@ -185,7 +186,7 @@ func (c *Connection) Shutdown(ctx context.Context) error { select { case <-c.backgroundConnectionDoneCh: case <-ctx.Done(): - return ctx.Err() + return context.Cause(ctx) } c.mu.Lock() @@ -200,17 +201,17 @@ func (c *Connection) Shutdown(ctx context.Context) error { return nil } -func (c *Connection) ContextWithStop(ctx context.Context) (context.Context, context.CancelFunc) { +func (c *Connection) ContextWithStop(ctx context.Context) (context.Context, context.CancelCauseFunc) { // Unify the parent context Done signal with the Connection's // stop channel. - ctx, cancel := context.WithCancel(ctx) - go func(ctx context.Context, cancel context.CancelFunc) { + ctx, cancel := context.WithCancelCause(ctx) + go func(ctx context.Context, cancel context.CancelCauseFunc) { select { case <-ctx.Done(): // Nothing to do, either cancelled or deadline // happened. case <-c.stopCh: - cancel() + cancel(errors.WithStack(context.Canceled)) } }(ctx, cancel) return ctx, cancel diff --git a/vendor/github.com/moby/buildkit/util/tracing/tracing.go b/vendor/github.com/moby/buildkit/util/tracing/tracing.go index 97f538f575082..8fb1dcbde39e3 100644 --- a/vendor/github.com/moby/buildkit/util/tracing/tracing.go +++ b/vendor/github.com/moby/buildkit/util/tracing/tracing.go @@ -14,13 +14,14 @@ import ( "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) // StartSpan starts a new span as a child of the span in context. // If there is no span in context then this is a no-op. func StartSpan(ctx context.Context, operationName string, opts ...trace.SpanStartOption) (trace.Span, context.Context) { parent := trace.SpanFromContext(ctx) - tracer := trace.NewNoopTracerProvider().Tracer("") + tracer := noop.NewTracerProvider().Tracer("") if parent != nil && parent.SpanContext().IsValid() { tracer = parent.TracerProvider().Tracer("") } diff --git a/vendor/github.com/moby/buildkit/util/windows/util_windows.go b/vendor/github.com/moby/buildkit/util/windows/util_windows.go new file mode 100644 index 0000000000000..135968a6fae42 --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/windows/util_windows.go @@ -0,0 +1,155 @@ +package windows + +import ( + "bytes" + "context" + "encoding/json" + "strings" + "syscall" + + "github.com/containerd/containerd/mount" + "github.com/docker/docker/pkg/idtools" + "github.com/moby/buildkit/executor" + "github.com/moby/buildkit/snapshot" + "github.com/pkg/errors" +) + +func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount []mount.Mount, userName string) (idtools.Identity, error) { + // This is a shortcut in case the user is one of the builtin users that should exist + // in any WCOW container. While these users do exist in containers, they don't exist on the + // host. We check them before trying to look them up using LookupSID(). + if strings.EqualFold(userName, "ContainerAdministrator") || userName == "" { + return idtools.Identity{SID: idtools.ContainerAdministratorSidString}, nil + } else if strings.EqualFold(userName, "ContainerUser") { + return idtools.Identity{SID: idtools.ContainerUserSidString}, nil + } + + // We might have a SID set as username. There is no guarantee that this SID will exist + // inside the container, even if we can successfully parse it. If a SID was used, we trust + // that the user has made sure it does map to an identity inside the container. + if strings.HasPrefix(strings.ToLower(userName), "s-") { + if _, err := syscall.StringToSid(userName); err == nil { + return idtools.Identity{SID: userName}, nil + } + } + + // We test for well known accounts that should exist inside any system. This has the potential + // to fail if the usernames/group names differ in the container, as is the case on internationalized + // versions where the builtin account and group names may have names in the local language. + // If the user specified an internationalized version of the account name, but the host is in English, + // this lookup will most likely fail and we will fall back to running get-account-info inside the container. + // This should however catch most of the cases when well known accounts/groups are used. + sid, _, accountType, err := syscall.LookupSID("", userName) + if err == nil { + if accountType == syscall.SidTypeAlias || accountType == syscall.SidTypeWellKnownGroup { + sidAsString, err := sid.String() + if err == nil { + return idtools.Identity{SID: sidAsString}, nil + } + } + } + + // Last resort. + // The equivalent in Windows of /etc/passwd and /etc/group is a registry hive called SAM which can be found + // on any windows system in: C:\Windows\System32\config\SAM. + // + // This hive holds all user information on a particular system, including the SID of the user we care + // about. The bad news is that the data structures in this hive are completely undocumented and there + // is no API we can call to load the security info inside an offline SAM hive. We can load it as a + // registry hive, but parsing the data structures it holds is not documented. It's not impossible to do, + // but in the absence of a supported API to do this for us, we risk that sometime in the future our parser + // will break. + // + // That being said, we have no choice but to execute a command inside the rootMount and attempt to get the + // SID of the user we care about using officially supported Windows APIs. This obviously adds some overhead. + // + // TODO(gsamfira): Should we use a snapshot of the rootMount? + ident, err := GetUserIdentFromContainer(ctx, exec, rootMount, userName) + if err != nil { + return idtools.Identity{}, errors.Wrap(err, "getting account SID from container") + } + return ident, nil +} + +func GetUserIdentFromContainer(ctx context.Context, exec executor.Executor, rootMounts []mount.Mount, userName string) (idtools.Identity, error) { + var ident idtools.Identity + + if len(rootMounts) > 1 { + return ident, errors.Errorf("unexpected number of root mounts: %d", len(rootMounts)) + } + + stdout := &bytesReadWriteCloser{ + bw: &bytes.Buffer{}, + } + stderr := &bytesReadWriteCloser{ + bw: &bytes.Buffer{}, + } + + defer stdout.Close() + defer stderr.Close() + + procInfo := executor.ProcessInfo{ + Meta: executor.Meta{ + Args: []string{"get-user-info", userName}, + User: "ContainerAdministrator", + Cwd: "/", + }, + Stdin: nil, + Stdout: stdout, + Stderr: stderr, + } + + if _, err := exec.Run(ctx, "", newStubMountable(rootMounts), nil, procInfo, nil); err != nil { + return ident, errors.Wrap(err, "executing command") + } + + data := stdout.bw.Bytes() + if err := json.Unmarshal(data, &ident); err != nil { + return ident, errors.Wrap(err, "reading user info") + } + + return ident, nil +} + +type bytesReadWriteCloser struct { + bw *bytes.Buffer +} + +func (b *bytesReadWriteCloser) Write(p []byte) (int, error) { + if b.bw == nil { + return 0, errors.Errorf("invalid bytes buffer") + } + return b.bw.Write(p) +} + +func (b *bytesReadWriteCloser) Close() error { + if b.bw == nil { + return nil + } + b.bw.Reset() + return nil +} + +type snapshotMountable struct { + m []mount.Mount +} + +func (m *snapshotMountable) Mount() ([]mount.Mount, func() error, error) { + cleanup := func() error { return nil } + return m.m, cleanup, nil +} +func (m *snapshotMountable) IdentityMapping() *idtools.IdentityMapping { + return nil +} + +type executorMountable struct { + m snapshot.Mountable +} + +func (m *executorMountable) Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error) { + return m.m, nil +} + +func newStubMountable(m []mount.Mount) executor.Mount { + return executor.Mount{Src: &executorMountable{m: &snapshotMountable{m: m}}} +} diff --git a/vendor/github.com/moby/buildkit/util/winlayers/differ.go b/vendor/github.com/moby/buildkit/util/winlayers/differ.go index effe0c16cb4a1..b4c7fdd91894e 100644 --- a/vendor/github.com/moby/buildkit/util/winlayers/differ.go +++ b/vendor/github.com/moby/buildkit/util/winlayers/differ.go @@ -14,6 +14,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/labels" "github.com/containerd/containerd/mount" log "github.com/moby/buildkit/util/bklog" digest "github.com/opencontainers/go-digest" @@ -121,7 +122,7 @@ func (s *winDiffer) Compare(ctx context.Context, lower, upper []mount.Mount, opt if config.Labels == nil { config.Labels = map[string]string{} } - config.Labels["containerd.io/uncompressed"] = dgstr.Digest().String() + config.Labels[labels.LabelUncompressed] = dgstr.Digest().String() } else { w, discard, done := makeWindowsLayer(ctx, cw) if err = archive.WriteDiff(ctx, w, lowerRoot, upperRoot); err != nil { diff --git a/vendor/github.com/moby/buildkit/worker/base/worker.go b/vendor/github.com/moby/buildkit/worker/base/worker.go index dcea020cb1f8c..8072abba21d1e 100644 --- a/vendor/github.com/moby/buildkit/worker/base/worker.go +++ b/vendor/github.com/moby/buildkit/worker/base/worker.go @@ -18,7 +18,7 @@ import ( "github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache/metadata" "github.com/moby/buildkit/client" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/executor/resources" "github.com/moby/buildkit/exporter" @@ -365,16 +365,65 @@ func (w *Worker) PruneCacheMounts(ctx context.Context, ids []string) error { return nil } -func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) { - // is this an registry source? Or an OCI layout source? - switch opt.ResolverType { - case llb.ResolverTypeOCILayout: - return w.OCILayoutSource.ResolveImageConfig(ctx, ref, opt, sm, g) - // we probably should put an explicit case llb.ResolverTypeRegistry and default here, - // but then go complains that we do not have a return statement, - // so we just add it after +func (w *Worker) ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (*sourceresolver.MetaResponse, error) { + if opt.SourcePolicies != nil { + return nil, errors.New("source policies can not be set for worker") } - return w.ImageSource.ResolveImageConfig(ctx, ref, opt, sm, g) + + var platform *pb.Platform + if p := opt.Platform; p != nil { + platform = &pb.Platform{ + Architecture: p.Architecture, + OS: p.OS, + Variant: p.Variant, + OSVersion: p.OSVersion, + } + } + + id, err := w.SourceManager.Identifier(&pb.Op_Source{Source: op}, platform) + if err != nil { + return nil, err + } + + switch idt := id.(type) { + case *containerimage.ImageIdentifier: + if opt.ImageOpt == nil { + opt.ImageOpt = &sourceresolver.ResolveImageOpt{} + } + dgst, config, err := w.ImageSource.ResolveImageConfig(ctx, idt.Reference.String(), opt, sm, g) + if err != nil { + return nil, err + } + return &sourceresolver.MetaResponse{ + Op: op, + Image: &sourceresolver.ResolveImageResponse{ + Digest: dgst, + Config: config, + }, + }, nil + case *containerimage.OCIIdentifier: + opt.OCILayoutOpt = &sourceresolver.ResolveOCILayoutOpt{ + Store: sourceresolver.ResolveImageConfigOptStore{ + StoreID: idt.StoreID, + SessionID: idt.SessionID, + }, + } + dgst, config, err := w.OCILayoutSource.ResolveImageConfig(ctx, idt.Reference.String(), opt, sm, g) + if err != nil { + return nil, err + } + return &sourceresolver.MetaResponse{ + Op: op, + Image: &sourceresolver.ResolveImageResponse{ + Digest: dgst, + Config: config, + }, + }, nil + } + + return &sourceresolver.MetaResponse{ + Op: op, + }, nil } func (w *Worker) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error) { diff --git a/vendor/github.com/moby/buildkit/worker/containerd/containerd.go b/vendor/github.com/moby/buildkit/worker/containerd/containerd.go index e8d948d0e8c60..42987b727b21a 100644 --- a/vendor/github.com/moby/buildkit/worker/containerd/containerd.go +++ b/vendor/github.com/moby/buildkit/worker/containerd/containerd.go @@ -4,12 +4,14 @@ import ( "context" "os" "path/filepath" + goRuntime "runtime" "strconv" "strings" "github.com/containerd/containerd" "github.com/containerd/containerd/gc" "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/platforms" ptypes "github.com/containerd/containerd/protobuf/types" "github.com/moby/buildkit/cache" "github.com/moby/buildkit/cache/metadata" @@ -26,17 +28,53 @@ import ( "golang.org/x/sync/semaphore" ) +type RuntimeInfo = containerdexecutor.RuntimeInfo + // NewWorkerOpt creates a WorkerOpt. -func NewWorkerOpt(root string, address, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) { +func NewWorkerOpt( + root string, + address, snapshotterName, ns string, + rootless bool, + labels map[string]string, + dns *oci.DNSConfig, + nopt netproviders.Opt, + apparmorProfile string, + selinux bool, + parallelismSem *semaphore.Weighted, + traceSocket string, + runtime *RuntimeInfo, + opts ...containerd.ClientOpt, +) (base.WorkerOpt, error) { opts = append(opts, containerd.WithDefaultNamespace(ns)) + + if goRuntime.GOOS == "windows" { + // TODO(profnandaa): once the upstream PR[1] is merged and + // vendored in buildkit, we will remove this block. + // [1] https://github.com/containerd/containerd/pull/9412 + address = strings.TrimPrefix(address, "npipe://") + } client, err := containerd.New(address, opts...) if err != nil { return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address) } - return newContainerd(root, client, snapshotterName, ns, rootless, labels, dns, nopt, apparmorProfile, selinux, parallelismSem, traceSocket) + return newContainerd( + root, + client, + snapshotterName, + ns, + rootless, + labels, + dns, + nopt, + apparmorProfile, + selinux, + parallelismSem, + traceSocket, + runtime, + ) } -func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string) (base.WorkerOpt, error) { +func newContainerd(root string, client *containerd.Client, snapshotterName, ns string, rootless bool, labels map[string]string, dns *oci.DNSConfig, nopt netproviders.Opt, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket string, runtime *RuntimeInfo) (base.WorkerOpt, error) { if strings.Contains(snapshotterName, "/") { return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName) } @@ -103,14 +141,15 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s return base.WorkerOpt{}, errors.New("failed to find any runtime plugins") } - var platforms []ocispecs.Platform + var platformSpecs []ocispecs.Platform for _, plugin := range resp.Plugins { for _, p := range plugin.Platforms { - platforms = append(platforms, ocispecs.Platform{ + // containerd can return platforms that are not normalized + platformSpecs = append(platformSpecs, platforms.Normalize(ocispecs.Platform{ OS: p.OS, Architecture: p.Architecture, Variant: p.Variant, - }) + })) } } @@ -137,13 +176,13 @@ func newContainerd(root string, client *containerd.Client, snapshotterName, ns s Labels: xlabels, MetadataStore: md, NetworkProviders: np, - Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile, selinux, traceSocket, rootless), + Executor: containerdexecutor.New(client, root, "", np, dns, apparmorProfile, selinux, traceSocket, rootless, runtime), Snapshotter: snap, ContentStore: cs, Applier: winlayers.NewFileSystemApplierWithWindows(cs, df), Differ: winlayers.NewWalkingDiffWithWindows(cs, df), ImageStore: client.ImageService(), - Platforms: platforms, + Platforms: platformSpecs, LeaseManager: lm, GarbageCollect: gc, ParallelismSem: parallelismSem, diff --git a/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_unix.go b/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_unix.go new file mode 100644 index 0000000000000..0e08990c20174 --- /dev/null +++ b/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_unix.go @@ -0,0 +1,15 @@ +//go:build !windows +// +build !windows + +package containerd + +import ( + "os" + "testing" +) + +func checkRequirement(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("requires root") + } +} diff --git a/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_windows.go b/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_windows.go new file mode 100644 index 0000000000000..b3b412684e711 --- /dev/null +++ b/vendor/github.com/moby/buildkit/worker/containerd/containerd_test_windows.go @@ -0,0 +1,8 @@ +package containerd + +import "testing" + +//lint:ignore U1000 for parity with unix +func checkRequirement(t *testing.T) { + // no special requirements needed for Windows +} diff --git a/vendor/github.com/moby/buildkit/worker/worker.go b/vendor/github.com/moby/buildkit/worker/worker.go index 8a12585ed9a9e..dd336917a4c9d 100644 --- a/vendor/github.com/moby/buildkit/worker/worker.go +++ b/vendor/github.com/moby/buildkit/worker/worker.go @@ -6,15 +6,15 @@ import ( "github.com/moby/buildkit/cache" "github.com/moby/buildkit/client" - "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/sourceresolver" "github.com/moby/buildkit/executor" "github.com/moby/buildkit/exporter" "github.com/moby/buildkit/frontend" "github.com/moby/buildkit/session" containerdsnapshot "github.com/moby/buildkit/snapshot/containerd" "github.com/moby/buildkit/solver" + "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/leaseutil" - digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -30,7 +30,7 @@ type Worker interface { LoadRef(ctx context.Context, id string, hidden bool) (cache.ImmutableRef, error) // ResolveOp resolves Vertex.Sys() to Op implementation. ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *session.Manager) (solver.Op, error) - ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) + ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (*sourceresolver.MetaResponse, error) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error) Exporter(name string, sm *session.Manager) (exporter.Exporter, error) Prune(ctx context.Context, ch chan client.UsageInfo, opt ...client.PruneInfo) error diff --git a/vendor/github.com/tonistiigi/fsutil/.gitignore b/vendor/github.com/tonistiigi/fsutil/.gitignore index 51b9602c84a38..e5c343e2d7ba5 100644 --- a/vendor/github.com/tonistiigi/fsutil/.gitignore +++ b/vendor/github.com/tonistiigi/fsutil/.gitignore @@ -1,9 +1,5 @@ # if you want to ignore files created by your editor/tools, consider using a # global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files -.* -!.github -!.gitignore -!.travis.yml -*.prof +bin/ # support running go modules in vendor mode for local development vendor/ diff --git a/vendor/github.com/tonistiigi/fsutil/.golangci.yml b/vendor/github.com/tonistiigi/fsutil/.golangci.yml new file mode 100644 index 0000000000000..7300a0e582684 --- /dev/null +++ b/vendor/github.com/tonistiigi/fsutil/.golangci.yml @@ -0,0 +1,30 @@ +run: + timeout: 10m + skip-files: + - ".*\\.pb\\.go$" + +linters: + enable: + - gofmt + - govet + - goimports + - ineffassign + - misspell + - unused + - staticcheck + - typecheck + disable-all: true + +linters-settings: + depguard: + rules: + main: + deny: + # The io/ioutil package has been deprecated. + # https://go.dev/doc/go1.16#ioutil + - pkg: "io/ioutil" + desc: The io/ioutil package has been deprecated. + +# show all +max-issues-per-linter: 0 +max-same-issues: 0 diff --git a/vendor/github.com/tonistiigi/fsutil/Dockerfile b/vendor/github.com/tonistiigi/fsutil/Dockerfile index 9584648d05831..21c1f39f60826 100644 --- a/vendor/github.com/tonistiigi/fsutil/Dockerfile +++ b/vendor/github.com/tonistiigi/fsutil/Dockerfile @@ -1,7 +1,9 @@ -#syntax=docker/dockerfile:1 -ARG GO_VERSION=1.20 +# syntax=docker/dockerfile:1 -FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx +ARG GO_VERSION=1.21 +ARG XX_VERSION=1.4.0 + +FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base RUN apk add --no-cache git @@ -18,13 +20,19 @@ FROM base AS test ARG TESTFLAGS RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \ --mount=target=/root/.cache,type=cache \ - CGO_ENABLED=0 xx-go test -test.v ${TESTFLAGS} ./... + CGO_ENABLED=0 xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ${TESTFLAGS} ./... FROM base AS test-noroot RUN mkdir /go/pkg && chmod 0777 /go/pkg USER 1000:1000 RUN --mount=target=. \ --mount=target=/tmp/.cache,type=cache \ - CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -test.v ./... + CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -v -coverprofile=/tmp/coverage.txt -covermode=atomic ./... + +FROM scratch AS test-coverage +COPY --from=test /tmp/coverage.txt /coverage-root.txt + +FROM scratch AS test-noroot-coverage +COPY --from=test-noroot /tmp/coverage.txt /coverage-noroot.txt FROM build diff --git a/vendor/github.com/tonistiigi/fsutil/codecov.yml b/vendor/github.com/tonistiigi/fsutil/codecov.yml new file mode 100644 index 0000000000000..f5f9e02cc887b --- /dev/null +++ b/vendor/github.com/tonistiigi/fsutil/codecov.yml @@ -0,0 +1,12 @@ +comment: false + +coverage: + status: + project: # settings affecting project coverage + default: + target: auto # auto % coverage target + threshold: 1% # allow for 1% reduction of coverage without failing + patch: off + +github_checks: + annotations: false diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy.go b/vendor/github.com/tonistiigi/fsutil/copy/copy.go index 558c553f7c5aa..f8cc0a4331f7f 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy.go @@ -88,7 +88,7 @@ func Copy(ctx context.Context, srcRoot, src, dstRoot, dst string, opts ...Opt) e return err } - c, err := newCopier(dstRoot, ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler, ci.IncludePatterns, ci.ExcludePatterns, ci.ChangeFunc) + c, err := newCopier(dstRoot, ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler, ci.IncludePatterns, ci.ExcludePatterns, ci.AlwaysReplaceExistingDestPaths, ci.ChangeFunc) if err != nil { return err } @@ -172,7 +172,11 @@ type CopyInfo struct { IncludePatterns []string // Exclude files/dir matching any of these patterns (even if they match an include pattern) ExcludePatterns []string - ChangeFunc fsutil.ChangeFunc + // If true, any source path that overwrite existing destination paths will always replace + // the existing destination path, even if they are of different types (e.g. a directory will + // replace any existing symlink or file) + AlwaysReplaceExistingDestPaths bool + ChangeFunc fsutil.ChangeFunc } type Opt func(*CopyInfo) @@ -227,16 +231,17 @@ func WithChangeNotifier(fn fsutil.ChangeFunc) Opt { } type copier struct { - chown Chowner - utime *time.Time - mode *int - inodes map[uint64]string - xattrErrorHandler XAttrErrorHandler - includePatternMatcher *patternmatcher.PatternMatcher - excludePatternMatcher *patternmatcher.PatternMatcher - parentDirs []parentDir - changefn fsutil.ChangeFunc - root string + chown Chowner + utime *time.Time + mode *int + inodes map[uint64]string + xattrErrorHandler XAttrErrorHandler + includePatternMatcher *patternmatcher.PatternMatcher + excludePatternMatcher *patternmatcher.PatternMatcher + parentDirs []parentDir + changefn fsutil.ChangeFunc + root string + alwaysReplaceExistingDestPaths bool } type parentDir struct { @@ -245,7 +250,7 @@ type parentDir struct { copied bool } -func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, includePatterns, excludePatterns []string, changeFunc fsutil.ChangeFunc) (*copier, error) { +func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, includePatterns, excludePatterns []string, alwaysReplaceExistingDestPaths bool, changeFunc fsutil.ChangeFunc) (*copier, error) { if xeh == nil { xeh = func(dst, src, key string, err error) error { return err @@ -271,15 +276,16 @@ func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrEr } return &copier{ - root: root, - inodes: map[uint64]string{}, - chown: chown, - utime: tm, - xattrErrorHandler: xeh, - mode: mode, - includePatternMatcher: includePatternMatcher, - excludePatternMatcher: excludePatternMatcher, - changefn: changeFunc, + root: root, + inodes: map[uint64]string{}, + chown: chown, + utime: tm, + xattrErrorHandler: xeh, + mode: mode, + includePatternMatcher: includePatternMatcher, + excludePatternMatcher: excludePatternMatcher, + changefn: changeFunc, + alwaysReplaceExistingDestPaths: alwaysReplaceExistingDestPaths, }, nil } @@ -324,6 +330,10 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov } if include { + if err := c.removeTargetIfNeeded(src, target, fi, targetFi); err != nil { + return err + } + if err := c.createParentDirs(src, srcComponents, target, overwriteTargetMetadata); err != nil { return err } @@ -440,6 +450,21 @@ func (c *copier) exclude(path string, fi os.FileInfo, parentExcludeMatchInfo pat return m, matchInfo, nil } +func (c *copier) removeTargetIfNeeded(src, target string, srcFi, targetFi os.FileInfo) error { + if !c.alwaysReplaceExistingDestPaths { + return nil + } + if targetFi == nil { + // already doesn't exist + return nil + } + if srcFi.IsDir() && targetFi.IsDir() { + // directories are merged, not replaced + return nil + } + return os.RemoveAll(target) +} + // Delayed creation of parent directories when a file or dir matches an include // pattern. func (c *copier) createParentDirs(src, srcComponents, target string, overwriteTargetMetadata bool) error { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go index bc93b21cedaf8..0cdc00a82cd9e 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_darwin.go @@ -13,7 +13,7 @@ import ( func copyFile(source, target string) error { if err := unix.Clonefileat(unix.AT_FDCWD, source, unix.AT_FDCWD, target, unix.CLONE_NOFOLLOW); err != nil { - if err != unix.EINVAL { + if err != unix.EINVAL && err != unix.EXDEV { return err } } else { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go index 971cb5c5d49c6..6d9b490c66c06 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go @@ -30,7 +30,16 @@ func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { m := fi.Mode() if c.mode != nil { - m = (m & ^os.FileMode(0777)) | os.FileMode(*c.mode&0777) + m = os.FileMode(*c.mode).Perm() + if *c.mode&syscall.S_ISGID != 0 { + m |= os.ModeSetgid + } + if *c.mode&syscall.S_ISUID != 0 { + m |= os.ModeSetuid + } + if *c.mode&syscall.S_ISVTX != 0 { + m |= os.ModeSticky + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { if err := os.Chmod(name, m); err != nil { diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go index 945e96c5f23d7..4a7d0c86b1bb4 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go @@ -31,7 +31,16 @@ func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { m := fi.Mode() if c.mode != nil { - m = (m & ^os.FileMode(0777)) | os.FileMode(*c.mode&0777) + m = os.FileMode(*c.mode).Perm() + if *c.mode&syscall.S_ISGID != 0 { + m |= os.ModeSetgid + } + if *c.mode&syscall.S_ISUID != 0 { + m |= os.ModeSetuid + } + if *c.mode&syscall.S_ISVTX != 0 { + m |= os.ModeSticky + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { if err := os.Chmod(name, m); err != nil { diff --git a/vendor/github.com/tonistiigi/fsutil/diff_containerd.go b/vendor/github.com/tonistiigi/fsutil/diff_containerd.go index d8619abf1c084..84fdc89dc5bf8 100644 --- a/vendor/github.com/tonistiigi/fsutil/diff_containerd.go +++ b/vendor/github.com/tonistiigi/fsutil/diff_containerd.go @@ -5,6 +5,7 @@ import ( "context" "io" "os" + "path/filepath" "strings" "github.com/tonistiigi/fsutil/types" @@ -110,7 +111,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil if filter != nil { filter(f2.path, &statCopy) } - f2copy = ¤tPath{path: f2.path, stat: &statCopy} + f2copy = ¤tPath{path: filepath.FromSlash(f2.path), stat: &statCopy} } k, p := pathChange(f1, f2copy) switch k { @@ -127,7 +128,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil f1 = nil continue } else if rmdir == "" && f1.stat.IsDir() { - rmdir = f1.path + string(os.PathSeparator) + rmdir = f1.path + string(filepath.Separator) } else if rmdir != "" { rmdir = "" } @@ -138,7 +139,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil return err } if f1.stat.IsDir() && !f2copy.stat.IsDir() { - rmdir = f1.path + string(os.PathSeparator) + rmdir = f1.path + string(filepath.Separator) } else if rmdir != "" { rmdir = "" } diff --git a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl index 6ba3c867247cf..48127d4ff0fce 100644 --- a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl +++ b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl @@ -1,5 +1,9 @@ variable "GO_VERSION" { - default = "1.20" + default = null +} + +variable "DESTDIR" { + default = "./bin" } group "default" { @@ -18,12 +22,14 @@ group "test" { target "test-root" { inherits = ["build"] - target = "test" + target = "test-coverage" + output = ["${DESTDIR}/coverage"] } target "test-noroot" { inherits = ["build"] - target = "test-noroot" + target = "test-noroot-coverage" + output = ["${DESTDIR}/coverage"] } target "lint" { diff --git a/vendor/github.com/tonistiigi/fsutil/walker.go b/vendor/github.com/tonistiigi/fsutil/filter.go similarity index 51% rename from vendor/github.com/tonistiigi/fsutil/walker.go rename to vendor/github.com/tonistiigi/fsutil/filter.go index 545f5e905f21f..9cee8ad238ace 100644 --- a/vendor/github.com/tonistiigi/fsutil/walker.go +++ b/vendor/github.com/tonistiigi/fsutil/filter.go @@ -2,25 +2,35 @@ package fsutil import ( "context" + "io" gofs "io/fs" "os" "path/filepath" "strings" "syscall" - "time" "github.com/moby/patternmatcher" "github.com/pkg/errors" "github.com/tonistiigi/fsutil/types" ) -type WalkOpt struct { +type FilterOpt struct { + // IncludePatterns requires that the path matches at least one of the + // specified patterns. IncludePatterns []string + + // ExcludePatterns requires that the path does not match any of the + // specified patterns. ExcludePatterns []string - // FollowPaths contains symlinks that are resolved into include patterns - // before performing the fs walk + + // FollowPaths contains symlinks that are resolved into IncludePatterns + // at the time of the call to NewFilterFS. FollowPaths []string - Map MapFunc + + // Map is called for each path that is included in the result. + // The function can modify the stat info for each element, while the result + // of the function controls both how Walk continues. + Map MapFunc } type MapFunc func(string, *types.Stat) MapResult @@ -43,33 +53,41 @@ const ( MapResultSkipDir ) -func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) error { - root, err := filepath.EvalSymlinks(p) - if err != nil { - return errors.WithStack(&os.PathError{Op: "resolve", Path: root, Err: err}) - } - rootFI, err := os.Stat(root) - if err != nil { - return errors.WithStack(err) - } - if !rootFI.IsDir() { - return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR}) - } +type filterFS struct { + fs FS - var ( - includePatterns []string - includeMatcher *patternmatcher.PatternMatcher - excludeMatcher *patternmatcher.PatternMatcher - ) + includeMatcher *patternmatcher.PatternMatcher + excludeMatcher *patternmatcher.PatternMatcher + onlyPrefixIncludes bool + onlyPrefixExcludeExceptions bool - if opt != nil && opt.IncludePatterns != nil { + mapFn MapFunc +} + +// NewFilterFS creates a new FS that filters the given FS using the given +// FilterOpt. +// +// The returned FS will not contain any paths that do not match the provided +// include and exclude patterns, or that are are excluded using the mapping +// function. +// +// The FS is assumed to be a snapshot of the filesystem at the time of the +// call to NewFilterFS. If the underlying filesystem changes, calls to the +// underlying FS may be inconsistent. +func NewFilterFS(fs FS, opt *FilterOpt) (FS, error) { + if opt == nil { + return fs, nil + } + + var includePatterns []string + if opt.IncludePatterns != nil { includePatterns = make([]string, len(opt.IncludePatterns)) copy(includePatterns, opt.IncludePatterns) } - if opt != nil && opt.FollowPaths != nil { - targets, err := FollowLinks(p, opt.FollowPaths) + if opt.FollowPaths != nil { + targets, err := FollowLinks(fs, opt.FollowPaths) if err != nil { - return err + return nil, err } if targets != nil { includePatterns = append(includePatterns, targets...) @@ -78,15 +96,22 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } patternChars := "*[]?^" - if os.PathSeparator != '\\' { + if filepath.Separator != '\\' { patternChars += `\` } - onlyPrefixIncludes := true - if len(includePatterns) != 0 { + var ( + includeMatcher *patternmatcher.PatternMatcher + excludeMatcher *patternmatcher.PatternMatcher + err error + onlyPrefixIncludes = true + onlyPrefixExcludeExceptions = true + ) + + if len(includePatterns) > 0 { includeMatcher, err = patternmatcher.New(includePatterns) if err != nil { - return errors.Wrapf(err, "invalid includepatterns: %s", opt.IncludePatterns) + return nil, errors.Wrapf(err, "invalid includepatterns: %s", opt.IncludePatterns) } for _, p := range includeMatcher.Patterns() { @@ -98,11 +123,10 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } - onlyPrefixExcludeExceptions := true - if opt != nil && opt.ExcludePatterns != nil { + if len(opt.ExcludePatterns) > 0 { excludeMatcher, err = patternmatcher.New(opt.ExcludePatterns) if err != nil { - return errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns) + return nil, errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns) } for _, p := range excludeMatcher.Patterns() { @@ -113,47 +137,67 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } } + return &filterFS{ + fs: fs, + includeMatcher: includeMatcher, + excludeMatcher: excludeMatcher, + onlyPrefixIncludes: onlyPrefixIncludes, + onlyPrefixExcludeExceptions: onlyPrefixExcludeExceptions, + mapFn: opt.Map, + }, nil +} + +func (fs *filterFS) Open(p string) (io.ReadCloser, error) { + if fs.includeMatcher != nil { + m, err := fs.includeMatcher.MatchesOrParentMatches(p) + if err != nil { + return nil, err + } + if !m { + return nil, errors.Wrapf(os.ErrNotExist, "open %s", p) + } + } + if fs.excludeMatcher != nil { + m, err := fs.excludeMatcher.MatchesOrParentMatches(p) + if err != nil { + return nil, err + } + if m { + return nil, errors.Wrapf(os.ErrNotExist, "open %s", p) + } + } + return fs.fs.Open(p) +} + +func (fs *filterFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc) error { type visitedDir struct { - fi os.FileInfo - path string - origpath string + entry gofs.DirEntry pathWithSep string includeMatchInfo patternmatcher.MatchInfo excludeMatchInfo patternmatcher.MatchInfo calledFn bool + skipFn bool } // used only for include/exclude handling var parentDirs []visitedDir - seenFiles := make(map[uint64]string) - return filepath.WalkDir(root, func(path string, dirEntry gofs.DirEntry, walkErr error) (retErr error) { + return fs.fs.Walk(ctx, target, func(path string, dirEntry gofs.DirEntry, walkErr error) (retErr error) { defer func() { if retErr != nil && isNotExist(retErr) { retErr = filepath.SkipDir } }() - origpath := path - path, err = filepath.Rel(root, path) - if err != nil { - return err - } - // Skip root - if path == "." { - return nil - } - var ( dir visitedDir isDir bool - fi gofs.FileInfo ) if dirEntry != nil { isDir = dirEntry.IsDir() } - if includeMatcher != nil || excludeMatcher != nil { + if fs.includeMatcher != nil || fs.excludeMatcher != nil { for len(parentDirs) != 0 { lastParentDir := parentDirs[len(parentDirs)-1].pathWithSep if strings.HasPrefix(path, lastParentDir) { @@ -163,15 +207,8 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } if isDir { - fi, err = dirEntry.Info() - if err != nil { - return err - } - dir = visitedDir{ - fi: fi, - path: path, - origpath: origpath, + entry: dirEntry, pathWithSep: path + string(filepath.Separator), } } @@ -179,12 +216,12 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err skip := false - if includeMatcher != nil { + if fs.includeMatcher != nil { var parentIncludeMatchInfo patternmatcher.MatchInfo if len(parentDirs) != 0 { parentIncludeMatchInfo = parentDirs[len(parentDirs)-1].includeMatchInfo } - m, matchInfo, err := includeMatcher.MatchesUsingParentResults(path, parentIncludeMatchInfo) + m, matchInfo, err := fs.includeMatcher.MatchesUsingParentResults(path, parentIncludeMatchInfo) if err != nil { return errors.Wrap(err, "failed to match includepatterns") } @@ -194,11 +231,11 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } if !m { - if isDir && onlyPrefixIncludes { + if isDir && fs.onlyPrefixIncludes { // Optimization: we can skip walking this dir if no include // patterns could match anything inside it. dirSlash := path + string(filepath.Separator) - for _, pat := range includeMatcher.Patterns() { + for _, pat := range fs.includeMatcher.Patterns() { if pat.Exclusion() { continue } @@ -214,12 +251,12 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } } - if excludeMatcher != nil { + if fs.excludeMatcher != nil { var parentExcludeMatchInfo patternmatcher.MatchInfo if len(parentDirs) != 0 { parentExcludeMatchInfo = parentDirs[len(parentDirs)-1].excludeMatchInfo } - m, matchInfo, err := excludeMatcher.MatchesUsingParentResults(path, parentExcludeMatchInfo) + m, matchInfo, err := fs.excludeMatcher.MatchesUsingParentResults(path, parentExcludeMatchInfo) if err != nil { return errors.Wrap(err, "failed to match excludepatterns") } @@ -229,16 +266,16 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } if m { - if isDir && onlyPrefixExcludeExceptions { + if isDir && fs.onlyPrefixExcludeExceptions { // Optimization: we can skip walking this dir if no // exceptions to exclude patterns could match anything // inside it. - if !excludeMatcher.Exclusions() { + if !fs.excludeMatcher.Exclusions() { return filepath.SkipDir } dirSlash := path + string(filepath.Separator) - for _, pat := range excludeMatcher.Patterns() { + for _, pat := range fs.excludeMatcher.Patterns() { if !pat.Exclusion() { continue } @@ -261,7 +298,7 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err return walkErr } - if includeMatcher != nil || excludeMatcher != nil { + if fs.includeMatcher != nil || fs.excludeMatcher != nil { defer func() { if isDir { parentDirs = append(parentDirs, dir) @@ -275,25 +312,21 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err dir.calledFn = true - // The FileInfo might have already been read further up. - if fi == nil { - fi, err = dirEntry.Info() - if err != nil { - return err - } - } - - stat, err := mkstat(origpath, path, fi, seenFiles) + fi, err := dirEntry.Info() if err != nil { return err } + stat, ok := fi.Sys().(*types.Stat) + if !ok { + return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) + } select { case <-ctx.Done(): return ctx.Err() default: - if opt != nil && opt.Map != nil { - result := opt.Map(stat.Path, stat) + if fs.mapFn != nil { + result := fs.mapFn(stat.Path, stat) if result == MapResultSkipDir { return filepath.SkipDir } else if result == MapResultExclude { @@ -301,32 +334,45 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } } for i, parentDir := range parentDirs { + if parentDir.skipFn { + return filepath.SkipDir + } if parentDir.calledFn { continue } - parentStat, err := mkstat(parentDir.origpath, parentDir.path, parentDir.fi, seenFiles) + parentFi, err := parentDir.entry.Info() if err != nil { return err } + parentStat, ok := parentFi.Sys().(*types.Stat) + if !ok { + return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) + } select { case <-ctx.Done(): return ctx.Err() default: } - if opt != nil && opt.Map != nil { - result := opt.Map(parentStat.Path, parentStat) - if result == MapResultSkipDir || result == MapResultExclude { + if fs.mapFn != nil { + result := fs.mapFn(parentStat.Path, parentStat) + if result == MapResultExclude { continue + } else if result == MapResultSkipDir { + parentDirs[i].skipFn = true + return filepath.SkipDir } } - if err := fn(parentStat.Path, &StatInfo{parentStat}, nil); err != nil { + parentDirs[i].calledFn = true + if err := fn(parentStat.Path, &DirEntryInfo{Stat: parentStat}, nil); err == filepath.SkipDir { + parentDirs[i].skipFn = true + return filepath.SkipDir + } else if err != nil { return err } - parentDirs[i].calledFn = true } - if err := fn(stat.Path, &StatInfo{stat}, nil); err != nil { + if err := fn(stat.Path, &DirEntryInfo{Stat: stat}, nil); err != nil { return err } } @@ -334,6 +380,40 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err }) } +func Walk(ctx context.Context, p string, opt *FilterOpt, fn filepath.WalkFunc) error { + f, err := NewFS(p) + if err != nil { + return err + } + f, err = NewFilterFS(f, opt) + if err != nil { + return err + } + return f.Walk(ctx, "/", func(path string, d gofs.DirEntry, err error) error { + var info gofs.FileInfo + if d != nil { + var err2 error + info, err2 = d.Info() + if err == nil { + err = err2 + } + } + return fn(path, info, err) + }) +} + +func WalkDir(ctx context.Context, p string, opt *FilterOpt, fn gofs.WalkDirFunc) error { + f, err := NewFS(p) + if err != nil { + return err + } + f, err = NewFilterFS(f, opt) + if err != nil { + return err + } + return f.Walk(ctx, "/", fn) +} + func patternWithoutTrailingGlob(p *patternmatcher.Pattern) string { patStr := p.String() // We use filepath.Separator here because patternmatcher.Pattern patterns @@ -344,29 +424,6 @@ func patternWithoutTrailingGlob(p *patternmatcher.Pattern) string { return patStr } -type StatInfo struct { - *types.Stat -} - -func (s *StatInfo) Name() string { - return filepath.Base(s.Stat.Path) -} -func (s *StatInfo) Size() int64 { - return s.Stat.Size_ -} -func (s *StatInfo) Mode() os.FileMode { - return os.FileMode(s.Stat.Mode) -} -func (s *StatInfo) ModTime() time.Time { - return time.Unix(s.Stat.ModTime/1e9, s.Stat.ModTime%1e9) -} -func (s *StatInfo) IsDir() bool { - return s.Mode().IsDir() -} -func (s *StatInfo) Sys() interface{} { - return s.Stat -} - func isNotExist(err error) bool { return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) } diff --git a/vendor/github.com/tonistiigi/fsutil/followlinks.go b/vendor/github.com/tonistiigi/fsutil/followlinks.go index f03a9cf3500b0..559291d79d9ad 100644 --- a/vendor/github.com/tonistiigi/fsutil/followlinks.go +++ b/vendor/github.com/tonistiigi/fsutil/followlinks.go @@ -1,17 +1,21 @@ package fsutil import ( + "context" + gofs "io/fs" "os" "path/filepath" "runtime" "sort" strings "strings" + "syscall" "github.com/pkg/errors" + "github.com/tonistiigi/fsutil/types" ) -func FollowLinks(root string, paths []string) ([]string, error) { - r := &symlinkResolver{root: root, resolved: map[string]struct{}{}} +func FollowLinks(fs FS, paths []string) ([]string, error) { + r := &symlinkResolver{fs: fs, resolved: map[string]struct{}{}} for _, p := range paths { if err := r.append(p); err != nil { return nil, err @@ -26,7 +30,7 @@ func FollowLinks(root string, paths []string) ([]string, error) { } type symlinkResolver struct { - root string + fs FS resolved map[string]struct{} } @@ -76,10 +80,9 @@ func (r *symlinkResolver) append(p string) error { } func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, error) { - realPath := filepath.Join(r.root, p) base := filepath.Base(p) if allowWildcard && containsWildcards(base) { - fis, err := os.ReadDir(filepath.Dir(realPath)) + fis, err := readDir(r.fs, filepath.Dir(p)) if err != nil { if isNotFound(err) { return nil, nil @@ -99,21 +102,30 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e return out, nil } - fi, err := os.Lstat(realPath) + entry, err := statFile(r.fs, p) if err != nil { if isNotFound(err) { return nil, nil } return nil, errors.WithStack(err) } - if fi.Mode()&os.ModeSymlink == 0 { + if entry == nil { return nil, nil } - link, err := os.Readlink(realPath) + if entry.Type()&os.ModeSymlink == 0 { + return nil, nil + } + + fi, err := entry.Info() if err != nil { return nil, errors.WithStack(err) } - link = filepath.Clean(link) + stat, ok := fi.Sys().(*types.Stat) + if !ok { + return nil, errors.WithStack(&os.PathError{Path: p, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) + } + + link := filepath.Clean(stat.Linkname) if filepath.IsAbs(link) { return []string{link}, nil } @@ -122,6 +134,76 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e }, nil } +func statFile(fs FS, root string) (os.DirEntry, error) { + var out os.DirEntry + + root = filepath.FromSlash(filepath.Clean(root)) + if root == string(filepath.Separator) || root == "." { + return nil, nil + } + + err := fs.Walk(context.TODO(), root, func(p string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if p != root { + return errors.Errorf("expected single entry %q but got %q", root, p) + } + out = entry + if entry.IsDir() { + return filepath.SkipDir + } + return nil + }) + if err != nil { + return nil, err + } + + if out == nil { + return nil, errors.Wrapf(os.ErrNotExist, "readFile %s", root) + } + return out, nil +} + +func readDir(fs FS, root string) ([]os.DirEntry, error) { + var out []os.DirEntry + + root = filepath.FromSlash(filepath.Clean(root)) + if root == string(filepath.Separator) || root == "." { + root = "." + out = make([]gofs.DirEntry, 0) + } + + err := fs.Walk(context.TODO(), root, func(p string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if p == root { + if !entry.IsDir() { + return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR}) + } + out = make([]gofs.DirEntry, 0) + return nil + } + if out == nil { + return errors.Errorf("expected to read parent entry %q before child %q", root, p) + } + out = append(out, entry) + if entry.IsDir() { + return filepath.SkipDir + } + return nil + }) + if err != nil { + return nil, err + } + + if out == nil && root != "." { + return nil, errors.Wrapf(os.ErrNotExist, "readDir %s", root) + } + return out, nil +} + func containsWildcards(name string) bool { isWindows := runtime.GOOS == "windows" for i := 0; i < len(name); i++ { diff --git a/vendor/github.com/tonistiigi/fsutil/fs.go b/vendor/github.com/tonistiigi/fsutil/fs.go index db587b77cd80d..fe370194bed3a 100644 --- a/vendor/github.com/tonistiigi/fsutil/fs.go +++ b/vendor/github.com/tonistiigi/fsutil/fs.go @@ -3,36 +3,86 @@ package fsutil import ( "context" "io" + gofs "io/fs" "os" "path" "path/filepath" "sort" "strings" "syscall" + "time" "github.com/pkg/errors" "github.com/tonistiigi/fsutil/types" ) type FS interface { - Walk(context.Context, filepath.WalkFunc) error + Walk(context.Context, string, gofs.WalkDirFunc) error Open(string) (io.ReadCloser, error) } -func NewFS(root string, opt *WalkOpt) FS { +// NewFS creates a new FS from a root directory on the host filesystem. +func NewFS(root string) (FS, error) { + root, err := filepath.EvalSymlinks(root) + if err != nil { + return nil, errors.WithStack(&os.PathError{Op: "resolve", Path: root, Err: err}) + } + fi, err := os.Stat(root) + if err != nil { + return nil, err + } + if !fi.IsDir() { + return nil, errors.WithStack(&os.PathError{Op: "stat", Path: root, Err: syscall.ENOTDIR}) + } + return &fs{ root: root, - opt: opt, - } + }, nil } type fs struct { root string - opt *WalkOpt } -func (fs *fs) Walk(ctx context.Context, fn filepath.WalkFunc) error { - return Walk(ctx, fs.root, fs.opt, fn) +func (fs *fs) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc) error { + seenFiles := make(map[uint64]string) + return filepath.WalkDir(filepath.Join(fs.root, target), func(path string, dirEntry gofs.DirEntry, walkErr error) (retErr error) { + defer func() { + if retErr != nil && isNotExist(retErr) { + retErr = filepath.SkipDir + } + }() + + origpath := path + path, err := filepath.Rel(fs.root, path) + if err != nil { + return err + } + // Skip root + if path == "." { + return nil + } + + var entry gofs.DirEntry + if dirEntry != nil { + entry = &DirEntryInfo{ + path: path, + origpath: origpath, + entry: dirEntry, + seenFiles: seenFiles, + } + } + + select { + case <-ctx.Done(): + return ctx.Err() + default: + if err := fn(path, entry, walkErr); err != nil { + return err + } + } + return nil + }) } func (fs *fs) Open(p string) (io.ReadCloser, error) { @@ -67,16 +117,31 @@ type subDirFS struct { dirs []Dir } -func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error { +func (fs *subDirFS) Walk(ctx context.Context, target string, fn gofs.WalkDirFunc) error { + first, rest, _ := strings.Cut(target, string(filepath.Separator)) + for _, d := range fs.dirs { - fi := &StatInfo{Stat: &d.Stat} + if first != "" && first != d.Stat.Path { + continue + } + + fi := &StatInfo{&d.Stat} if !fi.IsDir() { return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.ENOTDIR, Op: "walk subdir"}) } - if err := fn(d.Stat.Path, fi, nil); err != nil { + dStat := d.Stat + if err := fn(d.Stat.Path, &DirEntryInfo{Stat: &dStat}, nil); err != nil { return err } - if err := d.FS.Walk(ctx, func(p string, fi os.FileInfo, err error) error { + if err := d.FS.Walk(ctx, rest, func(p string, entry gofs.DirEntry, err error) error { + if err != nil { + return err + } + + fi, err := entry.Info() + if err != nil { + return err + } stat, ok := fi.Sys().(*types.Stat) if !ok { return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) @@ -91,7 +156,7 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error { stat.Linkname = path.Join(d.Stat.Path, stat.Linkname) } } - return fn(filepath.Join(d.Stat.Path, p), &StatInfo{stat}, nil) + return fn(filepath.Join(d.Stat.Path, p), &DirEntryInfo{Stat: stat}, nil) }); err != nil { return err } @@ -117,3 +182,70 @@ type emptyReader struct { func (*emptyReader) Read([]byte) (int, error) { return 0, io.EOF } + +type StatInfo struct { + *types.Stat +} + +func (s *StatInfo) Name() string { + return filepath.Base(s.Stat.Path) +} +func (s *StatInfo) Size() int64 { + return s.Stat.Size_ +} +func (s *StatInfo) Mode() os.FileMode { + return os.FileMode(s.Stat.Mode) +} +func (s *StatInfo) ModTime() time.Time { + return time.Unix(s.Stat.ModTime/1e9, s.Stat.ModTime%1e9) +} +func (s *StatInfo) IsDir() bool { + return s.Mode().IsDir() +} +func (s *StatInfo) Sys() interface{} { + return s.Stat +} + +type DirEntryInfo struct { + *types.Stat + + entry gofs.DirEntry + path string + origpath string + seenFiles map[uint64]string +} + +func (s *DirEntryInfo) Name() string { + if s.Stat != nil { + return filepath.Base(s.Stat.Path) + } + return s.entry.Name() +} +func (s *DirEntryInfo) IsDir() bool { + if s.Stat != nil { + return s.Stat.IsDir() + } + return s.entry.IsDir() +} +func (s *DirEntryInfo) Type() gofs.FileMode { + if s.Stat != nil { + return gofs.FileMode(s.Stat.Mode) + } + return s.entry.Type() +} +func (s *DirEntryInfo) Info() (gofs.FileInfo, error) { + if s.Stat == nil { + fi, err := s.entry.Info() + if err != nil { + return nil, err + } + stat, err := mkstat(s.origpath, s.path, fi, s.seenFiles) + if err != nil { + return nil, err + } + s.Stat = stat + } + + st := *s.Stat + return &StatInfo{&st}, nil +} diff --git a/vendor/github.com/tonistiigi/fsutil/readme.md b/vendor/github.com/tonistiigi/fsutil/readme.md index 5ce685b7edc7e..c417168876faa 100644 --- a/vendor/github.com/tonistiigi/fsutil/readme.md +++ b/vendor/github.com/tonistiigi/fsutil/readme.md @@ -1,3 +1,8 @@ +[![PkgGoDev](https://img.shields.io/badge/go.dev-docs-007d9c?style=flat-square&logo=go&logoColor=white)](https://pkg.go.dev/github.com/tonistiigi/fsutil) +[![CI Status](https://img.shields.io/github/actions/workflow/status/tonistiigi/fsutil/ci.yml?label=ci&logo=github&style=flat-square)](https://github.com/tonistiigi/fsutil/actions?query=workflow%3Aci) +[![Go Report Card](https://goreportcard.com/badge/github.com/tonistiigi/fsutil?style=flat-square)](https://goreportcard.com/report/github.com/tonistiigi/fsutil) +[![Codecov](https://img.shields.io/codecov/c/github/tonistiigi/fsutil?logo=codecov&style=flat-square)](https://codecov.io/gh/tonistiigi/fsutil) + Incremental file directory sync tools in golang. ``` diff --git a/vendor/github.com/tonistiigi/fsutil/send.go b/vendor/github.com/tonistiigi/fsutil/send.go index f1c51b83652d5..6a935ed06c036 100644 --- a/vendor/github.com/tonistiigi/fsutil/send.go +++ b/vendor/github.com/tonistiigi/fsutil/send.go @@ -4,6 +4,7 @@ import ( "context" "io" "os" + "path/filepath" "sync" "syscall" @@ -144,7 +145,11 @@ func (s *sender) sendFile(h *sendHandle) error { func (s *sender) walk(ctx context.Context) error { var i uint32 = 0 - err := s.fs.Walk(ctx, func(path string, fi os.FileInfo, err error) error { + err := s.fs.Walk(ctx, "/", func(path string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + fi, err := entry.Info() if err != nil { return err } @@ -152,7 +157,7 @@ func (s *sender) walk(ctx context.Context) error { if !ok { return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) } - + stat.Path = filepath.ToSlash(stat.Path) p := &types.Packet{ Type: types.PACKET_STAT, Stat: stat, diff --git a/vendor/github.com/tonistiigi/fsutil/stat.go b/vendor/github.com/tonistiigi/fsutil/stat.go index 2ab8da118e2cf..44441cb65696e 100644 --- a/vendor/github.com/tonistiigi/fsutil/stat.go +++ b/vendor/github.com/tonistiigi/fsutil/stat.go @@ -19,7 +19,7 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (* relpath = filepath.ToSlash(relpath) stat := &types.Stat{ - Path: relpath, + Path: filepath.FromSlash(relpath), Mode: uint32(fi.Mode()), ModTime: fi.ModTime().UnixNano(), } diff --git a/vendor/github.com/tonistiigi/fsutil/tarwriter.go b/vendor/github.com/tonistiigi/fsutil/tarwriter.go index bd46a2250ff84..06b7bda9bec01 100644 --- a/vendor/github.com/tonistiigi/fsutil/tarwriter.go +++ b/vendor/github.com/tonistiigi/fsutil/tarwriter.go @@ -15,10 +15,15 @@ import ( func WriteTar(ctx context.Context, fs FS, w io.Writer) error { tw := tar.NewWriter(w) - err := fs.Walk(ctx, func(path string, fi os.FileInfo, err error) error { + err := fs.Walk(ctx, "/", func(path string, entry os.DirEntry, err error) error { if err != nil && !errors.Is(err, os.ErrNotExist) { return err } + + fi, err := entry.Info() + if err != nil { + return err + } stat, ok := fi.Sys().(*types.Stat) if !ok { return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"}) diff --git a/vendor/github.com/tonistiigi/fsutil/validator.go b/vendor/github.com/tonistiigi/fsutil/validator.go index 9bd7d94d36438..8b0dd91ec4df3 100644 --- a/vendor/github.com/tonistiigi/fsutil/validator.go +++ b/vendor/github.com/tonistiigi/fsutil/validator.go @@ -2,8 +2,7 @@ package fsutil import ( "os" - "path" - "runtime" + "path/filepath" "sort" "strings" "syscall" @@ -28,21 +27,18 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err if v.parentDirs == nil { v.parentDirs = make([]parent, 1, 10) } - if runtime.GOOS == "windows" { - p = strings.Replace(p, "\\", "", -1) - } - if p != path.Clean(p) { + if p != filepath.Clean(p) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"}) } - if path.IsAbs(p) { + if filepath.IsAbs(p) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"}) } - dir := path.Dir(p) - base := path.Base(p) + dir := filepath.Dir(p) + base := filepath.Base(p) if dir == "." { dir = "" } - if dir == ".." || strings.HasPrefix(p, "../") { + if dir == ".." || strings.HasPrefix(p, filepath.FromSlash("../")) { return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"}) } @@ -56,12 +52,12 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err } if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base { - return errors.Errorf("changes out of order: %q %q", p, path.Join(v.parentDirs[i].dir, v.parentDirs[i].last)) + return errors.Errorf("changes out of order: %q %q", p, filepath.Join(v.parentDirs[i].dir, v.parentDirs[i].last)) } v.parentDirs[i].last = base if kind != ChangeKindDelete && fi.IsDir() { v.parentDirs = append(v.parentDirs, parent{ - dir: path.Join(dir, base), + dir: filepath.Join(dir, base), last: "", }) } @@ -76,7 +72,7 @@ func ComparePath(p1, p2 string) int { switch { case p1[i] == p2[i]: continue - case p2[i] != '/' && p1[i] < p2[i] || p1[i] == '/': + case p2[i] != filepath.Separator && p1[i] < p2[i] || p1[i] == filepath.Separator: return -1 default: return 1 diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/LICENSE b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/doc.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/doc.go new file mode 100644 index 0000000000000..31831c415fecd --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/doc.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package otlpmetric provides an OpenTelemetry metric Exporter that can be +// used with PeriodicReader. It transforms metricdata into OTLP and transmits +// the transformed data to OTLP receivers. The Exporter is configurable to use +// different Clients, each using a distinct transport protocol to communicate +// to an OTLP receiving endpoint. +package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/LICENSE b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/client.go new file mode 100644 index 0000000000000..ff0647deec378 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/client.go @@ -0,0 +1,199 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + +import ( + "context" + "time" + + "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry" + colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1" + metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +type client struct { + metadata metadata.MD + exportTimeout time.Duration + requestFunc retry.RequestFunc + + // ourConn keeps track of where conn was created: true if created here in + // NewClient, or false if passed with an option. This is important on + // Shutdown as the conn should only be closed if we created it. Otherwise, + // it is up to the processes that passed the conn to close it. + ourConn bool + conn *grpc.ClientConn + msc colmetricpb.MetricsServiceClient +} + +// newClient creates a new gRPC metric client. +func newClient(ctx context.Context, cfg oconf.Config) (*client, error) { + c := &client{ + exportTimeout: cfg.Metrics.Timeout, + requestFunc: cfg.RetryConfig.RequestFunc(retryable), + conn: cfg.GRPCConn, + } + + if len(cfg.Metrics.Headers) > 0 { + c.metadata = metadata.New(cfg.Metrics.Headers) + } + + if c.conn == nil { + // If the caller did not provide a ClientConn when the client was + // created, create one using the configuration they did provide. + conn, err := grpc.DialContext(ctx, cfg.Metrics.Endpoint, cfg.DialOptions...) + if err != nil { + return nil, err + } + // Keep track that we own the lifecycle of this conn and need to close + // it on Shutdown. + c.ourConn = true + c.conn = conn + } + + c.msc = colmetricpb.NewMetricsServiceClient(c.conn) + + return c, nil +} + +// Shutdown shuts down the client, freeing all resource. +// +// Any active connections to a remote endpoint are closed if they were created +// by the client. Any gRPC connection passed during creation using +// WithGRPCConn will not be closed. It is the caller's responsibility to +// handle cleanup of that resource. +func (c *client) Shutdown(ctx context.Context) error { + // The otlpmetric.Exporter synchronizes access to client methods and + // ensures this is called only once. The only thing that needs to be done + // here is to release any computational resources the client holds. + + c.metadata = nil + c.requestFunc = nil + c.msc = nil + + err := ctx.Err() + if c.ourConn { + closeErr := c.conn.Close() + // A context timeout error takes precedence over this error. + if err == nil && closeErr != nil { + err = closeErr + } + } + c.conn = nil + return err +} + +// UploadMetrics sends protoMetrics to connected endpoint. +// +// Retryable errors from the server will be handled according to any +// RetryConfig the client was created with. +func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.ResourceMetrics) error { + // The otlpmetric.Exporter synchronizes access to client methods, and + // ensures this is not called after the Exporter is shutdown. Only thing + // to do here is send data. + + select { + case <-ctx.Done(): + // Do not upload if the context is already expired. + return ctx.Err() + default: + } + + ctx, cancel := c.exportContext(ctx) + defer cancel() + + return c.requestFunc(ctx, func(iCtx context.Context) error { + resp, err := c.msc.Export(iCtx, &colmetricpb.ExportMetricsServiceRequest{ + ResourceMetrics: []*metricpb.ResourceMetrics{protoMetrics}, + }) + if resp != nil && resp.PartialSuccess != nil { + msg := resp.PartialSuccess.GetErrorMessage() + n := resp.PartialSuccess.GetRejectedDataPoints() + if n != 0 || msg != "" { + err := internal.MetricPartialSuccessError(n, msg) + otel.Handle(err) + } + } + // nil is converted to OK. + if status.Code(err) == codes.OK { + // Success. + return nil + } + return err + }) +} + +// exportContext returns a copy of parent with an appropriate deadline and +// cancellation function based on the clients configured export timeout. +// +// It is the callers responsibility to cancel the returned context once its +// use is complete, via the parent or directly with the returned CancelFunc, to +// ensure all resources are correctly released. +func (c *client) exportContext(parent context.Context) (context.Context, context.CancelFunc) { + var ( + ctx context.Context + cancel context.CancelFunc + ) + + if c.exportTimeout > 0 { + ctx, cancel = context.WithTimeout(parent, c.exportTimeout) + } else { + ctx, cancel = context.WithCancel(parent) + } + + if c.metadata.Len() > 0 { + ctx = metadata.NewOutgoingContext(ctx, c.metadata) + } + + return ctx, cancel +} + +// retryable returns if err identifies a request that can be retried and a +// duration to wait for if an explicit throttle time is included in err. +func retryable(err error) (bool, time.Duration) { + s := status.Convert(err) + switch s.Code() { + case codes.Canceled, + codes.DeadlineExceeded, + codes.ResourceExhausted, + codes.Aborted, + codes.OutOfRange, + codes.Unavailable, + codes.DataLoss: + return true, throttleDelay(s) + } + + // Not a retry-able error. + return false, 0 +} + +// throttleDelay returns a duration to wait for if an explicit throttle time +// is included in the response status. +func throttleDelay(s *status.Status) time.Duration { + for _, detail := range s.Details() { + if t, ok := detail.(*errdetails.RetryInfo); ok { + return t.RetryDelay.AsDuration() + } + } + return 0 +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/config.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/config.go new file mode 100644 index 0000000000000..6ba3600b1c1e6 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/config.go @@ -0,0 +1,256 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + +import ( + "fmt" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry" + "go.opentelemetry.io/otel/sdk/metric" +) + +// Option applies a configuration option to the Exporter. +type Option interface { + applyGRPCOption(oconf.Config) oconf.Config +} + +func asGRPCOptions(opts []Option) []oconf.GRPCOption { + converted := make([]oconf.GRPCOption, len(opts)) + for i, o := range opts { + converted[i] = oconf.NewGRPCOption(o.applyGRPCOption) + } + return converted +} + +// RetryConfig defines configuration for retrying the export of metric data +// that failed. +// +// This configuration does not define any network retry strategy. That is +// entirely handled by the gRPC ClientConn. +type RetryConfig retry.Config + +type wrappedOption struct { + oconf.GRPCOption +} + +func (w wrappedOption) applyGRPCOption(cfg oconf.Config) oconf.Config { + return w.ApplyGRPCOption(cfg) +} + +// WithInsecure disables client transport security for the Exporter's gRPC +// connection, just like grpc.WithInsecure() +// (https://pkg.go.dev/google.golang.org/grpc#WithInsecure) does. +// +// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// environment variable is set, and this option is not passed, that variable +// value will be used to determine client security. If the endpoint has a +// scheme of "http" or "unix" client security will be disabled. If both are +// set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, client security will be used. +// +// This option has no effect if WithGRPCConn is used. +func WithInsecure() Option { + return wrappedOption{oconf.WithInsecure()} +} + +// WithEndpoint sets the target endpoint the Exporter will connect to. +// +// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// environment variable is set, and this option is not passed, that variable +// value will be used. If both are set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, "localhost:4317" will be used. +// +// This option has no effect if WithGRPCConn is used. +func WithEndpoint(endpoint string) Option { + return wrappedOption{oconf.WithEndpoint(endpoint)} +} + +// WithReconnectionPeriod set the minimum amount of time between connection +// attempts to the target endpoint. +// +// This option has no effect if WithGRPCConn is used. +func WithReconnectionPeriod(rp time.Duration) Option { + return wrappedOption{oconf.NewGRPCOption(func(cfg oconf.Config) oconf.Config { + cfg.ReconnectionPeriod = rp + return cfg + })} +} + +func compressorToCompression(compressor string) oconf.Compression { + if compressor == "gzip" { + return oconf.GzipCompression + } + + otel.Handle(fmt.Errorf("invalid compression type: '%s', using no compression as default", compressor)) + return oconf.NoCompression +} + +// WithCompressor sets the compressor the gRPC client uses. +// +// It is the responsibility of the caller to ensure that the compressor set +// has been registered with google.golang.org/grpc/encoding (see +// encoding.RegisterCompressor for more information). For example, to register +// the gzip compressor import the package: +// +// import _ "google.golang.org/grpc/encoding/gzip" +// +// If the OTEL_EXPORTER_OTLP_COMPRESSION or +// OTEL_EXPORTER_OTLP_METRICS_COMPRESSION environment variable is set, and +// this option is not passed, that variable value will be used. That value can +// be either "none" or "gzip". If both are set, +// OTEL_EXPORTER_OTLP_METRICS_COMPRESSION will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, no compressor will be used. +// +// This option has no effect if WithGRPCConn is used. +func WithCompressor(compressor string) Option { + return wrappedOption{oconf.WithCompression(compressorToCompression(compressor))} +} + +// WithHeaders will send the provided headers with each gRPC requests. +// +// If the OTEL_EXPORTER_OTLP_HEADERS or OTEL_EXPORTER_OTLP_METRICS_HEADERS +// environment variable is set, and this option is not passed, that variable +// value will be used. The value will be parsed as a list of key value pairs. +// These pairs are expected to be in the W3C Correlation-Context format +// without additional semi-colon delimited metadata (i.e. "k1=v1,k2=v2"). If +// both are set, OTEL_EXPORTER_OTLP_METRICS_HEADERS will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, no user headers will be set. +func WithHeaders(headers map[string]string) Option { + return wrappedOption{oconf.WithHeaders(headers)} +} + +// WithTLSCredentials sets the gRPC connection to use creds. +// +// If the OTEL_EXPORTER_OTLP_CERTIFICATE or +// OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE environment variable is set, and +// this option is not passed, that variable value will be used. The value will +// be parsed the filepath of the TLS certificate chain to use. If both are +// set, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, no TLS credentials will be used. +// +// This option has no effect if WithGRPCConn is used. +func WithTLSCredentials(creds credentials.TransportCredentials) Option { + return wrappedOption{oconf.NewGRPCOption(func(cfg oconf.Config) oconf.Config { + cfg.Metrics.GRPCCredentials = creds + return cfg + })} +} + +// WithServiceConfig defines the default gRPC service config used. +// +// This option has no effect if WithGRPCConn is used. +func WithServiceConfig(serviceConfig string) Option { + return wrappedOption{oconf.NewGRPCOption(func(cfg oconf.Config) oconf.Config { + cfg.ServiceConfig = serviceConfig + return cfg + })} +} + +// WithDialOption sets explicit grpc.DialOptions to use when establishing a +// gRPC connection. The options here are appended to the internal grpc.DialOptions +// used so they will take precedence over any other internal grpc.DialOptions +// they might conflict with. +// +// This option has no effect if WithGRPCConn is used. +func WithDialOption(opts ...grpc.DialOption) Option { + return wrappedOption{oconf.NewGRPCOption(func(cfg oconf.Config) oconf.Config { + cfg.DialOptions = opts + return cfg + })} +} + +// WithGRPCConn sets conn as the gRPC ClientConn used for all communication. +// +// This option takes precedence over any other option that relates to +// establishing or persisting a gRPC connection to a target endpoint. Any +// other option of those types passed will be ignored. +// +// It is the callers responsibility to close the passed conn. The Exporter +// Shutdown method will not close this connection. +func WithGRPCConn(conn *grpc.ClientConn) Option { + return wrappedOption{oconf.NewGRPCOption(func(cfg oconf.Config) oconf.Config { + cfg.GRPCConn = conn + return cfg + })} +} + +// WithTimeout sets the max amount of time an Exporter will attempt an export. +// +// This takes precedence over any retry settings defined by WithRetry. Once +// this time limit has been reached the export is abandoned and the metric +// data is dropped. +// +// If the OTEL_EXPORTER_OTLP_TIMEOUT or OTEL_EXPORTER_OTLP_METRICS_TIMEOUT +// environment variable is set, and this option is not passed, that variable +// value will be used. The value will be parsed as an integer representing the +// timeout in milliseconds. If both are set, +// OTEL_EXPORTER_OTLP_METRICS_TIMEOUT will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, a timeout of 10 seconds will be used. +func WithTimeout(duration time.Duration) Option { + return wrappedOption{oconf.WithTimeout(duration)} +} + +// WithRetry sets the retry policy for transient retryable errors that are +// returned by the target endpoint. +// +// If the target endpoint responds with not only a retryable error, but +// explicitly returns a backoff time in the response, that time will take +// precedence over these settings. +// +// These settings do not define any network retry strategy. That is entirely +// handled by the gRPC ClientConn. +// +// If unset, the default retry policy will be used. It will retry the export +// 5 seconds after receiving a retryable error and increase exponentially +// after each error for no more than a total time of 1 minute. +func WithRetry(settings RetryConfig) Option { + return wrappedOption{oconf.WithRetry(retry.Config(settings))} +} + +// WithTemporalitySelector sets the TemporalitySelector the client will use to +// determine the Temporality of an instrument based on its kind. If this option +// is not used, the client will use the DefaultTemporalitySelector from the +// go.opentelemetry.io/otel/sdk/metric package. +func WithTemporalitySelector(selector metric.TemporalitySelector) Option { + return wrappedOption{oconf.WithTemporalitySelector(selector)} +} + +// WithAggregationSelector sets the AggregationSelector the client will use to +// determine the aggregation to use for an instrument based on its kind. If +// this option is not used, the reader will use the DefaultAggregationSelector +// from the go.opentelemetry.io/otel/sdk/metric package, or the aggregation +// explicitly passed for a view matching an instrument. +func WithAggregationSelector(selector metric.AggregationSelector) Option { + return wrappedOption{oconf.WithAggregationSelector(selector)} +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/doc.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/doc.go new file mode 100644 index 0000000000000..7820619bf6084 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package otlpmetricgrpc provides an otlpmetric.Exporter that communicates +// with an OTLP receiving endpoint using gRPC. +package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/exporter.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/exporter.go new file mode 100644 index 0000000000000..826276ba39224 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/exporter.go @@ -0,0 +1,167 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + +import ( + "context" + "fmt" + "sync" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +// Exporter is a OpenTelemetry metric Exporter using gRPC. +type Exporter struct { + // Ensure synchronous access to the client across all functionality. + clientMu sync.Mutex + client interface { + UploadMetrics(context.Context, *metricpb.ResourceMetrics) error + Shutdown(context.Context) error + } + + temporalitySelector metric.TemporalitySelector + aggregationSelector metric.AggregationSelector + + shutdownOnce sync.Once +} + +func newExporter(c *client, cfg oconf.Config) (*Exporter, error) { + ts := cfg.Metrics.TemporalitySelector + if ts == nil { + ts = func(metric.InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality + } + } + + as := cfg.Metrics.AggregationSelector + if as == nil { + as = metric.DefaultAggregationSelector + } + + return &Exporter{ + client: c, + + temporalitySelector: ts, + aggregationSelector: as, + }, nil +} + +// Temporality returns the Temporality to use for an instrument kind. +func (e *Exporter) Temporality(k metric.InstrumentKind) metricdata.Temporality { + return e.temporalitySelector(k) +} + +// Aggregation returns the Aggregation to use for an instrument kind. +func (e *Exporter) Aggregation(k metric.InstrumentKind) metric.Aggregation { + return e.aggregationSelector(k) +} + +// Export transforms and transmits metric data to an OTLP receiver. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +func (e *Exporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error { + defer global.Debug("OTLP/gRPC exporter export", "Data", rm) + + otlpRm, err := transform.ResourceMetrics(rm) + // Best effort upload of transformable metrics. + e.clientMu.Lock() + upErr := e.client.UploadMetrics(ctx, otlpRm) + e.clientMu.Unlock() + if upErr != nil { + if err == nil { + return fmt.Errorf("failed to upload metrics: %w", upErr) + } + // Merge the two errors. + return fmt.Errorf("failed to upload incomplete metrics (%s): %w", err, upErr) + } + return err +} + +// ForceFlush flushes any metric data held by an exporter. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +// +// This method is safe to call concurrently. +func (e *Exporter) ForceFlush(ctx context.Context) error { + // The exporter and client hold no state, nothing to flush. + return ctx.Err() +} + +// Shutdown flushes all metric data held by an exporter and releases any held +// computational resources. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +// +// This method is safe to call concurrently. +func (e *Exporter) Shutdown(ctx context.Context) error { + err := errShutdown + e.shutdownOnce.Do(func() { + e.clientMu.Lock() + client := e.client + e.client = shutdownClient{} + e.clientMu.Unlock() + err = client.Shutdown(ctx) + }) + return err +} + +var errShutdown = fmt.Errorf("gRPC exporter is shutdown") + +type shutdownClient struct{} + +func (c shutdownClient) err(ctx context.Context) error { + if err := ctx.Err(); err != nil { + return err + } + return errShutdown +} + +func (c shutdownClient) UploadMetrics(ctx context.Context, _ *metricpb.ResourceMetrics) error { + return c.err(ctx) +} + +func (c shutdownClient) Shutdown(ctx context.Context) error { + return c.err(ctx) +} + +// MarshalLog returns logging data about the Exporter. +func (e *Exporter) MarshalLog() interface{} { + return struct{ Type string }{Type: "OTLP/gRPC"} +} + +// New returns an OpenTelemetry metric Exporter. The Exporter can be used with +// a PeriodicReader to export OpenTelemetry metric data to an OTLP receiving +// endpoint using gRPC. +// +// If an already established gRPC ClientConn is not passed in options using +// WithGRPCConn, a connection to the OTLP endpoint will be established based +// on options. If a connection cannot be establishes in the lifetime of ctx, +// an error will be returned. +func New(ctx context.Context, options ...Option) (*Exporter, error) { + cfg := oconf.NewGRPCConfig(asGRPCOptions(options)...) + c, err := newClient(ctx, cfg) + if err != nil { + return nil, err + } + return newExporter(c, cfg) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig/envconfig.go new file mode 100644 index 0000000000000..1d571294695ce --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig/envconfig.go @@ -0,0 +1,202 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/envconfig/envconfig.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package envconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig" + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "go.opentelemetry.io/otel/internal/global" +) + +// ConfigFn is the generic function used to set a config. +type ConfigFn func(*EnvOptionsReader) + +// EnvOptionsReader reads the required environment variables. +type EnvOptionsReader struct { + GetEnv func(string) string + ReadFile func(string) ([]byte, error) + Namespace string +} + +// Apply runs every ConfigFn. +func (e *EnvOptionsReader) Apply(opts ...ConfigFn) { + for _, o := range opts { + o(e) + } +} + +// GetEnvValue gets an OTLP environment variable value of the specified key +// using the GetEnv function. +// This function prepends the OTLP specified namespace to all key lookups. +func (e *EnvOptionsReader) GetEnvValue(key string) (string, bool) { + v := strings.TrimSpace(e.GetEnv(keyWithNamespace(e.Namespace, key))) + return v, v != "" +} + +// WithString retrieves the specified config and passes it to ConfigFn as a string. +func WithString(n string, fn func(string)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + fn(v) + } + } +} + +// WithBool returns a ConfigFn that reads the environment variable n and if it exists passes its parsed bool value to fn. +func WithBool(n string, fn func(bool)) ConfigFn { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + b := strings.ToLower(v) == "true" + fn(b) + } + } +} + +// WithDuration retrieves the specified config and passes it to ConfigFn as a duration. +func WithDuration(n string, fn func(time.Duration)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + d, err := strconv.Atoi(v) + if err != nil { + global.Error(err, "parse duration", "input", v) + return + } + fn(time.Duration(d) * time.Millisecond) + } + } +} + +// WithHeaders retrieves the specified config and passes it to ConfigFn as a map of HTTP headers. +func WithHeaders(n string, fn func(map[string]string)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + fn(stringToHeader(v)) + } + } +} + +// WithURL retrieves the specified config and passes it to ConfigFn as a net/url.URL. +func WithURL(n string, fn func(*url.URL)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + u, err := url.Parse(v) + if err != nil { + global.Error(err, "parse url", "input", v) + return + } + fn(u) + } + } +} + +// WithCertPool returns a ConfigFn that reads the environment variable n as a filepath to a TLS certificate pool. If it exists, it is parsed as a crypto/x509.CertPool and it is passed to fn. +func WithCertPool(n string, fn func(*x509.CertPool)) ConfigFn { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + b, err := e.ReadFile(v) + if err != nil { + global.Error(err, "read tls ca cert file", "file", v) + return + } + c, err := createCertPool(b) + if err != nil { + global.Error(err, "create tls cert pool") + return + } + fn(c) + } + } +} + +// WithClientCert returns a ConfigFn that reads the environment variable nc and nk as filepaths to a client certificate and key pair. If they exists, they are parsed as a crypto/tls.Certificate and it is passed to fn. +func WithClientCert(nc, nk string, fn func(tls.Certificate)) ConfigFn { + return func(e *EnvOptionsReader) { + vc, okc := e.GetEnvValue(nc) + vk, okk := e.GetEnvValue(nk) + if !okc || !okk { + return + } + cert, err := e.ReadFile(vc) + if err != nil { + global.Error(err, "read tls client cert", "file", vc) + return + } + key, err := e.ReadFile(vk) + if err != nil { + global.Error(err, "read tls client key", "file", vk) + return + } + crt, err := tls.X509KeyPair(cert, key) + if err != nil { + global.Error(err, "create tls client key pair") + return + } + fn(crt) + } +} + +func keyWithNamespace(ns, key string) string { + if ns == "" { + return key + } + return fmt.Sprintf("%s_%s", ns, key) +} + +func stringToHeader(value string) map[string]string { + headersPairs := strings.Split(value, ",") + headers := make(map[string]string) + + for _, header := range headersPairs { + n, v, found := strings.Cut(header, "=") + if !found { + global.Error(errors.New("missing '="), "parse headers", "input", header) + continue + } + name, err := url.QueryUnescape(n) + if err != nil { + global.Error(err, "escape header key", "key", n) + continue + } + trimmedName := strings.TrimSpace(name) + value, err := url.QueryUnescape(v) + if err != nil { + global.Error(err, "escape header value", "value", v) + continue + } + trimmedValue := strings.TrimSpace(value) + + headers[trimmedName] = trimmedValue + } + + return headers +} + +func createCertPool(certBytes []byte) (*x509.CertPool, error) { + cp := x509.NewCertPool() + if ok := cp.AppendCertsFromPEM(certBytes); !ok { + return nil, errors.New("failed to append certificate to the cert pool") + } + return cp, nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go new file mode 100644 index 0000000000000..06718efa89869 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/gen.go @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal" + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess.go.tmpl "--data={}" --out=partialsuccess.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess_test.go.tmpl "--data={}" --out=partialsuccess_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry.go.tmpl "--data={}" --out=retry/retry.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry_test.go.tmpl "--data={}" --out=retry/retry_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig.go.tmpl "--data={}" --out=envconfig/envconfig.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig_test.go.tmpl "--data={}" --out=envconfig/envconfig_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig\"}" --out=oconf/envconfig.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig_test.go.tmpl "--data={}" --out=oconf/envconfig_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry\"}" --out=oconf/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig\"}" --out=oconf/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl "--data={}" --out=oconf/optiontypes.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl "--data={}" --out=oconf/tls.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/client.go.tmpl "--data={}" --out=otest/client.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/client_test.go.tmpl "--data={\"internalImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal\"}" --out=otest/client_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/collector.go.tmpl "--data={\"oconfImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf\"}" --out=otest/collector.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/attribute.go.tmpl "--data={}" --out=transform/attribute.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/attribute_test.go.tmpl "--data={}" --out=transform/attribute_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/error.go.tmpl "--data={}" --out=transform/error.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/error_test.go.tmpl "--data={}" --out=transform/error_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/metricdata.go.tmpl "--data={}" --out=transform/metricdata.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/metricdata_test.go.tmpl "--data={}" --out=transform/metricdata_test.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go new file mode 100644 index 0000000000000..ae100513bad3f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go @@ -0,0 +1,221 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + +import ( + "crypto/tls" + "crypto/x509" + "net/url" + "os" + "path" + "strings" + "time" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// DefaultEnvOptionsReader is the default environments reader. +var DefaultEnvOptionsReader = envconfig.EnvOptionsReader{ + GetEnv: os.Getenv, + ReadFile: os.ReadFile, + Namespace: "OTEL_EXPORTER_OTLP", +} + +// ApplyGRPCEnvConfigs applies the env configurations for gRPC. +func ApplyGRPCEnvConfigs(cfg Config) Config { + opts := getOptionsFromEnv() + for _, opt := range opts { + cfg = opt.ApplyGRPCOption(cfg) + } + return cfg +} + +// ApplyHTTPEnvConfigs applies the env configurations for HTTP. +func ApplyHTTPEnvConfigs(cfg Config) Config { + opts := getOptionsFromEnv() + for _, opt := range opts { + cfg = opt.ApplyHTTPOption(cfg) + } + return cfg +} + +func getOptionsFromEnv() []GenericOption { + opts := []GenericOption{} + + tlsConf := &tls.Config{} + DefaultEnvOptionsReader.Apply( + envconfig.WithURL("ENDPOINT", func(u *url.URL) { + opts = append(opts, withEndpointScheme(u)) + opts = append(opts, newSplitOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = u.Host + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Metrics.URLPath = path.Join(u.Path, DefaultMetricsPath) + return cfg + }, withEndpointForGRPC(u))) + }), + envconfig.WithURL("METRICS_ENDPOINT", func(u *url.URL) { + opts = append(opts, withEndpointScheme(u)) + opts = append(opts, newSplitOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = u.Host + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Metrics.URLPath = path + return cfg + }, withEndpointForGRPC(u))) + }), + envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }), + envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }), + envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }), + envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }), + envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }), + envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }), + withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }), + envconfig.WithHeaders("HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }), + envconfig.WithHeaders("METRICS_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }), + WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }), + WithEnvCompression("METRICS_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }), + envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }), + envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }), + withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }), + withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }), + ) + + return opts +} + +func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { + return func(cfg Config) Config { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + return cfg + } +} + +// WithEnvCompression retrieves the specified config and passes it to ConfigFn as a Compression. +func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + cp := NoCompression + if v == "gzip" { + cp = GzipCompression + } + + fn(cp) + } + } +} + +func withEndpointScheme(u *url.URL) GenericOption { + switch strings.ToLower(u.Scheme) { + case "http", "unix": + return WithInsecure() + default: + return WithSecure() + } +} + +// revive:disable-next-line:flag-parameter +func withInsecure(b bool) GenericOption { + if b { + return WithInsecure() + } + return WithSecure() +} + +func withTLSConfig(c *tls.Config, fn func(*tls.Config)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if c.RootCAs != nil || len(c.Certificates) > 0 { + fn(c) + } + } +} + +func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if s, ok := e.GetEnvValue(n); ok { + switch strings.ToLower(s) { + case "cumulative": + fn(cumulativeTemporality) + case "delta": + fn(deltaTemporality) + case "lowmemory": + fn(lowMemory) + default: + global.Warn("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", "value", s) + } + } + } +} + +func cumulativeTemporality(metric.InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality +} + +func deltaTemporality(ik metric.InstrumentKind) metricdata.Temporality { + switch ik { + case metric.InstrumentKindCounter, metric.InstrumentKindHistogram, metric.InstrumentKindObservableCounter: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +func lowMemory(ik metric.InstrumentKind) metricdata.Temporality { + switch ik { + case metric.InstrumentKindCounter, metric.InstrumentKindHistogram: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if s, ok := e.GetEnvValue(n); ok { + switch strings.ToLower(s) { + case "explicit_bucket_histogram": + fn(metric.DefaultAggregationSelector) + case "base2_exponential_bucket_histogram": + fn(func(kind metric.InstrumentKind) metric.Aggregation { + if kind == metric.InstrumentKindHistogram { + return metric.AggregationBase2ExponentialHistogram{ + MaxSize: 160, + MaxScale: 20, + NoMinMax: false, + } + } + return metric.DefaultAggregationSelector(kind) + }) + default: + global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s) + } + } + } +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go new file mode 100644 index 0000000000000..40a4469f77ae3 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go @@ -0,0 +1,359 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/options.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + +import ( + "crypto/tls" + "fmt" + "path" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/encoding/gzip" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry" + "go.opentelemetry.io/otel/sdk/metric" +) + +const ( + // DefaultMaxAttempts describes how many times the driver + // should retry the sending of the payload in case of a + // retryable error. + DefaultMaxAttempts int = 5 + // DefaultMetricsPath is a default URL path for endpoint that + // receives metrics. + DefaultMetricsPath string = "/v1/metrics" + // DefaultBackoff is a default base backoff time used in the + // exponential backoff strategy. + DefaultBackoff time.Duration = 300 * time.Millisecond + // DefaultTimeout is a default max waiting time for the backend to process + // each span or metrics batch. + DefaultTimeout time.Duration = 10 * time.Second +) + +type ( + SignalConfig struct { + Endpoint string + Insecure bool + TLSCfg *tls.Config + Headers map[string]string + Compression Compression + Timeout time.Duration + URLPath string + + // gRPC configurations + GRPCCredentials credentials.TransportCredentials + + TemporalitySelector metric.TemporalitySelector + AggregationSelector metric.AggregationSelector + } + + Config struct { + // Signal specific configurations + Metrics SignalConfig + + RetryConfig retry.Config + + // gRPC configurations + ReconnectionPeriod time.Duration + ServiceConfig string + DialOptions []grpc.DialOption + GRPCConn *grpc.ClientConn + } +) + +// NewHTTPConfig returns a new Config with all settings applied from opts and +// any unset setting using the default HTTP config values. +func NewHTTPConfig(opts ...HTTPOption) Config { + cfg := Config{ + Metrics: SignalConfig{ + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), + URLPath: DefaultMetricsPath, + Compression: NoCompression, + Timeout: DefaultTimeout, + + TemporalitySelector: metric.DefaultTemporalitySelector, + AggregationSelector: metric.DefaultAggregationSelector, + }, + RetryConfig: retry.DefaultConfig, + } + cfg = ApplyHTTPEnvConfigs(cfg) + for _, opt := range opts { + cfg = opt.ApplyHTTPOption(cfg) + } + cfg.Metrics.URLPath = cleanPath(cfg.Metrics.URLPath, DefaultMetricsPath) + return cfg +} + +// cleanPath returns a path with all spaces trimmed and all redundancies +// removed. If urlPath is empty or cleaning it results in an empty string, +// defaultPath is returned instead. +func cleanPath(urlPath string, defaultPath string) string { + tmp := path.Clean(strings.TrimSpace(urlPath)) + if tmp == "." { + return defaultPath + } + if !path.IsAbs(tmp) { + tmp = fmt.Sprintf("/%s", tmp) + } + return tmp +} + +// NewGRPCConfig returns a new Config with all settings applied from opts and +// any unset setting using the default gRPC config values. +func NewGRPCConfig(opts ...GRPCOption) Config { + userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() + cfg := Config{ + Metrics: SignalConfig{ + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort), + URLPath: DefaultMetricsPath, + Compression: NoCompression, + Timeout: DefaultTimeout, + + TemporalitySelector: metric.DefaultTemporalitySelector, + AggregationSelector: metric.DefaultAggregationSelector, + }, + RetryConfig: retry.DefaultConfig, + DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)}, + } + cfg = ApplyGRPCEnvConfigs(cfg) + for _, opt := range opts { + cfg = opt.ApplyGRPCOption(cfg) + } + + if cfg.ServiceConfig != "" { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + } + // Priroritize GRPCCredentials over Insecure (passing both is an error). + if cfg.Metrics.GRPCCredentials != nil { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) + } else if cfg.Metrics.Insecure { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + } else { + // Default to using the host's root CA. + creds := credentials.NewTLS(nil) + cfg.Metrics.GRPCCredentials = creds + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + } + if cfg.Metrics.Compression == GzipCompression { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + } + if len(cfg.DialOptions) != 0 { + cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...) + } + if cfg.ReconnectionPeriod != 0 { + p := grpc.ConnectParams{ + Backoff: backoff.DefaultConfig, + MinConnectTimeout: cfg.ReconnectionPeriod, + } + cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + } + + return cfg +} + +type ( + // GenericOption applies an option to the HTTP or gRPC driver. + GenericOption interface { + ApplyHTTPOption(Config) Config + ApplyGRPCOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } + + // HTTPOption applies an option to the HTTP driver. + HTTPOption interface { + ApplyHTTPOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } + + // GRPCOption applies an option to the gRPC driver. + GRPCOption interface { + ApplyGRPCOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } +) + +// genericOption is an option that applies the same logic +// for both gRPC and HTTP. +type genericOption struct { + fn func(Config) Config +} + +func (g *genericOption) ApplyGRPCOption(cfg Config) Config { + return g.fn(cfg) +} + +func (g *genericOption) ApplyHTTPOption(cfg Config) Config { + return g.fn(cfg) +} + +func (genericOption) private() {} + +func newGenericOption(fn func(cfg Config) Config) GenericOption { + return &genericOption{fn: fn} +} + +// splitOption is an option that applies different logics +// for gRPC and HTTP. +type splitOption struct { + httpFn func(Config) Config + grpcFn func(Config) Config +} + +func (g *splitOption) ApplyGRPCOption(cfg Config) Config { + return g.grpcFn(cfg) +} + +func (g *splitOption) ApplyHTTPOption(cfg Config) Config { + return g.httpFn(cfg) +} + +func (splitOption) private() {} + +func newSplitOption(httpFn func(cfg Config) Config, grpcFn func(cfg Config) Config) GenericOption { + return &splitOption{httpFn: httpFn, grpcFn: grpcFn} +} + +// httpOption is an option that is only applied to the HTTP driver. +type httpOption struct { + fn func(Config) Config +} + +func (h *httpOption) ApplyHTTPOption(cfg Config) Config { + return h.fn(cfg) +} + +func (httpOption) private() {} + +func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { + return &httpOption{fn: fn} +} + +// grpcOption is an option that is only applied to the gRPC driver. +type grpcOption struct { + fn func(Config) Config +} + +func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { + return h.fn(cfg) +} + +func (grpcOption) private() {} + +func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { + return &grpcOption{fn: fn} +} + +// Generic Options + +func WithEndpoint(endpoint string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = endpoint + return cfg + }) +} + +func WithCompression(compression Compression) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Compression = compression + return cfg + }) +} + +func WithURLPath(urlPath string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.URLPath = urlPath + return cfg + }) +} + +func WithRetry(rc retry.Config) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.RetryConfig = rc + return cfg + }) +} + +func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { + return newSplitOption(func(cfg Config) Config { + cfg.Metrics.TLSCfg = tlsCfg.Clone() + return cfg + }, func(cfg Config) Config { + cfg.Metrics.GRPCCredentials = credentials.NewTLS(tlsCfg) + return cfg + }) +} + +func WithInsecure() GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Insecure = true + return cfg + }) +} + +func WithSecure() GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Insecure = false + return cfg + }) +} + +func WithHeaders(headers map[string]string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Headers = headers + return cfg + }) +} + +func WithTimeout(duration time.Duration) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Timeout = duration + return cfg + }) +} + +func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.TemporalitySelector = selector + return cfg + }) +} + +func WithAggregationSelector(selector metric.AggregationSelector) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.AggregationSelector = selector + return cfg + }) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/optiontypes.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/optiontypes.go new file mode 100644 index 0000000000000..8a3c8422e1bc1 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/optiontypes.go @@ -0,0 +1,58 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + +import "time" + +const ( + // DefaultCollectorGRPCPort is the default gRPC port of the collector. + DefaultCollectorGRPCPort uint16 = 4317 + // DefaultCollectorHTTPPort is the default HTTP port of the collector. + DefaultCollectorHTTPPort uint16 = 4318 + // DefaultCollectorHost is the host address the Exporter will attempt + // connect to if no collector address is provided. + DefaultCollectorHost string = "localhost" +) + +// Compression describes the compression used for payloads sent to the +// collector. +type Compression int + +const ( + // NoCompression tells the driver to send payloads without + // compression. + NoCompression Compression = iota + // GzipCompression tells the driver to send payloads after + // compressing them with gzip. + GzipCompression +) + +// RetrySettings defines configuration for retrying batches in case of export failure +// using an exponential backoff. +type RetrySettings struct { + // Enabled indicates whether to not retry sending batches in case of export failure. + Enabled bool + // InitialInterval the time to wait after the first failure before retrying. + InitialInterval time.Duration + // MaxInterval is the upper bound on backoff interval. Once this value is reached the delay between + // consecutive retries will always be `MaxInterval`. + MaxInterval time.Duration + // MaxElapsedTime is the maximum amount of time (including retries) spent trying to send a request/batch. + // Once this value is reached, the data is discarded. + MaxElapsedTime time.Duration +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/tls.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/tls.go new file mode 100644 index 0000000000000..2e36e0b6f253d --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/tls.go @@ -0,0 +1,49 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf" + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "os" +) + +// ReadTLSConfigFromFile reads a PEM certificate file and creates +// a tls.Config that will use this certifate to verify a server certificate. +func ReadTLSConfigFromFile(path string) (*tls.Config, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + return CreateTLSConfig(b) +} + +// CreateTLSConfig creates a tls.Config from a raw certificate bytes +// to verify a server certificate. +func CreateTLSConfig(certBytes []byte) (*tls.Config, error) { + cp := x509.NewCertPool() + if ok := cp.AppendCertsFromPEM(certBytes); !ok { + return nil, errors.New("failed to append certificate to the cert pool") + } + + return &tls.Config{ + RootCAs: cp, + }, nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/partialsuccess.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/partialsuccess.go new file mode 100644 index 0000000000000..f4d48198251d0 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/partialsuccess.go @@ -0,0 +1,67 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/partialsuccess.go + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal" + +import "fmt" + +// PartialSuccess represents the underlying error for all handling +// OTLP partial success messages. Use `errors.Is(err, +// PartialSuccess{})` to test whether an error passed to the OTel +// error handler belongs to this category. +type PartialSuccess struct { + ErrorMessage string + RejectedItems int64 + RejectedKind string +} + +var _ error = PartialSuccess{} + +// Error implements the error interface. +func (ps PartialSuccess) Error() string { + msg := ps.ErrorMessage + if msg == "" { + msg = "empty message" + } + return fmt.Sprintf("OTLP partial success: %s (%d %s rejected)", msg, ps.RejectedItems, ps.RejectedKind) +} + +// Is supports the errors.Is() interface. +func (ps PartialSuccess) Is(err error) bool { + _, ok := err.(PartialSuccess) + return ok +} + +// TracePartialSuccessError returns an error describing a partial success +// response for the trace signal. +func TracePartialSuccessError(itemsRejected int64, errorMessage string) error { + return PartialSuccess{ + ErrorMessage: errorMessage, + RejectedItems: itemsRejected, + RejectedKind: "spans", + } +} + +// MetricPartialSuccessError returns an error describing a partial success +// response for the metric signal. +func MetricPartialSuccessError(itemsRejected int64, errorMessage string) error { + return PartialSuccess{ + ErrorMessage: errorMessage, + RejectedItems: itemsRejected, + RejectedKind: "metric data points", + } +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry/retry.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry/retry.go new file mode 100644 index 0000000000000..689779c360439 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry/retry.go @@ -0,0 +1,156 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/retry/retry.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package retry provides request retry functionality that can perform +// configurable exponential backoff for transient errors and honor any +// explicit throttle responses received. +package retry // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry" + +import ( + "context" + "fmt" + "time" + + "github.com/cenkalti/backoff/v4" +) + +// DefaultConfig are the recommended defaults to use. +var DefaultConfig = Config{ + Enabled: true, + InitialInterval: 5 * time.Second, + MaxInterval: 30 * time.Second, + MaxElapsedTime: time.Minute, +} + +// Config defines configuration for retrying batches in case of export failure +// using an exponential backoff. +type Config struct { + // Enabled indicates whether to not retry sending batches in case of + // export failure. + Enabled bool + // InitialInterval the time to wait after the first failure before + // retrying. + InitialInterval time.Duration + // MaxInterval is the upper bound on backoff interval. Once this value is + // reached the delay between consecutive retries will always be + // `MaxInterval`. + MaxInterval time.Duration + // MaxElapsedTime is the maximum amount of time (including retries) spent + // trying to send a request/batch. Once this value is reached, the data + // is discarded. + MaxElapsedTime time.Duration +} + +// RequestFunc wraps a request with retry logic. +type RequestFunc func(context.Context, func(context.Context) error) error + +// EvaluateFunc returns if an error is retry-able and if an explicit throttle +// duration should be honored that was included in the error. +// +// The function must return true if the error argument is retry-able, +// otherwise it must return false for the first return parameter. +// +// The function must return a non-zero time.Duration if the error contains +// explicit throttle duration that should be honored, otherwise it must return +// a zero valued time.Duration. +type EvaluateFunc func(error) (bool, time.Duration) + +// RequestFunc returns a RequestFunc using the evaluate function to determine +// if requests can be retried and based on the exponential backoff +// configuration of c. +func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc { + if !c.Enabled { + return func(ctx context.Context, fn func(context.Context) error) error { + return fn(ctx) + } + } + + return func(ctx context.Context, fn func(context.Context) error) error { + // Do not use NewExponentialBackOff since it calls Reset and the code here + // must call Reset after changing the InitialInterval (this saves an + // unnecessary call to Now). + b := &backoff.ExponentialBackOff{ + InitialInterval: c.InitialInterval, + RandomizationFactor: backoff.DefaultRandomizationFactor, + Multiplier: backoff.DefaultMultiplier, + MaxInterval: c.MaxInterval, + MaxElapsedTime: c.MaxElapsedTime, + Stop: backoff.Stop, + Clock: backoff.SystemClock, + } + b.Reset() + + for { + err := fn(ctx) + if err == nil { + return nil + } + + retryable, throttle := evaluate(err) + if !retryable { + return err + } + + bOff := b.NextBackOff() + if bOff == backoff.Stop { + return fmt.Errorf("max retry time elapsed: %w", err) + } + + // Wait for the greater of the backoff or throttle delay. + var delay time.Duration + if bOff > throttle { + delay = bOff + } else { + elapsed := b.GetElapsedTime() + if b.MaxElapsedTime != 0 && elapsed+throttle > b.MaxElapsedTime { + return fmt.Errorf("max retry time would elapse: %w", err) + } + delay = throttle + } + + if ctxErr := waitFunc(ctx, delay); ctxErr != nil { + return fmt.Errorf("%w: %s", ctxErr, err) + } + } + } +} + +// Allow override for testing. +var waitFunc = wait + +// wait takes the caller's context, and the amount of time to wait. It will +// return nil if the timer fires before or at the same time as the context's +// deadline. This indicates that the call can be retried. +func wait(ctx context.Context, delay time.Duration) error { + timer := time.NewTimer(delay) + defer timer.Stop() + + select { + case <-ctx.Done(): + // Handle the case where the timer and context deadline end + // simultaneously by prioritizing the timer expiration nil value + // response. + select { + case <-timer.C: + default: + return ctx.Err() + } + case <-timer.C: + } + + return nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/attribute.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/attribute.go new file mode 100644 index 0000000000000..e80798eebde48 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/attribute.go @@ -0,0 +1,155 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/attribute.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform" + +import ( + "go.opentelemetry.io/otel/attribute" + cpb "go.opentelemetry.io/proto/otlp/common/v1" +) + +// AttrIter transforms an attribute iterator into OTLP key-values. +func AttrIter(iter attribute.Iterator) []*cpb.KeyValue { + l := iter.Len() + if l == 0 { + return nil + } + + out := make([]*cpb.KeyValue, 0, l) + for iter.Next() { + out = append(out, KeyValue(iter.Attribute())) + } + return out +} + +// KeyValues transforms a slice of attribute KeyValues into OTLP key-values. +func KeyValues(attrs []attribute.KeyValue) []*cpb.KeyValue { + if len(attrs) == 0 { + return nil + } + + out := make([]*cpb.KeyValue, 0, len(attrs)) + for _, kv := range attrs { + out = append(out, KeyValue(kv)) + } + return out +} + +// KeyValue transforms an attribute KeyValue into an OTLP key-value. +func KeyValue(kv attribute.KeyValue) *cpb.KeyValue { + return &cpb.KeyValue{Key: string(kv.Key), Value: Value(kv.Value)} +} + +// Value transforms an attribute Value into an OTLP AnyValue. +func Value(v attribute.Value) *cpb.AnyValue { + av := new(cpb.AnyValue) + switch v.Type() { + case attribute.BOOL: + av.Value = &cpb.AnyValue_BoolValue{ + BoolValue: v.AsBool(), + } + case attribute.BOOLSLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: boolSliceValues(v.AsBoolSlice()), + }, + } + case attribute.INT64: + av.Value = &cpb.AnyValue_IntValue{ + IntValue: v.AsInt64(), + } + case attribute.INT64SLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: int64SliceValues(v.AsInt64Slice()), + }, + } + case attribute.FLOAT64: + av.Value = &cpb.AnyValue_DoubleValue{ + DoubleValue: v.AsFloat64(), + } + case attribute.FLOAT64SLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: float64SliceValues(v.AsFloat64Slice()), + }, + } + case attribute.STRING: + av.Value = &cpb.AnyValue_StringValue{ + StringValue: v.AsString(), + } + case attribute.STRINGSLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: stringSliceValues(v.AsStringSlice()), + }, + } + default: + av.Value = &cpb.AnyValue_StringValue{ + StringValue: "INVALID", + } + } + return av +} + +func boolSliceValues(vals []bool) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_BoolValue{ + BoolValue: v, + }, + } + } + return converted +} + +func int64SliceValues(vals []int64) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_IntValue{ + IntValue: v, + }, + } + } + return converted +} + +func float64SliceValues(vals []float64) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_DoubleValue{ + DoubleValue: v, + }, + } + } + return converted +} + +func stringSliceValues(vals []string) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_StringValue{ + StringValue: v, + }, + } + } + return converted +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/error.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/error.go new file mode 100644 index 0000000000000..d5d2fdcb7ea70 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/error.go @@ -0,0 +1,114 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/error.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform" + +import ( + "errors" + "fmt" + "strings" + + mpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +var ( + errUnknownAggregation = errors.New("unknown aggregation") + errUnknownTemporality = errors.New("unknown temporality") +) + +type errMetric struct { + m *mpb.Metric + err error +} + +func (e errMetric) Unwrap() error { + return e.err +} + +func (e errMetric) Error() string { + format := "invalid metric (name: %q, description: %q, unit: %q): %s" + return fmt.Sprintf(format, e.m.Name, e.m.Description, e.m.Unit, e.err) +} + +func (e errMetric) Is(target error) bool { + return errors.Is(e.err, target) +} + +// multiErr is used by the data-type transform functions to wrap multiple +// errors into a single return value. The error message will show all errors +// as a list and scope them by the datatype name that is returning them. +type multiErr struct { + datatype string + errs []error +} + +// errOrNil returns nil if e contains no errors, otherwise it returns e. +func (e *multiErr) errOrNil() error { + if len(e.errs) == 0 { + return nil + } + return e +} + +// append adds err to e. If err is a multiErr, its errs are flattened into e. +func (e *multiErr) append(err error) { + // Do not use errors.As here, this should only be flattened one layer. If + // there is a *multiErr several steps down the chain, all the errors above + // it will be discarded if errors.As is used instead. + switch other := err.(type) { + case *multiErr: + // Flatten err errors into e. + e.errs = append(e.errs, other.errs...) + default: + e.errs = append(e.errs, err) + } +} + +func (e *multiErr) Error() string { + es := make([]string, len(e.errs)) + for i, err := range e.errs { + es[i] = fmt.Sprintf("* %s", err) + } + + format := "%d errors occurred transforming %s:\n\t%s" + return fmt.Sprintf(format, len(es), e.datatype, strings.Join(es, "\n\t")) +} + +func (e *multiErr) Unwrap() error { + switch len(e.errs) { + case 0: + return nil + case 1: + return e.errs[0] + } + + // Return a multiErr without the leading error. + cp := &multiErr{ + datatype: e.datatype, + errs: make([]error, len(e.errs)-1), + } + copy(cp.errs, e.errs[1:]) + return cp +} + +func (e *multiErr) Is(target error) bool { + if len(e.errs) == 0 { + return false + } + // Check if the first error is target. + return errors.Is(e.errs[0], target) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go new file mode 100644 index 0000000000000..00d5c74ad906e --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform/metricdata.go @@ -0,0 +1,292 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/metricdata.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package transform provides transformation functionality from the +// sdk/metric/metricdata data-types into OTLP data-types. +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform" + +import ( + "fmt" + "time" + + "go.opentelemetry.io/otel/sdk/metric/metricdata" + cpb "go.opentelemetry.io/proto/otlp/common/v1" + mpb "go.opentelemetry.io/proto/otlp/metrics/v1" + rpb "go.opentelemetry.io/proto/otlp/resource/v1" +) + +// ResourceMetrics returns an OTLP ResourceMetrics generated from rm. If rm +// contains invalid ScopeMetrics, an error will be returned along with an OTLP +// ResourceMetrics that contains partial OTLP ScopeMetrics. +func ResourceMetrics(rm *metricdata.ResourceMetrics) (*mpb.ResourceMetrics, error) { + sms, err := ScopeMetrics(rm.ScopeMetrics) + return &mpb.ResourceMetrics{ + Resource: &rpb.Resource{ + Attributes: AttrIter(rm.Resource.Iter()), + }, + ScopeMetrics: sms, + SchemaUrl: rm.Resource.SchemaURL(), + }, err +} + +// ScopeMetrics returns a slice of OTLP ScopeMetrics generated from sms. If +// sms contains invalid metric values, an error will be returned along with a +// slice that contains partial OTLP ScopeMetrics. +func ScopeMetrics(sms []metricdata.ScopeMetrics) ([]*mpb.ScopeMetrics, error) { + errs := &multiErr{datatype: "ScopeMetrics"} + out := make([]*mpb.ScopeMetrics, 0, len(sms)) + for _, sm := range sms { + ms, err := Metrics(sm.Metrics) + if err != nil { + errs.append(err) + } + + out = append(out, &mpb.ScopeMetrics{ + Scope: &cpb.InstrumentationScope{ + Name: sm.Scope.Name, + Version: sm.Scope.Version, + }, + Metrics: ms, + SchemaUrl: sm.Scope.SchemaURL, + }) + } + return out, errs.errOrNil() +} + +// Metrics returns a slice of OTLP Metric generated from ms. If ms contains +// invalid metric values, an error will be returned along with a slice that +// contains partial OTLP Metrics. +func Metrics(ms []metricdata.Metrics) ([]*mpb.Metric, error) { + errs := &multiErr{datatype: "Metrics"} + out := make([]*mpb.Metric, 0, len(ms)) + for _, m := range ms { + o, err := metric(m) + if err != nil { + // Do not include invalid data. Drop the metric, report the error. + errs.append(errMetric{m: o, err: err}) + continue + } + out = append(out, o) + } + return out, errs.errOrNil() +} + +func metric(m metricdata.Metrics) (*mpb.Metric, error) { + var err error + out := &mpb.Metric{ + Name: m.Name, + Description: m.Description, + Unit: string(m.Unit), + } + switch a := m.Data.(type) { + case metricdata.Gauge[int64]: + out.Data = Gauge[int64](a) + case metricdata.Gauge[float64]: + out.Data = Gauge[float64](a) + case metricdata.Sum[int64]: + out.Data, err = Sum[int64](a) + case metricdata.Sum[float64]: + out.Data, err = Sum[float64](a) + case metricdata.Histogram[int64]: + out.Data, err = Histogram(a) + case metricdata.Histogram[float64]: + out.Data, err = Histogram(a) + case metricdata.ExponentialHistogram[int64]: + out.Data, err = ExponentialHistogram(a) + case metricdata.ExponentialHistogram[float64]: + out.Data, err = ExponentialHistogram(a) + default: + return out, fmt.Errorf("%w: %T", errUnknownAggregation, a) + } + return out, err +} + +// Gauge returns an OTLP Metric_Gauge generated from g. +func Gauge[N int64 | float64](g metricdata.Gauge[N]) *mpb.Metric_Gauge { + return &mpb.Metric_Gauge{ + Gauge: &mpb.Gauge{ + DataPoints: DataPoints(g.DataPoints), + }, + } +} + +// Sum returns an OTLP Metric_Sum generated from s. An error is returned +// if the temporality of s is unknown. +func Sum[N int64 | float64](s metricdata.Sum[N]) (*mpb.Metric_Sum, error) { + t, err := Temporality(s.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_Sum{ + Sum: &mpb.Sum{ + AggregationTemporality: t, + IsMonotonic: s.IsMonotonic, + DataPoints: DataPoints(s.DataPoints), + }, + }, nil +} + +// DataPoints returns a slice of OTLP NumberDataPoint generated from dPts. +func DataPoints[N int64 | float64](dPts []metricdata.DataPoint[N]) []*mpb.NumberDataPoint { + out := make([]*mpb.NumberDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + ndp := &mpb.NumberDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + } + switch v := any(dPt.Value).(type) { + case int64: + ndp.Value = &mpb.NumberDataPoint_AsInt{ + AsInt: v, + } + case float64: + ndp.Value = &mpb.NumberDataPoint_AsDouble{ + AsDouble: v, + } + } + out = append(out, ndp) + } + return out +} + +// Histogram returns an OTLP Metric_Histogram generated from h. An error is +// returned if the temporality of h is unknown. +func Histogram[N int64 | float64](h metricdata.Histogram[N]) (*mpb.Metric_Histogram, error) { + t, err := Temporality(h.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_Histogram{ + Histogram: &mpb.Histogram{ + AggregationTemporality: t, + DataPoints: HistogramDataPoints(h.DataPoints), + }, + }, nil +} + +// HistogramDataPoints returns a slice of OTLP HistogramDataPoint generated +// from dPts. +func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint[N]) []*mpb.HistogramDataPoint { + out := make([]*mpb.HistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + hdp := &mpb.HistogramDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + BucketCounts: dPt.BucketCounts, + ExplicitBounds: dPt.Bounds, + } + if v, ok := dPt.Min.Value(); ok { + vF64 := float64(v) + hdp.Min = &vF64 + } + if v, ok := dPt.Max.Value(); ok { + vF64 := float64(v) + hdp.Max = &vF64 + } + out = append(out, hdp) + } + return out +} + +// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is +// returned if the temporality of h is unknown. +func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) { + t, err := Temporality(h.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_ExponentialHistogram{ + ExponentialHistogram: &mpb.ExponentialHistogram{ + AggregationTemporality: t, + DataPoints: ExponentialHistogramDataPoints(h.DataPoints), + }, + }, nil +} + +// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated +// from dPts. +func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint { + out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + ehdp := &mpb.ExponentialHistogramDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + Scale: dPt.Scale, + ZeroCount: dPt.ZeroCount, + + Positive: ExponentialHistogramDataPointBuckets(dPt.PositiveBucket), + Negative: ExponentialHistogramDataPointBuckets(dPt.NegativeBucket), + } + if v, ok := dPt.Min.Value(); ok { + vF64 := float64(v) + ehdp.Min = &vF64 + } + if v, ok := dPt.Max.Value(); ok { + vF64 := float64(v) + ehdp.Max = &vF64 + } + out = append(out, ehdp) + } + return out +} + +// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated +// from bucket. +func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets { + return &mpb.ExponentialHistogramDataPoint_Buckets{ + Offset: bucket.Offset, + BucketCounts: bucket.Counts, + } +} + +// Temporality returns an OTLP AggregationTemporality generated from t. If t +// is unknown, an error is returned along with the invalid +// AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED. +func Temporality(t metricdata.Temporality) (mpb.AggregationTemporality, error) { + switch t { + case metricdata.DeltaTemporality: + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, nil + case metricdata.CumulativeTemporality: + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE, nil + default: + err := fmt.Errorf("%w: %s", errUnknownTemporality, t) + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED, err + } +} + +// timeUnixNano returns t as a Unix time, the number of nanoseconds elapsed +// since January 1, 1970 UTC as uint64. +// The result is undefined if the Unix time +// in nanoseconds cannot be represented by an int64 +// (a date before the year 1678 or after 2262). +// timeUnixNano on the zero Time returns 0. +// The result does not depend on the location associated with t. +func timeUnixNano(t time.Time) uint64 { + if t.IsZero() { + return 0 + } + return uint64(t.UnixNano()) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/LICENSE b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go new file mode 100644 index 0000000000000..33f5474c1aa22 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/client.go @@ -0,0 +1,297 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + +import ( + "bytes" + "compress/gzip" + "context" + "fmt" + "io" + "net" + "net/http" + "net/url" + "strconv" + "sync" + "time" + + "google.golang.org/protobuf/proto" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" + colmetricpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1" + metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +type client struct { + // req is cloned for every upload the client makes. + req *http.Request + compression Compression + requestFunc retry.RequestFunc + httpClient *http.Client +} + +// Keep it in sync with golang's DefaultTransport from net/http! We +// have our own copy to avoid handling a situation where the +// DefaultTransport is overwritten with some different implementation +// of http.RoundTripper or it's modified by another package. +var ourTransport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, +} + +// newClient creates a new HTTP metric client. +func newClient(cfg oconf.Config) (*client, error) { + httpClient := &http.Client{ + Transport: ourTransport, + Timeout: cfg.Metrics.Timeout, + } + if cfg.Metrics.TLSCfg != nil { + transport := ourTransport.Clone() + transport.TLSClientConfig = cfg.Metrics.TLSCfg + httpClient.Transport = transport + } + + u := &url.URL{ + Scheme: "https", + Host: cfg.Metrics.Endpoint, + Path: cfg.Metrics.URLPath, + } + if cfg.Metrics.Insecure { + u.Scheme = "http" + } + // Body is set when this is cloned during upload. + req, err := http.NewRequest(http.MethodPost, u.String(), http.NoBody) + if err != nil { + return nil, err + } + + userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() + req.Header.Set("User-Agent", userAgent) + + if n := len(cfg.Metrics.Headers); n > 0 { + for k, v := range cfg.Metrics.Headers { + req.Header.Set(k, v) + } + } + req.Header.Set("Content-Type", "application/x-protobuf") + + return &client{ + compression: Compression(cfg.Metrics.Compression), + req: req, + requestFunc: cfg.RetryConfig.RequestFunc(evaluate), + httpClient: httpClient, + }, nil +} + +// Shutdown shuts down the client, freeing all resources. +func (c *client) Shutdown(ctx context.Context) error { + // The otlpmetric.Exporter synchronizes access to client methods and + // ensures this is called only once. The only thing that needs to be done + // here is to release any computational resources the client holds. + + c.requestFunc = nil + c.httpClient = nil + return ctx.Err() +} + +// UploadMetrics sends protoMetrics to the connected endpoint. +// +// Retryable errors from the server will be handled according to any +// RetryConfig the client was created with. +func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.ResourceMetrics) error { + // The otlpmetric.Exporter synchronizes access to client methods, and + // ensures this is not called after the Exporter is shutdown. Only thing + // to do here is send data. + + pbRequest := &colmetricpb.ExportMetricsServiceRequest{ + ResourceMetrics: []*metricpb.ResourceMetrics{protoMetrics}, + } + body, err := proto.Marshal(pbRequest) + if err != nil { + return err + } + request, err := c.newRequest(ctx, body) + if err != nil { + return err + } + + return c.requestFunc(ctx, func(iCtx context.Context) error { + select { + case <-iCtx.Done(): + return iCtx.Err() + default: + } + + request.reset(iCtx) + resp, err := c.httpClient.Do(request.Request) + if err != nil { + return err + } + + var rErr error + switch sc := resp.StatusCode; { + case sc >= 200 && sc <= 299: + // Success, do not retry. + + // Read the partial success message, if any. + var respData bytes.Buffer + if _, err := io.Copy(&respData, resp.Body); err != nil { + return err + } + + if respData.Len() != 0 { + var respProto colmetricpb.ExportMetricsServiceResponse + if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil { + return err + } + + if respProto.PartialSuccess != nil { + msg := respProto.PartialSuccess.GetErrorMessage() + n := respProto.PartialSuccess.GetRejectedDataPoints() + if n != 0 || msg != "" { + err := internal.MetricPartialSuccessError(n, msg) + otel.Handle(err) + } + } + } + return nil + case sc == http.StatusTooManyRequests, sc == http.StatusServiceUnavailable: + // Retry-able failure. + rErr = newResponseError(resp.Header) + + // Going to retry, drain the body to reuse the connection. + if _, err := io.Copy(io.Discard, resp.Body); err != nil { + _ = resp.Body.Close() + return err + } + default: + rErr = fmt.Errorf("failed to send metrics to %s: %s", request.URL, resp.Status) + } + + if err := resp.Body.Close(); err != nil { + return err + } + return rErr + }) +} + +var gzPool = sync.Pool{ + New: func() interface{} { + w := gzip.NewWriter(io.Discard) + return w + }, +} + +func (c *client) newRequest(ctx context.Context, body []byte) (request, error) { + r := c.req.Clone(ctx) + req := request{Request: r} + + switch c.compression { + case NoCompression: + r.ContentLength = (int64)(len(body)) + req.bodyReader = bodyReader(body) + case GzipCompression: + // Ensure the content length is not used. + r.ContentLength = -1 + r.Header.Set("Content-Encoding", "gzip") + + gz := gzPool.Get().(*gzip.Writer) + defer gzPool.Put(gz) + + var b bytes.Buffer + gz.Reset(&b) + + if _, err := gz.Write(body); err != nil { + return req, err + } + // Close needs to be called to ensure body if fully written. + if err := gz.Close(); err != nil { + return req, err + } + + req.bodyReader = bodyReader(b.Bytes()) + } + + return req, nil +} + +// bodyReader returns a closure returning a new reader for buf. +func bodyReader(buf []byte) func() io.ReadCloser { + return func() io.ReadCloser { + return io.NopCloser(bytes.NewReader(buf)) + } +} + +// request wraps an http.Request with a resettable body reader. +type request struct { + *http.Request + + // bodyReader allows the same body to be used for multiple requests. + bodyReader func() io.ReadCloser +} + +// reset reinitializes the request Body and uses ctx for the request. +func (r *request) reset(ctx context.Context) { + r.Body = r.bodyReader() + r.Request = r.Request.WithContext(ctx) +} + +// retryableError represents a request failure that can be retried. +type retryableError struct { + throttle int64 +} + +// newResponseError returns a retryableError and will extract any explicit +// throttle delay contained in headers. +func newResponseError(header http.Header) error { + var rErr retryableError + if v := header.Get("Retry-After"); v != "" { + if t, err := strconv.ParseInt(v, 10, 64); err == nil { + rErr.throttle = t + } + } + return rErr +} + +func (e retryableError) Error() string { + return "retry-able request failure" +} + +// evaluate returns if err is retry-able. If it is and it includes an explicit +// throttling delay, that delay is also returned. +func evaluate(err error) (bool, time.Duration) { + if err == nil { + return false, 0 + } + + rErr, ok := err.(retryableError) + if !ok { + return false, 0 + } + + return true, time.Duration(rErr.throttle) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go new file mode 100644 index 0000000000000..6eae3e1bbdac0 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/config.go @@ -0,0 +1,199 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + +import ( + "crypto/tls" + "time" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" + "go.opentelemetry.io/otel/sdk/metric" +) + +// Compression describes the compression used for payloads sent to the +// collector. +type Compression oconf.Compression + +const ( + // NoCompression tells the driver to send payloads without + // compression. + NoCompression = Compression(oconf.NoCompression) + // GzipCompression tells the driver to send payloads after + // compressing them with gzip. + GzipCompression = Compression(oconf.GzipCompression) +) + +// Option applies an option to the Exporter. +type Option interface { + applyHTTPOption(oconf.Config) oconf.Config +} + +func asHTTPOptions(opts []Option) []oconf.HTTPOption { + converted := make([]oconf.HTTPOption, len(opts)) + for i, o := range opts { + converted[i] = oconf.NewHTTPOption(o.applyHTTPOption) + } + return converted +} + +// RetryConfig defines configuration for retrying the export of metric data +// that failed. +type RetryConfig retry.Config + +type wrappedOption struct { + oconf.HTTPOption +} + +func (w wrappedOption) applyHTTPOption(cfg oconf.Config) oconf.Config { + return w.ApplyHTTPOption(cfg) +} + +// WithEndpoint sets the target endpoint the Exporter will connect to. This +// endpoint is specified as a host and optional port, no path or scheme should +// be included (see WithInsecure and WithURLPath). +// +// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// environment variable is set, and this option is not passed, that variable +// value will be used. If both are set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, "localhost:4318" will be used. +func WithEndpoint(endpoint string) Option { + return wrappedOption{oconf.WithEndpoint(endpoint)} +} + +// WithCompression sets the compression strategy the Exporter will use to +// compress the HTTP body. +// +// If the OTEL_EXPORTER_OTLP_COMPRESSION or +// OTEL_EXPORTER_OTLP_METRICS_COMPRESSION environment variable is set, and +// this option is not passed, that variable value will be used. That value can +// be either "none" or "gzip". If both are set, +// OTEL_EXPORTER_OTLP_METRICS_COMPRESSION will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, no compression strategy will be used. +func WithCompression(compression Compression) Option { + return wrappedOption{oconf.WithCompression(oconf.Compression(compression))} +} + +// WithURLPath sets the URL path the Exporter will send requests to. +// +// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// environment variable is set, and this option is not passed, the path +// contained in that variable value will be used. If both are set, +// OTEL_EXPORTER_OTLP_METRICS_ENDPOINT will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, "/v1/metrics" will be used. +func WithURLPath(urlPath string) Option { + return wrappedOption{oconf.WithURLPath(urlPath)} +} + +// WithTLSClientConfig sets the TLS configuration the Exporter will use for +// HTTP requests. +// +// If the OTEL_EXPORTER_OTLP_CERTIFICATE or +// OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE environment variable is set, and +// this option is not passed, that variable value will be used. The value will +// be parsed the filepath of the TLS certificate chain to use. If both are +// set, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, the system default configuration is used. +func WithTLSClientConfig(tlsCfg *tls.Config) Option { + return wrappedOption{oconf.WithTLSClientConfig(tlsCfg)} +} + +// WithInsecure disables client transport security for the Exporter's HTTP +// connection. +// +// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT +// environment variable is set, and this option is not passed, that variable +// value will be used to determine client security. If the endpoint has a +// scheme of "http" or "unix" client security will be disabled. If both are +// set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, client security will be used. +func WithInsecure() Option { + return wrappedOption{oconf.WithInsecure()} +} + +// WithHeaders will send the provided headers with each HTTP requests. +// +// If the OTEL_EXPORTER_OTLP_HEADERS or OTEL_EXPORTER_OTLP_METRICS_HEADERS +// environment variable is set, and this option is not passed, that variable +// value will be used. The value will be parsed as a list of key value pairs. +// These pairs are expected to be in the W3C Correlation-Context format +// without additional semi-colon delimited metadata (i.e. "k1=v1,k2=v2"). If +// both are set, OTEL_EXPORTER_OTLP_METRICS_HEADERS will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, no user headers will be set. +func WithHeaders(headers map[string]string) Option { + return wrappedOption{oconf.WithHeaders(headers)} +} + +// WithTimeout sets the max amount of time an Exporter will attempt an export. +// +// This takes precedence over any retry settings defined by WithRetry. Once +// this time limit has been reached the export is abandoned and the metric +// data is dropped. +// +// If the OTEL_EXPORTER_OTLP_TIMEOUT or OTEL_EXPORTER_OTLP_METRICS_TIMEOUT +// environment variable is set, and this option is not passed, that variable +// value will be used. The value will be parsed as an integer representing the +// timeout in milliseconds. If both are set, +// OTEL_EXPORTER_OTLP_METRICS_TIMEOUT will take precedence. +// +// By default, if an environment variable is not set, and this option is not +// passed, a timeout of 10 seconds will be used. +func WithTimeout(duration time.Duration) Option { + return wrappedOption{oconf.WithTimeout(duration)} +} + +// WithRetry sets the retry policy for transient retryable errors that are +// returned by the target endpoint. +// +// If the target endpoint responds with not only a retryable error, but +// explicitly returns a backoff time in the response, that time will take +// precedence over these settings. +// +// If unset, the default retry policy will be used. It will retry the export +// 5 seconds after receiving a retryable error and increase exponentially +// after each error for no more than a total time of 1 minute. +func WithRetry(rc RetryConfig) Option { + return wrappedOption{oconf.WithRetry(retry.Config(rc))} +} + +// WithTemporalitySelector sets the TemporalitySelector the client will use to +// determine the Temporality of an instrument based on its kind. If this option +// is not used, the client will use the DefaultTemporalitySelector from the +// go.opentelemetry.io/otel/sdk/metric package. +func WithTemporalitySelector(selector metric.TemporalitySelector) Option { + return wrappedOption{oconf.WithTemporalitySelector(selector)} +} + +// WithAggregationSelector sets the AggregationSelector the client will use to +// determine the aggregation to use for an instrument based on its kind. If +// this option is not used, the reader will use the DefaultAggregationSelector +// from the go.opentelemetry.io/otel/sdk/metric package, or the aggregation +// explicitly passed for a view matching an instrument. +func WithAggregationSelector(selector metric.AggregationSelector) Option { + return wrappedOption{oconf.WithAggregationSelector(selector)} +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/doc.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/doc.go new file mode 100644 index 0000000000000..a49e246517110 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package otlpmetrichttp provides an otlpmetric.Exporter that communicates +// with an OTLP receiving endpoint using protobuf encoded metric data over +// HTTP. +package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/exporter.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/exporter.go new file mode 100644 index 0000000000000..96991ede5c7cf --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/exporter.go @@ -0,0 +1,162 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + +import ( + "context" + "fmt" + "sync" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +// Exporter is a OpenTelemetry metric Exporter using protobufs over HTTP. +type Exporter struct { + // Ensure synchronous access to the client across all functionality. + clientMu sync.Mutex + client interface { + UploadMetrics(context.Context, *metricpb.ResourceMetrics) error + Shutdown(context.Context) error + } + + temporalitySelector metric.TemporalitySelector + aggregationSelector metric.AggregationSelector + + shutdownOnce sync.Once +} + +func newExporter(c *client, cfg oconf.Config) (*Exporter, error) { + ts := cfg.Metrics.TemporalitySelector + if ts == nil { + ts = func(metric.InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality + } + } + + as := cfg.Metrics.AggregationSelector + if as == nil { + as = metric.DefaultAggregationSelector + } + + return &Exporter{ + client: c, + + temporalitySelector: ts, + aggregationSelector: as, + }, nil +} + +// Temporality returns the Temporality to use for an instrument kind. +func (e *Exporter) Temporality(k metric.InstrumentKind) metricdata.Temporality { + return e.temporalitySelector(k) +} + +// Aggregation returns the Aggregation to use for an instrument kind. +func (e *Exporter) Aggregation(k metric.InstrumentKind) metric.Aggregation { + return e.aggregationSelector(k) +} + +// Export transforms and transmits metric data to an OTLP receiver. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +func (e *Exporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error { + defer global.Debug("OTLP/HTTP exporter export", "Data", rm) + + otlpRm, err := transform.ResourceMetrics(rm) + // Best effort upload of transformable metrics. + e.clientMu.Lock() + upErr := e.client.UploadMetrics(ctx, otlpRm) + e.clientMu.Unlock() + if upErr != nil { + if err == nil { + return fmt.Errorf("failed to upload metrics: %w", upErr) + } + // Merge the two errors. + return fmt.Errorf("failed to upload incomplete metrics (%s): %w", err, upErr) + } + return err +} + +// ForceFlush flushes any metric data held by an exporter. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +// +// This method is safe to call concurrently. +func (e *Exporter) ForceFlush(ctx context.Context) error { + // The exporter and client hold no state, nothing to flush. + return ctx.Err() +} + +// Shutdown flushes all metric data held by an exporter and releases any held +// computational resources. +// +// This method returns an error if called after Shutdown. +// This method returns an error if the method is canceled by the passed context. +// +// This method is safe to call concurrently. +func (e *Exporter) Shutdown(ctx context.Context) error { + err := errShutdown + e.shutdownOnce.Do(func() { + e.clientMu.Lock() + client := e.client + e.client = shutdownClient{} + e.clientMu.Unlock() + err = client.Shutdown(ctx) + }) + return err +} + +var errShutdown = fmt.Errorf("HTTP exporter is shutdown") + +type shutdownClient struct{} + +func (c shutdownClient) err(ctx context.Context) error { + if err := ctx.Err(); err != nil { + return err + } + return errShutdown +} + +func (c shutdownClient) UploadMetrics(ctx context.Context, _ *metricpb.ResourceMetrics) error { + return c.err(ctx) +} + +func (c shutdownClient) Shutdown(ctx context.Context) error { + return c.err(ctx) +} + +// MarshalLog returns logging data about the Exporter. +func (e *Exporter) MarshalLog() interface{} { + return struct{ Type string }{Type: "OTLP/HTTP"} +} + +// New returns an OpenTelemetry metric Exporter. The Exporter can be used with +// a PeriodicReader to export OpenTelemetry metric data to an OTLP receiving +// endpoint using protobufs over HTTP. +func New(_ context.Context, opts ...Option) (*Exporter, error) { + cfg := oconf.NewHTTPConfig(asHTTPOptions(opts)...) + c, err := newClient(cfg) + if err != nil { + return nil, err + } + return newExporter(c, cfg) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig/envconfig.go new file mode 100644 index 0000000000000..38859fb9342b4 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig/envconfig.go @@ -0,0 +1,202 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/envconfig/envconfig.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package envconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig" + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "go.opentelemetry.io/otel/internal/global" +) + +// ConfigFn is the generic function used to set a config. +type ConfigFn func(*EnvOptionsReader) + +// EnvOptionsReader reads the required environment variables. +type EnvOptionsReader struct { + GetEnv func(string) string + ReadFile func(string) ([]byte, error) + Namespace string +} + +// Apply runs every ConfigFn. +func (e *EnvOptionsReader) Apply(opts ...ConfigFn) { + for _, o := range opts { + o(e) + } +} + +// GetEnvValue gets an OTLP environment variable value of the specified key +// using the GetEnv function. +// This function prepends the OTLP specified namespace to all key lookups. +func (e *EnvOptionsReader) GetEnvValue(key string) (string, bool) { + v := strings.TrimSpace(e.GetEnv(keyWithNamespace(e.Namespace, key))) + return v, v != "" +} + +// WithString retrieves the specified config and passes it to ConfigFn as a string. +func WithString(n string, fn func(string)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + fn(v) + } + } +} + +// WithBool returns a ConfigFn that reads the environment variable n and if it exists passes its parsed bool value to fn. +func WithBool(n string, fn func(bool)) ConfigFn { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + b := strings.ToLower(v) == "true" + fn(b) + } + } +} + +// WithDuration retrieves the specified config and passes it to ConfigFn as a duration. +func WithDuration(n string, fn func(time.Duration)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + d, err := strconv.Atoi(v) + if err != nil { + global.Error(err, "parse duration", "input", v) + return + } + fn(time.Duration(d) * time.Millisecond) + } + } +} + +// WithHeaders retrieves the specified config and passes it to ConfigFn as a map of HTTP headers. +func WithHeaders(n string, fn func(map[string]string)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + fn(stringToHeader(v)) + } + } +} + +// WithURL retrieves the specified config and passes it to ConfigFn as a net/url.URL. +func WithURL(n string, fn func(*url.URL)) func(e *EnvOptionsReader) { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + u, err := url.Parse(v) + if err != nil { + global.Error(err, "parse url", "input", v) + return + } + fn(u) + } + } +} + +// WithCertPool returns a ConfigFn that reads the environment variable n as a filepath to a TLS certificate pool. If it exists, it is parsed as a crypto/x509.CertPool and it is passed to fn. +func WithCertPool(n string, fn func(*x509.CertPool)) ConfigFn { + return func(e *EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + b, err := e.ReadFile(v) + if err != nil { + global.Error(err, "read tls ca cert file", "file", v) + return + } + c, err := createCertPool(b) + if err != nil { + global.Error(err, "create tls cert pool") + return + } + fn(c) + } + } +} + +// WithClientCert returns a ConfigFn that reads the environment variable nc and nk as filepaths to a client certificate and key pair. If they exists, they are parsed as a crypto/tls.Certificate and it is passed to fn. +func WithClientCert(nc, nk string, fn func(tls.Certificate)) ConfigFn { + return func(e *EnvOptionsReader) { + vc, okc := e.GetEnvValue(nc) + vk, okk := e.GetEnvValue(nk) + if !okc || !okk { + return + } + cert, err := e.ReadFile(vc) + if err != nil { + global.Error(err, "read tls client cert", "file", vc) + return + } + key, err := e.ReadFile(vk) + if err != nil { + global.Error(err, "read tls client key", "file", vk) + return + } + crt, err := tls.X509KeyPair(cert, key) + if err != nil { + global.Error(err, "create tls client key pair") + return + } + fn(crt) + } +} + +func keyWithNamespace(ns, key string) string { + if ns == "" { + return key + } + return fmt.Sprintf("%s_%s", ns, key) +} + +func stringToHeader(value string) map[string]string { + headersPairs := strings.Split(value, ",") + headers := make(map[string]string) + + for _, header := range headersPairs { + n, v, found := strings.Cut(header, "=") + if !found { + global.Error(errors.New("missing '="), "parse headers", "input", header) + continue + } + name, err := url.QueryUnescape(n) + if err != nil { + global.Error(err, "escape header key", "key", n) + continue + } + trimmedName := strings.TrimSpace(name) + value, err := url.QueryUnescape(v) + if err != nil { + global.Error(err, "escape header value", "value", v) + continue + } + trimmedValue := strings.TrimSpace(value) + + headers[trimmedName] = trimmedValue + } + + return headers +} + +func createCertPool(certBytes []byte) (*x509.CertPool, error) { + cp := x509.NewCertPool() + if ok := cp.AppendCertsFromPEM(certBytes); !ok { + return nil, errors.New("failed to append certificate to the cert pool") + } + return cp, nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go new file mode 100644 index 0000000000000..002c8b36b2e9b --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/gen.go @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal" + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess.go.tmpl "--data={}" --out=partialsuccess.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/partialsuccess_test.go.tmpl "--data={}" --out=partialsuccess_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry.go.tmpl "--data={}" --out=retry/retry.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/retry/retry_test.go.tmpl "--data={}" --out=retry/retry_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig.go.tmpl "--data={}" --out=envconfig/envconfig.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/envconfig/envconfig_test.go.tmpl "--data={}" --out=envconfig/envconfig_test.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig\"}" --out=oconf/envconfig.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/envconfig_test.go.tmpl "--data={}" --out=oconf/envconfig_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options.go.tmpl "--data={\"retryImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry\"}" --out=oconf/options.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/options_test.go.tmpl "--data={\"envconfigImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig\"}" --out=oconf/options_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl "--data={}" --out=oconf/optiontypes.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl "--data={}" --out=oconf/tls.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/client.go.tmpl "--data={}" --out=otest/client.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/client_test.go.tmpl "--data={\"internalImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal\"}" --out=otest/client_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/otest/collector.go.tmpl "--data={\"oconfImportPath\": \"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf\"}" --out=otest/collector.go + +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/attribute.go.tmpl "--data={}" --out=transform/attribute.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/attribute_test.go.tmpl "--data={}" --out=transform/attribute_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/error.go.tmpl "--data={}" --out=transform/error.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/error_test.go.tmpl "--data={}" --out=transform/error_test.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/metricdata.go.tmpl "--data={}" --out=transform/metricdata.go +//go:generate gotmpl --body=../../../../../internal/shared/otlp/otlpmetric/transform/metricdata_test.go.tmpl "--data={}" --out=transform/metricdata_test.go diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go new file mode 100644 index 0000000000000..2bab35be6c4cf --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go @@ -0,0 +1,221 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + +import ( + "crypto/tls" + "crypto/x509" + "net/url" + "os" + "path" + "strings" + "time" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// DefaultEnvOptionsReader is the default environments reader. +var DefaultEnvOptionsReader = envconfig.EnvOptionsReader{ + GetEnv: os.Getenv, + ReadFile: os.ReadFile, + Namespace: "OTEL_EXPORTER_OTLP", +} + +// ApplyGRPCEnvConfigs applies the env configurations for gRPC. +func ApplyGRPCEnvConfigs(cfg Config) Config { + opts := getOptionsFromEnv() + for _, opt := range opts { + cfg = opt.ApplyGRPCOption(cfg) + } + return cfg +} + +// ApplyHTTPEnvConfigs applies the env configurations for HTTP. +func ApplyHTTPEnvConfigs(cfg Config) Config { + opts := getOptionsFromEnv() + for _, opt := range opts { + cfg = opt.ApplyHTTPOption(cfg) + } + return cfg +} + +func getOptionsFromEnv() []GenericOption { + opts := []GenericOption{} + + tlsConf := &tls.Config{} + DefaultEnvOptionsReader.Apply( + envconfig.WithURL("ENDPOINT", func(u *url.URL) { + opts = append(opts, withEndpointScheme(u)) + opts = append(opts, newSplitOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = u.Host + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Metrics.URLPath = path.Join(u.Path, DefaultMetricsPath) + return cfg + }, withEndpointForGRPC(u))) + }), + envconfig.WithURL("METRICS_ENDPOINT", func(u *url.URL) { + opts = append(opts, withEndpointScheme(u)) + opts = append(opts, newSplitOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = u.Host + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Metrics.URLPath = path + return cfg + }, withEndpointForGRPC(u))) + }), + envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }), + envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }), + envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }), + envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }), + envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }), + envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }), + withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }), + envconfig.WithHeaders("HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }), + envconfig.WithHeaders("METRICS_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }), + WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }), + WithEnvCompression("METRICS_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }), + envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }), + envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }), + withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }), + withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }), + ) + + return opts +} + +func withEndpointForGRPC(u *url.URL) func(cfg Config) Config { + return func(cfg Config) Config { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + return cfg + } +} + +// WithEnvCompression retrieves the specified config and passes it to ConfigFn as a Compression. +func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if v, ok := e.GetEnvValue(n); ok { + cp := NoCompression + if v == "gzip" { + cp = GzipCompression + } + + fn(cp) + } + } +} + +func withEndpointScheme(u *url.URL) GenericOption { + switch strings.ToLower(u.Scheme) { + case "http", "unix": + return WithInsecure() + default: + return WithSecure() + } +} + +// revive:disable-next-line:flag-parameter +func withInsecure(b bool) GenericOption { + if b { + return WithInsecure() + } + return WithSecure() +} + +func withTLSConfig(c *tls.Config, fn func(*tls.Config)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if c.RootCAs != nil || len(c.Certificates) > 0 { + fn(c) + } + } +} + +func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if s, ok := e.GetEnvValue(n); ok { + switch strings.ToLower(s) { + case "cumulative": + fn(cumulativeTemporality) + case "delta": + fn(deltaTemporality) + case "lowmemory": + fn(lowMemory) + default: + global.Warn("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", "value", s) + } + } + } +} + +func cumulativeTemporality(metric.InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality +} + +func deltaTemporality(ik metric.InstrumentKind) metricdata.Temporality { + switch ik { + case metric.InstrumentKindCounter, metric.InstrumentKindHistogram, metric.InstrumentKindObservableCounter: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +func lowMemory(ik metric.InstrumentKind) metricdata.Temporality { + switch ik { + case metric.InstrumentKindCounter, metric.InstrumentKindHistogram: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e *envconfig.EnvOptionsReader) { + return func(e *envconfig.EnvOptionsReader) { + if s, ok := e.GetEnvValue(n); ok { + switch strings.ToLower(s) { + case "explicit_bucket_histogram": + fn(metric.DefaultAggregationSelector) + case "base2_exponential_bucket_histogram": + fn(func(kind metric.InstrumentKind) metric.Aggregation { + if kind == metric.InstrumentKindHistogram { + return metric.AggregationBase2ExponentialHistogram{ + MaxSize: 160, + MaxScale: 20, + NoMinMax: false, + } + } + return metric.DefaultAggregationSelector(kind) + }) + default: + global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s) + } + } + } +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go new file mode 100644 index 0000000000000..c1ec5ed210a29 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go @@ -0,0 +1,359 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/options.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + +import ( + "crypto/tls" + "fmt" + "path" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/encoding/gzip" + + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" + "go.opentelemetry.io/otel/sdk/metric" +) + +const ( + // DefaultMaxAttempts describes how many times the driver + // should retry the sending of the payload in case of a + // retryable error. + DefaultMaxAttempts int = 5 + // DefaultMetricsPath is a default URL path for endpoint that + // receives metrics. + DefaultMetricsPath string = "/v1/metrics" + // DefaultBackoff is a default base backoff time used in the + // exponential backoff strategy. + DefaultBackoff time.Duration = 300 * time.Millisecond + // DefaultTimeout is a default max waiting time for the backend to process + // each span or metrics batch. + DefaultTimeout time.Duration = 10 * time.Second +) + +type ( + SignalConfig struct { + Endpoint string + Insecure bool + TLSCfg *tls.Config + Headers map[string]string + Compression Compression + Timeout time.Duration + URLPath string + + // gRPC configurations + GRPCCredentials credentials.TransportCredentials + + TemporalitySelector metric.TemporalitySelector + AggregationSelector metric.AggregationSelector + } + + Config struct { + // Signal specific configurations + Metrics SignalConfig + + RetryConfig retry.Config + + // gRPC configurations + ReconnectionPeriod time.Duration + ServiceConfig string + DialOptions []grpc.DialOption + GRPCConn *grpc.ClientConn + } +) + +// NewHTTPConfig returns a new Config with all settings applied from opts and +// any unset setting using the default HTTP config values. +func NewHTTPConfig(opts ...HTTPOption) Config { + cfg := Config{ + Metrics: SignalConfig{ + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort), + URLPath: DefaultMetricsPath, + Compression: NoCompression, + Timeout: DefaultTimeout, + + TemporalitySelector: metric.DefaultTemporalitySelector, + AggregationSelector: metric.DefaultAggregationSelector, + }, + RetryConfig: retry.DefaultConfig, + } + cfg = ApplyHTTPEnvConfigs(cfg) + for _, opt := range opts { + cfg = opt.ApplyHTTPOption(cfg) + } + cfg.Metrics.URLPath = cleanPath(cfg.Metrics.URLPath, DefaultMetricsPath) + return cfg +} + +// cleanPath returns a path with all spaces trimmed and all redundancies +// removed. If urlPath is empty or cleaning it results in an empty string, +// defaultPath is returned instead. +func cleanPath(urlPath string, defaultPath string) string { + tmp := path.Clean(strings.TrimSpace(urlPath)) + if tmp == "." { + return defaultPath + } + if !path.IsAbs(tmp) { + tmp = fmt.Sprintf("/%s", tmp) + } + return tmp +} + +// NewGRPCConfig returns a new Config with all settings applied from opts and +// any unset setting using the default gRPC config values. +func NewGRPCConfig(opts ...GRPCOption) Config { + userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() + cfg := Config{ + Metrics: SignalConfig{ + Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort), + URLPath: DefaultMetricsPath, + Compression: NoCompression, + Timeout: DefaultTimeout, + + TemporalitySelector: metric.DefaultTemporalitySelector, + AggregationSelector: metric.DefaultAggregationSelector, + }, + RetryConfig: retry.DefaultConfig, + DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)}, + } + cfg = ApplyGRPCEnvConfigs(cfg) + for _, opt := range opts { + cfg = opt.ApplyGRPCOption(cfg) + } + + if cfg.ServiceConfig != "" { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig)) + } + // Priroritize GRPCCredentials over Insecure (passing both is an error). + if cfg.Metrics.GRPCCredentials != nil { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Metrics.GRPCCredentials)) + } else if cfg.Metrics.Insecure { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) + } else { + // Default to using the host's root CA. + creds := credentials.NewTLS(nil) + cfg.Metrics.GRPCCredentials = creds + cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds)) + } + if cfg.Metrics.Compression == GzipCompression { + cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) + } + if len(cfg.DialOptions) != 0 { + cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...) + } + if cfg.ReconnectionPeriod != 0 { + p := grpc.ConnectParams{ + Backoff: backoff.DefaultConfig, + MinConnectTimeout: cfg.ReconnectionPeriod, + } + cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p)) + } + + return cfg +} + +type ( + // GenericOption applies an option to the HTTP or gRPC driver. + GenericOption interface { + ApplyHTTPOption(Config) Config + ApplyGRPCOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } + + // HTTPOption applies an option to the HTTP driver. + HTTPOption interface { + ApplyHTTPOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } + + // GRPCOption applies an option to the gRPC driver. + GRPCOption interface { + ApplyGRPCOption(Config) Config + + // A private method to prevent users implementing the + // interface and so future additions to it will not + // violate compatibility. + private() + } +) + +// genericOption is an option that applies the same logic +// for both gRPC and HTTP. +type genericOption struct { + fn func(Config) Config +} + +func (g *genericOption) ApplyGRPCOption(cfg Config) Config { + return g.fn(cfg) +} + +func (g *genericOption) ApplyHTTPOption(cfg Config) Config { + return g.fn(cfg) +} + +func (genericOption) private() {} + +func newGenericOption(fn func(cfg Config) Config) GenericOption { + return &genericOption{fn: fn} +} + +// splitOption is an option that applies different logics +// for gRPC and HTTP. +type splitOption struct { + httpFn func(Config) Config + grpcFn func(Config) Config +} + +func (g *splitOption) ApplyGRPCOption(cfg Config) Config { + return g.grpcFn(cfg) +} + +func (g *splitOption) ApplyHTTPOption(cfg Config) Config { + return g.httpFn(cfg) +} + +func (splitOption) private() {} + +func newSplitOption(httpFn func(cfg Config) Config, grpcFn func(cfg Config) Config) GenericOption { + return &splitOption{httpFn: httpFn, grpcFn: grpcFn} +} + +// httpOption is an option that is only applied to the HTTP driver. +type httpOption struct { + fn func(Config) Config +} + +func (h *httpOption) ApplyHTTPOption(cfg Config) Config { + return h.fn(cfg) +} + +func (httpOption) private() {} + +func NewHTTPOption(fn func(cfg Config) Config) HTTPOption { + return &httpOption{fn: fn} +} + +// grpcOption is an option that is only applied to the gRPC driver. +type grpcOption struct { + fn func(Config) Config +} + +func (h *grpcOption) ApplyGRPCOption(cfg Config) Config { + return h.fn(cfg) +} + +func (grpcOption) private() {} + +func NewGRPCOption(fn func(cfg Config) Config) GRPCOption { + return &grpcOption{fn: fn} +} + +// Generic Options + +func WithEndpoint(endpoint string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Endpoint = endpoint + return cfg + }) +} + +func WithCompression(compression Compression) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Compression = compression + return cfg + }) +} + +func WithURLPath(urlPath string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.URLPath = urlPath + return cfg + }) +} + +func WithRetry(rc retry.Config) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.RetryConfig = rc + return cfg + }) +} + +func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption { + return newSplitOption(func(cfg Config) Config { + cfg.Metrics.TLSCfg = tlsCfg.Clone() + return cfg + }, func(cfg Config) Config { + cfg.Metrics.GRPCCredentials = credentials.NewTLS(tlsCfg) + return cfg + }) +} + +func WithInsecure() GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Insecure = true + return cfg + }) +} + +func WithSecure() GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Insecure = false + return cfg + }) +} + +func WithHeaders(headers map[string]string) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Headers = headers + return cfg + }) +} + +func WithTimeout(duration time.Duration) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.Timeout = duration + return cfg + }) +} + +func WithTemporalitySelector(selector metric.TemporalitySelector) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.TemporalitySelector = selector + return cfg + }) +} + +func WithAggregationSelector(selector metric.AggregationSelector) GenericOption { + return newGenericOption(func(cfg Config) Config { + cfg.Metrics.AggregationSelector = selector + return cfg + }) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/optiontypes.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/optiontypes.go new file mode 100644 index 0000000000000..f8805e31d622f --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/optiontypes.go @@ -0,0 +1,58 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/optiontypes.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + +import "time" + +const ( + // DefaultCollectorGRPCPort is the default gRPC port of the collector. + DefaultCollectorGRPCPort uint16 = 4317 + // DefaultCollectorHTTPPort is the default HTTP port of the collector. + DefaultCollectorHTTPPort uint16 = 4318 + // DefaultCollectorHost is the host address the Exporter will attempt + // connect to if no collector address is provided. + DefaultCollectorHost string = "localhost" +) + +// Compression describes the compression used for payloads sent to the +// collector. +type Compression int + +const ( + // NoCompression tells the driver to send payloads without + // compression. + NoCompression Compression = iota + // GzipCompression tells the driver to send payloads after + // compressing them with gzip. + GzipCompression +) + +// RetrySettings defines configuration for retrying batches in case of export failure +// using an exponential backoff. +type RetrySettings struct { + // Enabled indicates whether to not retry sending batches in case of export failure. + Enabled bool + // InitialInterval the time to wait after the first failure before retrying. + InitialInterval time.Duration + // MaxInterval is the upper bound on backoff interval. Once this value is reached the delay between + // consecutive retries will always be `MaxInterval`. + MaxInterval time.Duration + // MaxElapsedTime is the maximum amount of time (including retries) spent trying to send a request/batch. + // Once this value is reached, the data is discarded. + MaxElapsedTime time.Duration +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/tls.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/tls.go new file mode 100644 index 0000000000000..15cbec2585047 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/tls.go @@ -0,0 +1,49 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/oconf/tls.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "os" +) + +// ReadTLSConfigFromFile reads a PEM certificate file and creates +// a tls.Config that will use this certifate to verify a server certificate. +func ReadTLSConfigFromFile(path string) (*tls.Config, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + return CreateTLSConfig(b) +} + +// CreateTLSConfig creates a tls.Config from a raw certificate bytes +// to verify a server certificate. +func CreateTLSConfig(certBytes []byte) (*tls.Config, error) { + cp := x509.NewCertPool() + if ok := cp.AppendCertsFromPEM(certBytes); !ok { + return nil, errors.New("failed to append certificate to the cert pool") + } + + return &tls.Config{ + RootCAs: cp, + }, nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/partialsuccess.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/partialsuccess.go new file mode 100644 index 0000000000000..584785778accb --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/partialsuccess.go @@ -0,0 +1,67 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/partialsuccess.go + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal" + +import "fmt" + +// PartialSuccess represents the underlying error for all handling +// OTLP partial success messages. Use `errors.Is(err, +// PartialSuccess{})` to test whether an error passed to the OTel +// error handler belongs to this category. +type PartialSuccess struct { + ErrorMessage string + RejectedItems int64 + RejectedKind string +} + +var _ error = PartialSuccess{} + +// Error implements the error interface. +func (ps PartialSuccess) Error() string { + msg := ps.ErrorMessage + if msg == "" { + msg = "empty message" + } + return fmt.Sprintf("OTLP partial success: %s (%d %s rejected)", msg, ps.RejectedItems, ps.RejectedKind) +} + +// Is supports the errors.Is() interface. +func (ps PartialSuccess) Is(err error) bool { + _, ok := err.(PartialSuccess) + return ok +} + +// TracePartialSuccessError returns an error describing a partial success +// response for the trace signal. +func TracePartialSuccessError(itemsRejected int64, errorMessage string) error { + return PartialSuccess{ + ErrorMessage: errorMessage, + RejectedItems: itemsRejected, + RejectedKind: "spans", + } +} + +// MetricPartialSuccessError returns an error describing a partial success +// response for the metric signal. +func MetricPartialSuccessError(itemsRejected int64, errorMessage string) error { + return PartialSuccess{ + ErrorMessage: errorMessage, + RejectedItems: itemsRejected, + RejectedKind: "metric data points", + } +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry/retry.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry/retry.go new file mode 100644 index 0000000000000..c8d2a6ddfc772 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry/retry.go @@ -0,0 +1,156 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/retry/retry.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package retry provides request retry functionality that can perform +// configurable exponential backoff for transient errors and honor any +// explicit throttle responses received. +package retry // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" + +import ( + "context" + "fmt" + "time" + + "github.com/cenkalti/backoff/v4" +) + +// DefaultConfig are the recommended defaults to use. +var DefaultConfig = Config{ + Enabled: true, + InitialInterval: 5 * time.Second, + MaxInterval: 30 * time.Second, + MaxElapsedTime: time.Minute, +} + +// Config defines configuration for retrying batches in case of export failure +// using an exponential backoff. +type Config struct { + // Enabled indicates whether to not retry sending batches in case of + // export failure. + Enabled bool + // InitialInterval the time to wait after the first failure before + // retrying. + InitialInterval time.Duration + // MaxInterval is the upper bound on backoff interval. Once this value is + // reached the delay between consecutive retries will always be + // `MaxInterval`. + MaxInterval time.Duration + // MaxElapsedTime is the maximum amount of time (including retries) spent + // trying to send a request/batch. Once this value is reached, the data + // is discarded. + MaxElapsedTime time.Duration +} + +// RequestFunc wraps a request with retry logic. +type RequestFunc func(context.Context, func(context.Context) error) error + +// EvaluateFunc returns if an error is retry-able and if an explicit throttle +// duration should be honored that was included in the error. +// +// The function must return true if the error argument is retry-able, +// otherwise it must return false for the first return parameter. +// +// The function must return a non-zero time.Duration if the error contains +// explicit throttle duration that should be honored, otherwise it must return +// a zero valued time.Duration. +type EvaluateFunc func(error) (bool, time.Duration) + +// RequestFunc returns a RequestFunc using the evaluate function to determine +// if requests can be retried and based on the exponential backoff +// configuration of c. +func (c Config) RequestFunc(evaluate EvaluateFunc) RequestFunc { + if !c.Enabled { + return func(ctx context.Context, fn func(context.Context) error) error { + return fn(ctx) + } + } + + return func(ctx context.Context, fn func(context.Context) error) error { + // Do not use NewExponentialBackOff since it calls Reset and the code here + // must call Reset after changing the InitialInterval (this saves an + // unnecessary call to Now). + b := &backoff.ExponentialBackOff{ + InitialInterval: c.InitialInterval, + RandomizationFactor: backoff.DefaultRandomizationFactor, + Multiplier: backoff.DefaultMultiplier, + MaxInterval: c.MaxInterval, + MaxElapsedTime: c.MaxElapsedTime, + Stop: backoff.Stop, + Clock: backoff.SystemClock, + } + b.Reset() + + for { + err := fn(ctx) + if err == nil { + return nil + } + + retryable, throttle := evaluate(err) + if !retryable { + return err + } + + bOff := b.NextBackOff() + if bOff == backoff.Stop { + return fmt.Errorf("max retry time elapsed: %w", err) + } + + // Wait for the greater of the backoff or throttle delay. + var delay time.Duration + if bOff > throttle { + delay = bOff + } else { + elapsed := b.GetElapsedTime() + if b.MaxElapsedTime != 0 && elapsed+throttle > b.MaxElapsedTime { + return fmt.Errorf("max retry time would elapse: %w", err) + } + delay = throttle + } + + if ctxErr := waitFunc(ctx, delay); ctxErr != nil { + return fmt.Errorf("%w: %s", ctxErr, err) + } + } + } +} + +// Allow override for testing. +var waitFunc = wait + +// wait takes the caller's context, and the amount of time to wait. It will +// return nil if the timer fires before or at the same time as the context's +// deadline. This indicates that the call can be retried. +func wait(ctx context.Context, delay time.Duration) error { + timer := time.NewTimer(delay) + defer timer.Stop() + + select { + case <-ctx.Done(): + // Handle the case where the timer and context deadline end + // simultaneously by prioritizing the timer expiration nil value + // response. + select { + case <-timer.C: + default: + return ctx.Err() + } + case <-timer.C: + } + + return nil +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/attribute.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/attribute.go new file mode 100644 index 0000000000000..7fcc144c1cdb0 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/attribute.go @@ -0,0 +1,155 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/attribute.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform" + +import ( + "go.opentelemetry.io/otel/attribute" + cpb "go.opentelemetry.io/proto/otlp/common/v1" +) + +// AttrIter transforms an attribute iterator into OTLP key-values. +func AttrIter(iter attribute.Iterator) []*cpb.KeyValue { + l := iter.Len() + if l == 0 { + return nil + } + + out := make([]*cpb.KeyValue, 0, l) + for iter.Next() { + out = append(out, KeyValue(iter.Attribute())) + } + return out +} + +// KeyValues transforms a slice of attribute KeyValues into OTLP key-values. +func KeyValues(attrs []attribute.KeyValue) []*cpb.KeyValue { + if len(attrs) == 0 { + return nil + } + + out := make([]*cpb.KeyValue, 0, len(attrs)) + for _, kv := range attrs { + out = append(out, KeyValue(kv)) + } + return out +} + +// KeyValue transforms an attribute KeyValue into an OTLP key-value. +func KeyValue(kv attribute.KeyValue) *cpb.KeyValue { + return &cpb.KeyValue{Key: string(kv.Key), Value: Value(kv.Value)} +} + +// Value transforms an attribute Value into an OTLP AnyValue. +func Value(v attribute.Value) *cpb.AnyValue { + av := new(cpb.AnyValue) + switch v.Type() { + case attribute.BOOL: + av.Value = &cpb.AnyValue_BoolValue{ + BoolValue: v.AsBool(), + } + case attribute.BOOLSLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: boolSliceValues(v.AsBoolSlice()), + }, + } + case attribute.INT64: + av.Value = &cpb.AnyValue_IntValue{ + IntValue: v.AsInt64(), + } + case attribute.INT64SLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: int64SliceValues(v.AsInt64Slice()), + }, + } + case attribute.FLOAT64: + av.Value = &cpb.AnyValue_DoubleValue{ + DoubleValue: v.AsFloat64(), + } + case attribute.FLOAT64SLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: float64SliceValues(v.AsFloat64Slice()), + }, + } + case attribute.STRING: + av.Value = &cpb.AnyValue_StringValue{ + StringValue: v.AsString(), + } + case attribute.STRINGSLICE: + av.Value = &cpb.AnyValue_ArrayValue{ + ArrayValue: &cpb.ArrayValue{ + Values: stringSliceValues(v.AsStringSlice()), + }, + } + default: + av.Value = &cpb.AnyValue_StringValue{ + StringValue: "INVALID", + } + } + return av +} + +func boolSliceValues(vals []bool) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_BoolValue{ + BoolValue: v, + }, + } + } + return converted +} + +func int64SliceValues(vals []int64) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_IntValue{ + IntValue: v, + }, + } + } + return converted +} + +func float64SliceValues(vals []float64) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_DoubleValue{ + DoubleValue: v, + }, + } + } + return converted +} + +func stringSliceValues(vals []string) []*cpb.AnyValue { + converted := make([]*cpb.AnyValue, len(vals)) + for i, v := range vals { + converted[i] = &cpb.AnyValue{ + Value: &cpb.AnyValue_StringValue{ + StringValue: v, + }, + } + } + return converted +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/error.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/error.go new file mode 100644 index 0000000000000..0b5446e4d0772 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/error.go @@ -0,0 +1,114 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/error.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform" + +import ( + "errors" + "fmt" + "strings" + + mpb "go.opentelemetry.io/proto/otlp/metrics/v1" +) + +var ( + errUnknownAggregation = errors.New("unknown aggregation") + errUnknownTemporality = errors.New("unknown temporality") +) + +type errMetric struct { + m *mpb.Metric + err error +} + +func (e errMetric) Unwrap() error { + return e.err +} + +func (e errMetric) Error() string { + format := "invalid metric (name: %q, description: %q, unit: %q): %s" + return fmt.Sprintf(format, e.m.Name, e.m.Description, e.m.Unit, e.err) +} + +func (e errMetric) Is(target error) bool { + return errors.Is(e.err, target) +} + +// multiErr is used by the data-type transform functions to wrap multiple +// errors into a single return value. The error message will show all errors +// as a list and scope them by the datatype name that is returning them. +type multiErr struct { + datatype string + errs []error +} + +// errOrNil returns nil if e contains no errors, otherwise it returns e. +func (e *multiErr) errOrNil() error { + if len(e.errs) == 0 { + return nil + } + return e +} + +// append adds err to e. If err is a multiErr, its errs are flattened into e. +func (e *multiErr) append(err error) { + // Do not use errors.As here, this should only be flattened one layer. If + // there is a *multiErr several steps down the chain, all the errors above + // it will be discarded if errors.As is used instead. + switch other := err.(type) { + case *multiErr: + // Flatten err errors into e. + e.errs = append(e.errs, other.errs...) + default: + e.errs = append(e.errs, err) + } +} + +func (e *multiErr) Error() string { + es := make([]string, len(e.errs)) + for i, err := range e.errs { + es[i] = fmt.Sprintf("* %s", err) + } + + format := "%d errors occurred transforming %s:\n\t%s" + return fmt.Sprintf(format, len(es), e.datatype, strings.Join(es, "\n\t")) +} + +func (e *multiErr) Unwrap() error { + switch len(e.errs) { + case 0: + return nil + case 1: + return e.errs[0] + } + + // Return a multiErr without the leading error. + cp := &multiErr{ + datatype: e.datatype, + errs: make([]error, len(e.errs)-1), + } + copy(cp.errs, e.errs[1:]) + return cp +} + +func (e *multiErr) Is(target error) bool { + if len(e.errs) == 0 { + return false + } + // Check if the first error is target. + return errors.Is(e.errs[0], target) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go new file mode 100644 index 0000000000000..985fcfc6437d0 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform/metricdata.go @@ -0,0 +1,292 @@ +// Code created by gotmpl. DO NOT MODIFY. +// source: internal/shared/otlp/otlpmetric/transform/metricdata.go.tmpl + +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package transform provides transformation functionality from the +// sdk/metric/metricdata data-types into OTLP data-types. +package transform // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform" + +import ( + "fmt" + "time" + + "go.opentelemetry.io/otel/sdk/metric/metricdata" + cpb "go.opentelemetry.io/proto/otlp/common/v1" + mpb "go.opentelemetry.io/proto/otlp/metrics/v1" + rpb "go.opentelemetry.io/proto/otlp/resource/v1" +) + +// ResourceMetrics returns an OTLP ResourceMetrics generated from rm. If rm +// contains invalid ScopeMetrics, an error will be returned along with an OTLP +// ResourceMetrics that contains partial OTLP ScopeMetrics. +func ResourceMetrics(rm *metricdata.ResourceMetrics) (*mpb.ResourceMetrics, error) { + sms, err := ScopeMetrics(rm.ScopeMetrics) + return &mpb.ResourceMetrics{ + Resource: &rpb.Resource{ + Attributes: AttrIter(rm.Resource.Iter()), + }, + ScopeMetrics: sms, + SchemaUrl: rm.Resource.SchemaURL(), + }, err +} + +// ScopeMetrics returns a slice of OTLP ScopeMetrics generated from sms. If +// sms contains invalid metric values, an error will be returned along with a +// slice that contains partial OTLP ScopeMetrics. +func ScopeMetrics(sms []metricdata.ScopeMetrics) ([]*mpb.ScopeMetrics, error) { + errs := &multiErr{datatype: "ScopeMetrics"} + out := make([]*mpb.ScopeMetrics, 0, len(sms)) + for _, sm := range sms { + ms, err := Metrics(sm.Metrics) + if err != nil { + errs.append(err) + } + + out = append(out, &mpb.ScopeMetrics{ + Scope: &cpb.InstrumentationScope{ + Name: sm.Scope.Name, + Version: sm.Scope.Version, + }, + Metrics: ms, + SchemaUrl: sm.Scope.SchemaURL, + }) + } + return out, errs.errOrNil() +} + +// Metrics returns a slice of OTLP Metric generated from ms. If ms contains +// invalid metric values, an error will be returned along with a slice that +// contains partial OTLP Metrics. +func Metrics(ms []metricdata.Metrics) ([]*mpb.Metric, error) { + errs := &multiErr{datatype: "Metrics"} + out := make([]*mpb.Metric, 0, len(ms)) + for _, m := range ms { + o, err := metric(m) + if err != nil { + // Do not include invalid data. Drop the metric, report the error. + errs.append(errMetric{m: o, err: err}) + continue + } + out = append(out, o) + } + return out, errs.errOrNil() +} + +func metric(m metricdata.Metrics) (*mpb.Metric, error) { + var err error + out := &mpb.Metric{ + Name: m.Name, + Description: m.Description, + Unit: string(m.Unit), + } + switch a := m.Data.(type) { + case metricdata.Gauge[int64]: + out.Data = Gauge[int64](a) + case metricdata.Gauge[float64]: + out.Data = Gauge[float64](a) + case metricdata.Sum[int64]: + out.Data, err = Sum[int64](a) + case metricdata.Sum[float64]: + out.Data, err = Sum[float64](a) + case metricdata.Histogram[int64]: + out.Data, err = Histogram(a) + case metricdata.Histogram[float64]: + out.Data, err = Histogram(a) + case metricdata.ExponentialHistogram[int64]: + out.Data, err = ExponentialHistogram(a) + case metricdata.ExponentialHistogram[float64]: + out.Data, err = ExponentialHistogram(a) + default: + return out, fmt.Errorf("%w: %T", errUnknownAggregation, a) + } + return out, err +} + +// Gauge returns an OTLP Metric_Gauge generated from g. +func Gauge[N int64 | float64](g metricdata.Gauge[N]) *mpb.Metric_Gauge { + return &mpb.Metric_Gauge{ + Gauge: &mpb.Gauge{ + DataPoints: DataPoints(g.DataPoints), + }, + } +} + +// Sum returns an OTLP Metric_Sum generated from s. An error is returned +// if the temporality of s is unknown. +func Sum[N int64 | float64](s metricdata.Sum[N]) (*mpb.Metric_Sum, error) { + t, err := Temporality(s.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_Sum{ + Sum: &mpb.Sum{ + AggregationTemporality: t, + IsMonotonic: s.IsMonotonic, + DataPoints: DataPoints(s.DataPoints), + }, + }, nil +} + +// DataPoints returns a slice of OTLP NumberDataPoint generated from dPts. +func DataPoints[N int64 | float64](dPts []metricdata.DataPoint[N]) []*mpb.NumberDataPoint { + out := make([]*mpb.NumberDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + ndp := &mpb.NumberDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + } + switch v := any(dPt.Value).(type) { + case int64: + ndp.Value = &mpb.NumberDataPoint_AsInt{ + AsInt: v, + } + case float64: + ndp.Value = &mpb.NumberDataPoint_AsDouble{ + AsDouble: v, + } + } + out = append(out, ndp) + } + return out +} + +// Histogram returns an OTLP Metric_Histogram generated from h. An error is +// returned if the temporality of h is unknown. +func Histogram[N int64 | float64](h metricdata.Histogram[N]) (*mpb.Metric_Histogram, error) { + t, err := Temporality(h.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_Histogram{ + Histogram: &mpb.Histogram{ + AggregationTemporality: t, + DataPoints: HistogramDataPoints(h.DataPoints), + }, + }, nil +} + +// HistogramDataPoints returns a slice of OTLP HistogramDataPoint generated +// from dPts. +func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint[N]) []*mpb.HistogramDataPoint { + out := make([]*mpb.HistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + hdp := &mpb.HistogramDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + BucketCounts: dPt.BucketCounts, + ExplicitBounds: dPt.Bounds, + } + if v, ok := dPt.Min.Value(); ok { + vF64 := float64(v) + hdp.Min = &vF64 + } + if v, ok := dPt.Max.Value(); ok { + vF64 := float64(v) + hdp.Max = &vF64 + } + out = append(out, hdp) + } + return out +} + +// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is +// returned if the temporality of h is unknown. +func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) { + t, err := Temporality(h.Temporality) + if err != nil { + return nil, err + } + return &mpb.Metric_ExponentialHistogram{ + ExponentialHistogram: &mpb.ExponentialHistogram{ + AggregationTemporality: t, + DataPoints: ExponentialHistogramDataPoints(h.DataPoints), + }, + }, nil +} + +// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated +// from dPts. +func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint { + out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + ehdp := &mpb.ExponentialHistogramDataPoint{ + Attributes: AttrIter(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + Scale: dPt.Scale, + ZeroCount: dPt.ZeroCount, + + Positive: ExponentialHistogramDataPointBuckets(dPt.PositiveBucket), + Negative: ExponentialHistogramDataPointBuckets(dPt.NegativeBucket), + } + if v, ok := dPt.Min.Value(); ok { + vF64 := float64(v) + ehdp.Min = &vF64 + } + if v, ok := dPt.Max.Value(); ok { + vF64 := float64(v) + ehdp.Max = &vF64 + } + out = append(out, ehdp) + } + return out +} + +// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated +// from bucket. +func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets { + return &mpb.ExponentialHistogramDataPoint_Buckets{ + Offset: bucket.Offset, + BucketCounts: bucket.Counts, + } +} + +// Temporality returns an OTLP AggregationTemporality generated from t. If t +// is unknown, an error is returned along with the invalid +// AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED. +func Temporality(t metricdata.Temporality) (mpb.AggregationTemporality, error) { + switch t { + case metricdata.DeltaTemporality: + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, nil + case metricdata.CumulativeTemporality: + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE, nil + default: + err := fmt.Errorf("%w: %s", errUnknownTemporality, t) + return mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED, err + } +} + +// timeUnixNano returns t as a Unix time, the number of nanoseconds elapsed +// since January 1, 1970 UTC as uint64. +// The result is undefined if the Unix time +// in nanoseconds cannot be represented by an int64 +// (a date before the year 1678 or after 2262). +// timeUnixNano on the zero Time returns 0. +// The result does not depend on the location associated with t. +func timeUnixNano(t time.Time) uint64 { + if t.IsZero() { + return 0 + } + return uint64(t.UnixNano()) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/version.go b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/version.go new file mode 100644 index 0000000000000..b4ecccdfb4014 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/version.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" + +// Version is the current release version of the OpenTelemetry OTLP metrics exporter in use. +func Version() string { + return "0.42.0" +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/LICENSE b/vendor/go.opentelemetry.io/otel/exporters/prometheus/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/config.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/config.go new file mode 100644 index 0000000000000..885fd8b8b3906 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/config.go @@ -0,0 +1,153 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus // import "go.opentelemetry.io/otel/exporters/prometheus" + +import ( + "strings" + + "github.com/prometheus/client_golang/prometheus" + + "go.opentelemetry.io/otel/sdk/metric" +) + +// config contains options for the exporter. +type config struct { + registerer prometheus.Registerer + disableTargetInfo bool + withoutUnits bool + withoutCounterSuffixes bool + readerOpts []metric.ManualReaderOption + disableScopeInfo bool + namespace string +} + +// newConfig creates a validated config configured with options. +func newConfig(opts ...Option) config { + cfg := config{} + for _, opt := range opts { + cfg = opt.apply(cfg) + } + + if cfg.registerer == nil { + cfg.registerer = prometheus.DefaultRegisterer + } + + return cfg +} + +// Option sets exporter option values. +type Option interface { + apply(config) config +} + +type optionFunc func(config) config + +func (fn optionFunc) apply(cfg config) config { + return fn(cfg) +} + +// WithRegisterer configures which prometheus Registerer the Exporter will +// register with. If no registerer is used the prometheus DefaultRegisterer is +// used. +func WithRegisterer(reg prometheus.Registerer) Option { + return optionFunc(func(cfg config) config { + cfg.registerer = reg + return cfg + }) +} + +// WithAggregationSelector configure the Aggregation Selector the exporter will +// use. If no AggregationSelector is provided the DefaultAggregationSelector is +// used. +func WithAggregationSelector(agg metric.AggregationSelector) Option { + return optionFunc(func(cfg config) config { + cfg.readerOpts = append(cfg.readerOpts, metric.WithAggregationSelector(agg)) + return cfg + }) +} + +// WithProducer configure the metric Producer the exporter will use as a source +// of external metric data. +func WithProducer(producer metric.Producer) Option { + return optionFunc(func(cfg config) config { + cfg.readerOpts = append(cfg.readerOpts, metric.WithProducer(producer)) + return cfg + }) +} + +// WithoutTargetInfo configures the Exporter to not export the resource target_info metric. +// If not specified, the Exporter will create a target_info metric containing +// the metrics' resource.Resource attributes. +func WithoutTargetInfo() Option { + return optionFunc(func(cfg config) config { + cfg.disableTargetInfo = true + return cfg + }) +} + +// WithoutUnits disables exporter's addition of unit suffixes to metric names, +// and will also prevent unit comments from being added in OpenMetrics once +// unit comments are supported. +// +// By default, metric names include a unit suffix to follow Prometheus naming +// conventions. For example, the counter metric request.duration, with unit +// milliseconds would become request_duration_milliseconds_total. +// With this option set, the name would instead be request_duration_total. +func WithoutUnits() Option { + return optionFunc(func(cfg config) config { + cfg.withoutUnits = true + return cfg + }) +} + +// WithoutUnits disables exporter's addition _total suffixes on counters. +// +// By default, metric names include a _total suffix to follow Prometheus naming +// conventions. For example, the counter metric happy.people would become +// happy_people_total. With this option set, the name would instead be +// happy_people. +func WithoutCounterSuffixes() Option { + return optionFunc(func(cfg config) config { + cfg.withoutCounterSuffixes = true + return cfg + }) +} + +// WithoutScopeInfo configures the Exporter to not export the otel_scope_info metric. +// If not specified, the Exporter will create a otel_scope_info metric containing +// the metrics' Instrumentation Scope, and also add labels about Instrumentation Scope to all metric points. +func WithoutScopeInfo() Option { + return optionFunc(func(cfg config) config { + cfg.disableScopeInfo = true + return cfg + }) +} + +// WithNamespace configures the Exporter to prefix metric with the given namespace. +// Metadata metrics such as target_info and otel_scope_info are not prefixed since these +// have special behavior based on their name. +func WithNamespace(ns string) Option { + return optionFunc(func(cfg config) config { + ns = sanitizeName(ns) + if !strings.HasSuffix(ns, "_") { + // namespace and metric names should be separated with an underscore, + // adds a trailing underscore if there is not one already. + ns = ns + "_" + } + + cfg.namespace = ns + return cfg + }) +} diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/doc.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/doc.go new file mode 100644 index 0000000000000..f212c6146cf98 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package prometheus provides a Prometheus Exporter that converts +// OTLP metrics into the Prometheus exposition format and implements +// prometheus.Collector to provide a handler for these metrics. +package prometheus // import "go.opentelemetry.io/otel/exporters/prometheus" diff --git a/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go b/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go new file mode 100644 index 0000000000000..8973b2028e649 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go @@ -0,0 +1,533 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus // import "go.opentelemetry.io/otel/exporters/prometheus" + +import ( + "context" + "errors" + "fmt" + "sort" + "strings" + "sync" + "unicode" + "unicode/utf8" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/proto" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/resource" +) + +const ( + targetInfoMetricName = "target_info" + targetInfoDescription = "Target metadata" + + scopeInfoMetricName = "otel_scope_info" + scopeInfoDescription = "Instrumentation Scope metadata" +) + +var ( + scopeInfoKeys = [2]string{"otel_scope_name", "otel_scope_version"} + + errScopeInvalid = errors.New("invalid scope") +) + +// Exporter is a Prometheus Exporter that embeds the OTel metric.Reader +// interface for easy instantiation with a MeterProvider. +type Exporter struct { + metric.Reader +} + +// MarshalLog returns logging data about the Exporter. +func (e *Exporter) MarshalLog() interface{} { + const t = "Prometheus exporter" + + if r, ok := e.Reader.(*metric.ManualReader); ok { + under := r.MarshalLog() + if data, ok := under.(struct { + Type string + Registered bool + Shutdown bool + }); ok { + data.Type = t + return data + } + } + + return struct{ Type string }{Type: t} +} + +var _ metric.Reader = &Exporter{} + +// collector is used to implement prometheus.Collector. +type collector struct { + reader metric.Reader + + withoutUnits bool + withoutCounterSuffixes bool + disableScopeInfo bool + namespace string + + mu sync.Mutex // mu protects all members below from the concurrent access. + disableTargetInfo bool + targetInfo prometheus.Metric + scopeInfos map[instrumentation.Scope]prometheus.Metric + scopeInfosInvalid map[instrumentation.Scope]struct{} + metricFamilies map[string]*dto.MetricFamily +} + +// prometheus counters MUST have a _total suffix by default: +// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/compatibility/prometheus_and_openmetrics.md +const counterSuffix = "_total" + +// New returns a Prometheus Exporter. +func New(opts ...Option) (*Exporter, error) { + cfg := newConfig(opts...) + + // this assumes that the default temporality selector will always return cumulative. + // we only support cumulative temporality, so building our own reader enforces this. + // TODO (#3244): Enable some way to configure the reader, but not change temporality. + reader := metric.NewManualReader(cfg.readerOpts...) + + collector := &collector{ + reader: reader, + disableTargetInfo: cfg.disableTargetInfo, + withoutUnits: cfg.withoutUnits, + withoutCounterSuffixes: cfg.withoutCounterSuffixes, + disableScopeInfo: cfg.disableScopeInfo, + scopeInfos: make(map[instrumentation.Scope]prometheus.Metric), + scopeInfosInvalid: make(map[instrumentation.Scope]struct{}), + metricFamilies: make(map[string]*dto.MetricFamily), + namespace: cfg.namespace, + } + + if err := cfg.registerer.Register(collector); err != nil { + return nil, fmt.Errorf("cannot register the collector: %w", err) + } + + e := &Exporter{ + Reader: reader, + } + + return e, nil +} + +// Describe implements prometheus.Collector. +func (c *collector) Describe(ch chan<- *prometheus.Desc) { + // The Opentelemetry SDK doesn't have information on which will exist when the collector + // is registered. By returning nothing we are an "unchecked" collector in Prometheus, + // and assume responsibility for consistency of the metrics produced. + // + // See https://pkg.go.dev/github.com/prometheus/client_golang@v1.13.0/prometheus#hdr-Custom_Collectors_and_constant_Metrics +} + +// Collect implements prometheus.Collector. +// +// This method is safe to call concurrently. +func (c *collector) Collect(ch chan<- prometheus.Metric) { + // TODO (#3047): Use a sync.Pool instead of allocating metrics every Collect. + metrics := metricdata.ResourceMetrics{} + err := c.reader.Collect(context.TODO(), &metrics) + if err != nil { + otel.Handle(err) + if err == metric.ErrReaderNotRegistered { + return + } + } + + global.Debug("Prometheus exporter export", "Data", metrics) + + // Initialize (once) targetInfo and disableTargetInfo. + func() { + c.mu.Lock() + defer c.mu.Unlock() + + if c.targetInfo == nil && !c.disableTargetInfo { + targetInfo, err := createInfoMetric(targetInfoMetricName, targetInfoDescription, metrics.Resource) + if err != nil { + // If the target info metric is invalid, disable sending it. + c.disableTargetInfo = true + otel.Handle(err) + return + } + + c.targetInfo = targetInfo + } + }() + + if !c.disableTargetInfo { + ch <- c.targetInfo + } + + for _, scopeMetrics := range metrics.ScopeMetrics { + var keys, values [2]string + + if !c.disableScopeInfo { + scopeInfo, err := c.scopeInfo(scopeMetrics.Scope) + if err == errScopeInvalid { + // Do not report the same error multiple times. + continue + } + if err != nil { + otel.Handle(err) + continue + } + + ch <- scopeInfo + + keys = scopeInfoKeys + values = [2]string{scopeMetrics.Scope.Name, scopeMetrics.Scope.Version} + } + + for _, m := range scopeMetrics.Metrics { + typ := c.metricType(m) + if typ == nil { + continue + } + name := c.getName(m, typ) + + drop, help := c.validateMetrics(name, m.Description, typ) + if drop { + continue + } + + if help != "" { + m.Description = help + } + + switch v := m.Data.(type) { + case metricdata.Histogram[int64]: + addHistogramMetric(ch, v, m, keys, values, name) + case metricdata.Histogram[float64]: + addHistogramMetric(ch, v, m, keys, values, name) + case metricdata.Sum[int64]: + addSumMetric(ch, v, m, keys, values, name) + case metricdata.Sum[float64]: + addSumMetric(ch, v, m, keys, values, name) + case metricdata.Gauge[int64]: + addGaugeMetric(ch, v, m, keys, values, name) + case metricdata.Gauge[float64]: + addGaugeMetric(ch, v, m, keys, values, name) + } + } + } +} + +func addHistogramMetric[N int64 | float64](ch chan<- prometheus.Metric, histogram metricdata.Histogram[N], m metricdata.Metrics, ks, vs [2]string, name string) { + // TODO(https://github.com/open-telemetry/opentelemetry-go/issues/3163): support exemplars + for _, dp := range histogram.DataPoints { + keys, values := getAttrs(dp.Attributes, ks, vs) + + desc := prometheus.NewDesc(name, m.Description, keys, nil) + buckets := make(map[float64]uint64, len(dp.Bounds)) + + cumulativeCount := uint64(0) + for i, bound := range dp.Bounds { + cumulativeCount += dp.BucketCounts[i] + buckets[bound] = cumulativeCount + } + m, err := prometheus.NewConstHistogram(desc, dp.Count, float64(dp.Sum), buckets, values...) + if err != nil { + otel.Handle(err) + continue + } + ch <- m + } +} + +func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata.Sum[N], m metricdata.Metrics, ks, vs [2]string, name string) { + valueType := prometheus.CounterValue + if !sum.IsMonotonic { + valueType = prometheus.GaugeValue + } + + for _, dp := range sum.DataPoints { + keys, values := getAttrs(dp.Attributes, ks, vs) + + desc := prometheus.NewDesc(name, m.Description, keys, nil) + m, err := prometheus.NewConstMetric(desc, valueType, float64(dp.Value), values...) + if err != nil { + otel.Handle(err) + continue + } + ch <- m + } +} + +func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metricdata.Gauge[N], m metricdata.Metrics, ks, vs [2]string, name string) { + for _, dp := range gauge.DataPoints { + keys, values := getAttrs(dp.Attributes, ks, vs) + + desc := prometheus.NewDesc(name, m.Description, keys, nil) + m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(dp.Value), values...) + if err != nil { + otel.Handle(err) + continue + } + ch <- m + } +} + +// getAttrs parses the attribute.Set to two lists of matching Prometheus-style +// keys and values. It sanitizes invalid characters and handles duplicate keys +// (due to sanitization) by sorting and concatenating the values following the spec. +func getAttrs(attrs attribute.Set, ks, vs [2]string) ([]string, []string) { + keysMap := make(map[string][]string) + itr := attrs.Iter() + for itr.Next() { + kv := itr.Attribute() + key := strings.Map(sanitizeRune, string(kv.Key)) + if _, ok := keysMap[key]; !ok { + keysMap[key] = []string{kv.Value.Emit()} + } else { + // if the sanitized key is a duplicate, append to the list of keys + keysMap[key] = append(keysMap[key], kv.Value.Emit()) + } + } + + keys := make([]string, 0, attrs.Len()) + values := make([]string, 0, attrs.Len()) + for key, vals := range keysMap { + keys = append(keys, key) + sort.Slice(vals, func(i, j int) bool { + return i < j + }) + values = append(values, strings.Join(vals, ";")) + } + + if ks[0] != "" { + keys = append(keys, ks[:]...) + values = append(values, vs[:]...) + } + return keys, values +} + +func createInfoMetric(name, description string, res *resource.Resource) (prometheus.Metric, error) { + keys, values := getAttrs(*res.Set(), [2]string{}, [2]string{}) + desc := prometheus.NewDesc(name, description, keys, nil) + return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), values...) +} + +func createScopeInfoMetric(scope instrumentation.Scope) (prometheus.Metric, error) { + keys := scopeInfoKeys[:] + desc := prometheus.NewDesc(scopeInfoMetricName, scopeInfoDescription, keys, nil) + return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), scope.Name, scope.Version) +} + +func sanitizeRune(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) || r == ':' || r == '_' { + return r + } + return '_' +} + +var unitSuffixes = map[string]string{ + // Time + "d": "_days", + "h": "_hours", + "min": "_minutes", + "s": "_seconds", + "ms": "_milliseconds", + "us": "_microseconds", + "ns": "_nanoseconds", + + // Bytes + "By": "_bytes", + "KiBy": "_kibibytes", + "MiBy": "_mebibytes", + "GiBy": "_gibibytes", + "TiBy": "_tibibytes", + "KBy": "_kilobytes", + "MBy": "_megabytes", + "GBy": "_gigabytes", + "TBy": "_terabytes", + + // SI + "m": "_meters", + "V": "_volts", + "A": "_amperes", + "J": "_joules", + "W": "_watts", + "g": "_grams", + + // Misc + "Cel": "_celsius", + "Hz": "_hertz", + "1": "_ratio", + "%": "_percent", +} + +// getName returns the sanitized name, prefixed with the namespace and suffixed with unit. +func (c *collector) getName(m metricdata.Metrics, typ *dto.MetricType) string { + name := sanitizeName(m.Name) + addCounterSuffix := !c.withoutCounterSuffixes && *typ == dto.MetricType_COUNTER + if addCounterSuffix { + // Remove the _total suffix here, as we will re-add the total suffix + // later, and it needs to come after the unit suffix. + name = strings.TrimSuffix(name, counterSuffix) + } + if c.namespace != "" { + name = c.namespace + name + } + if suffix, ok := unitSuffixes[m.Unit]; ok && !c.withoutUnits && !strings.HasSuffix(name, suffix) { + name += suffix + } + if addCounterSuffix { + name += counterSuffix + } + return name +} + +func sanitizeName(n string) string { + // This algorithm is based on strings.Map from Go 1.19. + const replacement = '_' + + valid := func(i int, r rune) bool { + // Taken from + // https://github.com/prometheus/common/blob/dfbc25bd00225c70aca0d94c3c4bb7744f28ace0/model/metric.go#L92-L102 + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '_' || r == ':' || (r >= '0' && r <= '9' && i > 0) { + return true + } + return false + } + + // This output buffer b is initialized on demand, the first time a + // character needs to be replaced. + var b strings.Builder + for i, c := range n { + if valid(i, c) { + continue + } + + if i == 0 && c >= '0' && c <= '9' { + // Prefix leading number with replacement character. + b.Grow(len(n) + 1) + _ = b.WriteByte(byte(replacement)) + break + } + b.Grow(len(n)) + _, _ = b.WriteString(n[:i]) + _ = b.WriteByte(byte(replacement)) + width := utf8.RuneLen(c) + n = n[i+width:] + break + } + + // Fast path for unchanged input. + if b.Cap() == 0 { // b.Grow was not called above. + return n + } + + for _, c := range n { + // Due to inlining, it is more performant to invoke WriteByte rather then + // WriteRune. + if valid(1, c) { // We are guaranteed to not be at the start. + _ = b.WriteByte(byte(c)) + } else { + _ = b.WriteByte(byte(replacement)) + } + } + + return b.String() +} + +func (c *collector) metricType(m metricdata.Metrics) *dto.MetricType { + switch v := m.Data.(type) { + case metricdata.Histogram[int64], metricdata.Histogram[float64]: + return dto.MetricType_HISTOGRAM.Enum() + case metricdata.Sum[float64]: + if v.IsMonotonic { + return dto.MetricType_COUNTER.Enum() + } + return dto.MetricType_GAUGE.Enum() + case metricdata.Sum[int64]: + if v.IsMonotonic { + return dto.MetricType_COUNTER.Enum() + } + return dto.MetricType_GAUGE.Enum() + case metricdata.Gauge[int64], metricdata.Gauge[float64]: + return dto.MetricType_GAUGE.Enum() + } + return nil +} + +func (c *collector) scopeInfo(scope instrumentation.Scope) (prometheus.Metric, error) { + c.mu.Lock() + defer c.mu.Unlock() + + scopeInfo, ok := c.scopeInfos[scope] + if ok { + return scopeInfo, nil + } + + if _, ok := c.scopeInfosInvalid[scope]; ok { + return nil, errScopeInvalid + } + + scopeInfo, err := createScopeInfoMetric(scope) + if err != nil { + c.scopeInfosInvalid[scope] = struct{}{} + return nil, fmt.Errorf("cannot create scope info metric: %w", err) + } + + c.scopeInfos[scope] = scopeInfo + + return scopeInfo, nil +} + +func (c *collector) validateMetrics(name, description string, metricType *dto.MetricType) (drop bool, help string) { + c.mu.Lock() + defer c.mu.Unlock() + + emf, exist := c.metricFamilies[name] + + if !exist { + c.metricFamilies[name] = &dto.MetricFamily{ + Name: proto.String(name), + Help: proto.String(description), + Type: metricType, + } + return false, "" + } + + if emf.GetType() != *metricType { + global.Error( + errors.New("instrument type conflict"), + "Using existing type definition.", + "instrument", name, + "existing", emf.GetType(), + "dropped", *metricType, + ) + return true, "" + } + if emf.GetHelp() != description { + global.Info( + "Instrument description conflict, using existing", + "instrument", name, + "existing", emf.GetHelp(), + "dropped", description, + ) + return false, emf.GetHelp() + } + + return false, "" +} diff --git a/vendor/go.opentelemetry.io/otel/metric/noop/noop.go b/vendor/go.opentelemetry.io/otel/metric/noop/noop.go new file mode 100644 index 0000000000000..acc9a670b2209 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/metric/noop/noop.go @@ -0,0 +1,264 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package noop provides an implementation of the OpenTelemetry metric API that +// produces no telemetry and minimizes used computation resources. +// +// Using this package to implement the OpenTelemetry metric API will +// effectively disable OpenTelemetry. +// +// This implementation can be embedded in other implementations of the +// OpenTelemetry metric API. Doing so will mean the implementation defaults to +// no operation for methods it does not implement. +package noop // import "go.opentelemetry.io/otel/metric/noop" + +import ( + "context" + + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" +) + +var ( + // Compile-time check this implements the OpenTelemetry API. + + _ metric.MeterProvider = MeterProvider{} + _ metric.Meter = Meter{} + _ metric.Observer = Observer{} + _ metric.Registration = Registration{} + _ metric.Int64Counter = Int64Counter{} + _ metric.Float64Counter = Float64Counter{} + _ metric.Int64UpDownCounter = Int64UpDownCounter{} + _ metric.Float64UpDownCounter = Float64UpDownCounter{} + _ metric.Int64Histogram = Int64Histogram{} + _ metric.Float64Histogram = Float64Histogram{} + _ metric.Int64ObservableCounter = Int64ObservableCounter{} + _ metric.Float64ObservableCounter = Float64ObservableCounter{} + _ metric.Int64ObservableGauge = Int64ObservableGauge{} + _ metric.Float64ObservableGauge = Float64ObservableGauge{} + _ metric.Int64ObservableUpDownCounter = Int64ObservableUpDownCounter{} + _ metric.Float64ObservableUpDownCounter = Float64ObservableUpDownCounter{} + _ metric.Int64Observer = Int64Observer{} + _ metric.Float64Observer = Float64Observer{} +) + +// MeterProvider is an OpenTelemetry No-Op MeterProvider. +type MeterProvider struct{ embedded.MeterProvider } + +// NewMeterProvider returns a MeterProvider that does not record any telemetry. +func NewMeterProvider() MeterProvider { + return MeterProvider{} +} + +// Meter returns an OpenTelemetry Meter that does not record any telemetry. +func (MeterProvider) Meter(string, ...metric.MeterOption) metric.Meter { + return Meter{} +} + +// Meter is an OpenTelemetry No-Op Meter. +type Meter struct{ embedded.Meter } + +// Int64Counter returns a Counter used to record int64 measurements that +// produces no telemetry. +func (Meter) Int64Counter(string, ...metric.Int64CounterOption) (metric.Int64Counter, error) { + return Int64Counter{}, nil +} + +// Int64UpDownCounter returns an UpDownCounter used to record int64 +// measurements that produces no telemetry. +func (Meter) Int64UpDownCounter(string, ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) { + return Int64UpDownCounter{}, nil +} + +// Int64Histogram returns a Histogram used to record int64 measurements that +// produces no telemetry. +func (Meter) Int64Histogram(string, ...metric.Int64HistogramOption) (metric.Int64Histogram, error) { + return Int64Histogram{}, nil +} + +// Int64ObservableCounter returns an ObservableCounter used to record int64 +// measurements that produces no telemetry. +func (Meter) Int64ObservableCounter(string, ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) { + return Int64ObservableCounter{}, nil +} + +// Int64ObservableUpDownCounter returns an ObservableUpDownCounter used to +// record int64 measurements that produces no telemetry. +func (Meter) Int64ObservableUpDownCounter(string, ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) { + return Int64ObservableUpDownCounter{}, nil +} + +// Int64ObservableGauge returns an ObservableGauge used to record int64 +// measurements that produces no telemetry. +func (Meter) Int64ObservableGauge(string, ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) { + return Int64ObservableGauge{}, nil +} + +// Float64Counter returns a Counter used to record int64 measurements that +// produces no telemetry. +func (Meter) Float64Counter(string, ...metric.Float64CounterOption) (metric.Float64Counter, error) { + return Float64Counter{}, nil +} + +// Float64UpDownCounter returns an UpDownCounter used to record int64 +// measurements that produces no telemetry. +func (Meter) Float64UpDownCounter(string, ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) { + return Float64UpDownCounter{}, nil +} + +// Float64Histogram returns a Histogram used to record int64 measurements that +// produces no telemetry. +func (Meter) Float64Histogram(string, ...metric.Float64HistogramOption) (metric.Float64Histogram, error) { + return Float64Histogram{}, nil +} + +// Float64ObservableCounter returns an ObservableCounter used to record int64 +// measurements that produces no telemetry. +func (Meter) Float64ObservableCounter(string, ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) { + return Float64ObservableCounter{}, nil +} + +// Float64ObservableUpDownCounter returns an ObservableUpDownCounter used to +// record int64 measurements that produces no telemetry. +func (Meter) Float64ObservableUpDownCounter(string, ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) { + return Float64ObservableUpDownCounter{}, nil +} + +// Float64ObservableGauge returns an ObservableGauge used to record int64 +// measurements that produces no telemetry. +func (Meter) Float64ObservableGauge(string, ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) { + return Float64ObservableGauge{}, nil +} + +// RegisterCallback performs no operation. +func (Meter) RegisterCallback(metric.Callback, ...metric.Observable) (metric.Registration, error) { + return Registration{}, nil +} + +// Observer acts as a recorder of measurements for multiple instruments in a +// Callback, it performing no operation. +type Observer struct{ embedded.Observer } + +// ObserveFloat64 performs no operation. +func (Observer) ObserveFloat64(metric.Float64Observable, float64, ...metric.ObserveOption) { +} + +// ObserveInt64 performs no operation. +func (Observer) ObserveInt64(metric.Int64Observable, int64, ...metric.ObserveOption) { +} + +// Registration is the registration of a Callback with a No-Op Meter. +type Registration struct{ embedded.Registration } + +// Unregister unregisters the Callback the Registration represents with the +// No-Op Meter. This will always return nil because the No-Op Meter performs no +// operation, including hold any record of registrations. +func (Registration) Unregister() error { return nil } + +// Int64Counter is an OpenTelemetry Counter used to record int64 measurements. +// It produces no telemetry. +type Int64Counter struct{ embedded.Int64Counter } + +// Add performs no operation. +func (Int64Counter) Add(context.Context, int64, ...metric.AddOption) {} + +// Float64Counter is an OpenTelemetry Counter used to record float64 +// measurements. It produces no telemetry. +type Float64Counter struct{ embedded.Float64Counter } + +// Add performs no operation. +func (Float64Counter) Add(context.Context, float64, ...metric.AddOption) {} + +// Int64UpDownCounter is an OpenTelemetry UpDownCounter used to record int64 +// measurements. It produces no telemetry. +type Int64UpDownCounter struct{ embedded.Int64UpDownCounter } + +// Add performs no operation. +func (Int64UpDownCounter) Add(context.Context, int64, ...metric.AddOption) {} + +// Float64UpDownCounter is an OpenTelemetry UpDownCounter used to record +// float64 measurements. It produces no telemetry. +type Float64UpDownCounter struct{ embedded.Float64UpDownCounter } + +// Add performs no operation. +func (Float64UpDownCounter) Add(context.Context, float64, ...metric.AddOption) {} + +// Int64Histogram is an OpenTelemetry Histogram used to record int64 +// measurements. It produces no telemetry. +type Int64Histogram struct{ embedded.Int64Histogram } + +// Record performs no operation. +func (Int64Histogram) Record(context.Context, int64, ...metric.RecordOption) {} + +// Float64Histogram is an OpenTelemetry Histogram used to record float64 +// measurements. It produces no telemetry. +type Float64Histogram struct{ embedded.Float64Histogram } + +// Record performs no operation. +func (Float64Histogram) Record(context.Context, float64, ...metric.RecordOption) {} + +// Int64ObservableCounter is an OpenTelemetry ObservableCounter used to record +// int64 measurements. It produces no telemetry. +type Int64ObservableCounter struct { + metric.Int64Observable + embedded.Int64ObservableCounter +} + +// Float64ObservableCounter is an OpenTelemetry ObservableCounter used to record +// float64 measurements. It produces no telemetry. +type Float64ObservableCounter struct { + metric.Float64Observable + embedded.Float64ObservableCounter +} + +// Int64ObservableGauge is an OpenTelemetry ObservableGauge used to record +// int64 measurements. It produces no telemetry. +type Int64ObservableGauge struct { + metric.Int64Observable + embedded.Int64ObservableGauge +} + +// Float64ObservableGauge is an OpenTelemetry ObservableGauge used to record +// float64 measurements. It produces no telemetry. +type Float64ObservableGauge struct { + metric.Float64Observable + embedded.Float64ObservableGauge +} + +// Int64ObservableUpDownCounter is an OpenTelemetry ObservableUpDownCounter +// used to record int64 measurements. It produces no telemetry. +type Int64ObservableUpDownCounter struct { + metric.Int64Observable + embedded.Int64ObservableUpDownCounter +} + +// Float64ObservableUpDownCounter is an OpenTelemetry ObservableUpDownCounter +// used to record float64 measurements. It produces no telemetry. +type Float64ObservableUpDownCounter struct { + metric.Float64Observable + embedded.Float64ObservableUpDownCounter +} + +// Int64Observer is a recorder of int64 measurements that performs no operation. +type Int64Observer struct{ embedded.Int64Observer } + +// Observe performs no operation. +func (Int64Observer) Observe(int64, ...metric.ObserveOption) {} + +// Float64Observer is a recorder of float64 measurements that performs no +// operation. +type Float64Observer struct{ embedded.Float64Observer } + +// Observe performs no operation. +func (Float64Observer) Observe(float64, ...metric.ObserveOption) {} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE b/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go b/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go new file mode 100644 index 0000000000000..faddbb0b61b19 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/aggregation.go @@ -0,0 +1,201 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "errors" + "fmt" +) + +// errAgg is wrapped by misconfigured aggregations. +var errAgg = errors.New("aggregation") + +// Aggregation is the aggregation used to summarize recorded measurements. +type Aggregation interface { + // copy returns a deep copy of the Aggregation. + copy() Aggregation + + // err returns an error for any misconfigured Aggregation. + err() error +} + +// AggregationDrop is an Aggregation that drops all recorded data. +type AggregationDrop struct{} // AggregationDrop has no parameters. + +var _ Aggregation = AggregationDrop{} + +// copy returns a deep copy of d. +func (d AggregationDrop) copy() Aggregation { return d } + +// err returns an error for any misconfiguration. A drop aggregation has no +// parameters and cannot be misconfigured, therefore this always returns nil. +func (AggregationDrop) err() error { return nil } + +// AggregationDefault is an Aggregation that uses the default instrument kind selection +// mapping to select another Aggregation. A metric reader can be configured to +// make an aggregation selection based on instrument kind that differs from +// the default. This Aggregation ensures the default is used. +// +// See the [DefaultAggregationSelector] for information about the default +// instrument kind selection mapping. +type AggregationDefault struct{} // AggregationDefault has no parameters. + +var _ Aggregation = AggregationDefault{} + +// copy returns a deep copy of d. +func (d AggregationDefault) copy() Aggregation { return d } + +// err returns an error for any misconfiguration. A default aggregation has no +// parameters and cannot be misconfigured, therefore this always returns nil. +func (AggregationDefault) err() error { return nil } + +// AggregationSum is an Aggregation that summarizes a set of measurements as their +// arithmetic sum. +type AggregationSum struct{} // AggregationSum has no parameters. + +var _ Aggregation = AggregationSum{} + +// copy returns a deep copy of s. +func (s AggregationSum) copy() Aggregation { return s } + +// err returns an error for any misconfiguration. A sum aggregation has no +// parameters and cannot be misconfigured, therefore this always returns nil. +func (AggregationSum) err() error { return nil } + +// AggregationLastValue is an Aggregation that summarizes a set of measurements as the +// last one made. +type AggregationLastValue struct{} // AggregationLastValue has no parameters. + +var _ Aggregation = AggregationLastValue{} + +// copy returns a deep copy of l. +func (l AggregationLastValue) copy() Aggregation { return l } + +// err returns an error for any misconfiguration. A last-value aggregation has +// no parameters and cannot be misconfigured, therefore this always returns +// nil. +func (AggregationLastValue) err() error { return nil } + +// AggregationExplicitBucketHistogram is an Aggregation that summarizes a set of +// measurements as an histogram with explicitly defined buckets. +type AggregationExplicitBucketHistogram struct { + // Boundaries are the increasing bucket boundary values. Boundary values + // define bucket upper bounds. Buckets are exclusive of their lower + // boundary and inclusive of their upper bound (except at positive + // infinity). A measurement is defined to fall into the greatest-numbered + // bucket with a boundary that is greater than or equal to the + // measurement. As an example, boundaries defined as: + // + // []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 1000} + // + // Will define these buckets: + // + // (-∞, 0], (0, 5.0], (5.0, 10.0], (10.0, 25.0], (25.0, 50.0], + // (50.0, 75.0], (75.0, 100.0], (100.0, 250.0], (250.0, 500.0], + // (500.0, 1000.0], (1000.0, +∞) + Boundaries []float64 + // NoMinMax indicates whether to not record the min and max of the + // distribution. By default, these extrema are recorded. + // + // Recording these extrema for cumulative data is expected to have little + // value, they will represent the entire life of the instrument instead of + // just the current collection cycle. It is recommended to set this to true + // for that type of data to avoid computing the low-value extrema. + NoMinMax bool +} + +var _ Aggregation = AggregationExplicitBucketHistogram{} + +// errHist is returned by misconfigured ExplicitBucketHistograms. +var errHist = fmt.Errorf("%w: explicit bucket histogram", errAgg) + +// err returns an error for any misconfiguration. +func (h AggregationExplicitBucketHistogram) err() error { + if len(h.Boundaries) <= 1 { + return nil + } + + // Check boundaries are monotonic. + i := h.Boundaries[0] + for _, j := range h.Boundaries[1:] { + if i >= j { + return fmt.Errorf("%w: non-monotonic boundaries: %v", errHist, h.Boundaries) + } + i = j + } + + return nil +} + +// copy returns a deep copy of h. +func (h AggregationExplicitBucketHistogram) copy() Aggregation { + b := make([]float64, len(h.Boundaries)) + copy(b, h.Boundaries) + return AggregationExplicitBucketHistogram{ + Boundaries: b, + NoMinMax: h.NoMinMax, + } +} + +// AggregationBase2ExponentialHistogram is an Aggregation that summarizes a set of +// measurements as an histogram with bucket widths that grow exponentially. +type AggregationBase2ExponentialHistogram struct { + // MaxSize is the maximum number of buckets to use for the histogram. + MaxSize int32 + // MaxScale is the maximum resolution scale to use for the histogram. + // + // MaxScale has a maximum value of 20. Using a value of 20 means the + // maximum number of buckets that can fit within the range of a + // signed 32-bit integer index could be used. + // + // MaxScale has a minimum value of -10. Using a value of -10 means only + // two buckets will be used. + MaxScale int32 + + // NoMinMax indicates whether to not record the min and max of the + // distribution. By default, these extrema are recorded. + // + // Recording these extrema for cumulative data is expected to have little + // value, they will represent the entire life of the instrument instead of + // just the current collection cycle. It is recommended to set this to true + // for that type of data to avoid computing the low-value extrema. + NoMinMax bool +} + +var _ Aggregation = AggregationBase2ExponentialHistogram{} + +// copy returns a deep copy of the Aggregation. +func (e AggregationBase2ExponentialHistogram) copy() Aggregation { + return e +} + +const ( + expoMaxScale = 20 + expoMinScale = -10 +) + +// errExpoHist is returned by misconfigured Base2ExponentialBucketHistograms. +var errExpoHist = fmt.Errorf("%w: exponential histogram", errAgg) + +// err returns an error for any misconfigured Aggregation. +func (e AggregationBase2ExponentialHistogram) err() error { + if e.MaxScale > expoMaxScale { + return fmt.Errorf("%w: max size %d is greater than maximum scale %d", errExpoHist, e.MaxSize, expoMaxScale) + } + if e.MaxSize <= 0 { + return fmt.Errorf("%w: max size %d is less than or equal to zero", errExpoHist, e.MaxSize) + } + return nil +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/cache.go b/vendor/go.opentelemetry.io/otel/sdk/metric/cache.go new file mode 100644 index 0000000000000..de9d6f0019d2d --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/cache.go @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "sync" +) + +// cache is a locking storage used to quickly return already computed values. +// +// The zero value of a cache is empty and ready to use. +// +// A cache must not be copied after first use. +// +// All methods of a cache are safe to call concurrently. +type cache[K comparable, V any] struct { + sync.Mutex + data map[K]V +} + +// Lookup returns the value stored in the cache with the associated key if it +// exists. Otherwise, f is called and its returned value is set in the cache +// for key and returned. +// +// Lookup is safe to call concurrently. It will hold the cache lock, so f +// should not block excessively. +func (c *cache[K, V]) Lookup(key K, f func() V) V { + c.Lock() + defer c.Unlock() + + if c.data == nil { + val := f() + c.data = map[K]V{key: val} + return val + } + if v, ok := c.data[key]; ok { + return v + } + val := f() + c.data[key] = val + return val +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/config.go b/vendor/go.opentelemetry.io/otel/sdk/metric/config.go new file mode 100644 index 0000000000000..0b19112849423 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/config.go @@ -0,0 +1,148 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "fmt" + "sync" + + "go.opentelemetry.io/otel/sdk/resource" +) + +// config contains configuration options for a MeterProvider. +type config struct { + res *resource.Resource + readers []Reader + views []View +} + +// readerSignals returns a force-flush and shutdown function for a +// MeterProvider to call in their respective options. All Readers c contains +// will have their force-flush and shutdown methods unified into returned +// single functions. +func (c config) readerSignals() (forceFlush, shutdown func(context.Context) error) { + var fFuncs, sFuncs []func(context.Context) error + for _, r := range c.readers { + sFuncs = append(sFuncs, r.Shutdown) + if f, ok := r.(interface{ ForceFlush(context.Context) error }); ok { + fFuncs = append(fFuncs, f.ForceFlush) + } + } + + return unify(fFuncs), unifyShutdown(sFuncs) +} + +// unify unifies calling all of funcs into a single function call. All errors +// returned from calls to funcs will be unify into a single error return +// value. +func unify(funcs []func(context.Context) error) func(context.Context) error { + return func(ctx context.Context) error { + var errs []error + for _, f := range funcs { + if err := f(ctx); err != nil { + errs = append(errs, err) + } + } + return unifyErrors(errs) + } +} + +// unifyErrors combines multiple errors into a single error. +func unifyErrors(errs []error) error { + switch len(errs) { + case 0: + return nil + case 1: + return errs[0] + default: + return fmt.Errorf("%v", errs) + } +} + +// unifyShutdown unifies calling all of funcs once for a shutdown. If called +// more than once, an ErrReaderShutdown error is returned. +func unifyShutdown(funcs []func(context.Context) error) func(context.Context) error { + f := unify(funcs) + var once sync.Once + return func(ctx context.Context) error { + err := ErrReaderShutdown + once.Do(func() { err = f(ctx) }) + return err + } +} + +// newConfig returns a config configured with options. +func newConfig(options []Option) config { + conf := config{res: resource.Default()} + for _, o := range options { + conf = o.apply(conf) + } + return conf +} + +// Option applies a configuration option value to a MeterProvider. +type Option interface { + apply(config) config +} + +// optionFunc applies a set of options to a config. +type optionFunc func(config) config + +// apply returns a config with option(s) applied. +func (o optionFunc) apply(conf config) config { + return o(conf) +} + +// WithResource associates a Resource with a MeterProvider. This Resource +// represents the entity producing telemetry and is associated with all Meters +// the MeterProvider will create. +// +// By default, if this Option is not used, the default Resource from the +// go.opentelemetry.io/otel/sdk/resource package will be used. +func WithResource(res *resource.Resource) Option { + return optionFunc(func(conf config) config { + conf.res = res + return conf + }) +} + +// WithReader associates Reader r with a MeterProvider. +// +// By default, if this option is not used, the MeterProvider will perform no +// operations; no data will be exported without a Reader. +func WithReader(r Reader) Option { + return optionFunc(func(cfg config) config { + if r == nil { + return cfg + } + cfg.readers = append(cfg.readers, r) + return cfg + }) +} + +// WithView associates views a MeterProvider. +// +// Views are appended to existing ones in a MeterProvider if this option is +// used multiple times. +// +// By default, if this option is not used, the MeterProvider will use the +// default view. +func WithView(views ...View) Option { + return optionFunc(func(cfg config) config { + cfg.views = append(cfg.views, views...) + return cfg + }) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go b/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go new file mode 100644 index 0000000000000..53f80c42893d8 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/doc.go @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package metric provides an implementation of the OpenTelemetry metrics SDK. +// +// See https://opentelemetry.io/docs/concepts/signals/metrics/ for information +// about the concept of OpenTelemetry metrics and +// https://opentelemetry.io/docs/concepts/components/ for more information +// about OpenTelemetry SDKs. +// +// The entry point for the metric package is the MeterProvider. It is the +// object that all API calls use to create Meters, instruments, and ultimately +// make metric measurements. Also, it is an object that should be used to +// control the life-cycle (start, flush, and shutdown) of the SDK. +// +// A MeterProvider needs to be configured to export the measured data, this is +// done by configuring it with a Reader implementation (using the WithReader +// MeterProviderOption). Readers take two forms: ones that push to an endpoint +// (NewPeriodicReader), and ones that an endpoint pulls from. See +// [go.opentelemetry.io/otel/exporters] for exporters that can be used as +// or with these Readers. +// +// Each Reader, when registered with the MeterProvider, can be augmented with a +// View. Views allow users that run OpenTelemetry instrumented code to modify +// the generated data of that instrumentation. +// +// The data generated by a MeterProvider needs to include information about its +// origin. A MeterProvider needs to be configured with a Resource, using the +// WithResource MeterProviderOption, to include this information. This Resource +// should be used to describe the unique runtime environment instrumented code +// is being run on. That way when multiple instances of the code are collected +// at a single endpoint their origin is decipherable. +// +// See [go.opentelemetry.io/otel/metric] for more information about +// the metric API. +package metric // import "go.opentelemetry.io/otel/sdk/metric" diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/env.go b/vendor/go.opentelemetry.io/otel/sdk/metric/env.go new file mode 100644 index 0000000000000..940ba8159428e --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/env.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "os" + "strconv" + "time" + + "go.opentelemetry.io/otel/internal/global" +) + +// Environment variable names. +const ( + // The time interval (in milliseconds) between the start of two export attempts. + envInterval = "OTEL_METRIC_EXPORT_INTERVAL" + // Maximum allowed time (in milliseconds) to export data. + envTimeout = "OTEL_METRIC_EXPORT_TIMEOUT" +) + +// envDuration returns an environment variable's value as duration in milliseconds if it is exists, +// or the defaultValue if the environment variable is not defined or the value is not valid. +func envDuration(key string, defaultValue time.Duration) time.Duration { + v := os.Getenv(key) + if v == "" { + return defaultValue + } + d, err := strconv.Atoi(v) + if err != nil { + global.Error(err, "parse duration", "environment variable", key, "value", v) + return defaultValue + } + if d <= 0 { + global.Error(errNonPositiveDuration, "non-positive duration", "environment variable", key, "value", v) + return defaultValue + } + return time.Duration(d) * time.Millisecond +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/exporter.go b/vendor/go.opentelemetry.io/otel/sdk/metric/exporter.go new file mode 100644 index 0000000000000..da8941b378d30 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/exporter.go @@ -0,0 +1,88 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "fmt" + + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// ErrExporterShutdown is returned if Export or Shutdown are called after an +// Exporter has been Shutdown. +var ErrExporterShutdown = fmt.Errorf("exporter is shutdown") + +// Exporter handles the delivery of metric data to external receivers. This is +// the final component in the metric push pipeline. +type Exporter interface { + // Temporality returns the Temporality to use for an instrument kind. + // + // This method needs to be concurrent safe with itself and all the other + // Exporter methods. + Temporality(InstrumentKind) metricdata.Temporality + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // Aggregation returns the Aggregation to use for an instrument kind. + // + // This method needs to be concurrent safe with itself and all the other + // Exporter methods. + Aggregation(InstrumentKind) Aggregation + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // Export serializes and transmits metric data to a receiver. + // + // This is called synchronously, there is no concurrency safety + // requirement. Because of this, it is critical that all timeouts and + // cancellations of the passed context be honored. + // + // All retry logic must be contained in this function. The SDK does not + // implement any retry logic. All errors returned by this function are + // considered unrecoverable and will be reported to a configured error + // Handler. + // + // The passed ResourceMetrics may be reused when the call completes. If an + // exporter needs to hold this data after it returns, it needs to make a + // copy. + Export(context.Context, *metricdata.ResourceMetrics) error + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // ForceFlush flushes any metric data held by an exporter. + // + // The deadline or cancellation of the passed context must be honored. An + // appropriate error should be returned in these situations. + // + // This method needs to be concurrent safe. + ForceFlush(context.Context) error + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // Shutdown flushes all metric data held by an exporter and releases any + // held computational resources. + // + // The deadline or cancellation of the passed context must be honored. An + // appropriate error should be returned in these situations. + // + // After Shutdown is called, calls to Export will perform no operation and + // instead will return an error indicating the shutdown state. + // + // This method needs to be concurrent safe. + Shutdown(context.Context) error + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go new file mode 100644 index 0000000000000..bb52f6ec717d8 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/instrument.go @@ -0,0 +1,348 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate stringer -type=InstrumentKind -trimprefix=InstrumentKind + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "errors" + "fmt" + "strings" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" +) + +var ( + zeroInstrumentKind InstrumentKind + zeroScope instrumentation.Scope +) + +// InstrumentKind is the identifier of a group of instruments that all +// performing the same function. +type InstrumentKind uint8 + +const ( + // instrumentKindUndefined is an undefined instrument kind, it should not + // be used by any initialized type. + instrumentKindUndefined InstrumentKind = iota // nolint:deadcode,varcheck,unused + // InstrumentKindCounter identifies a group of instruments that record + // increasing values synchronously with the code path they are measuring. + InstrumentKindCounter + // InstrumentKindUpDownCounter identifies a group of instruments that + // record increasing and decreasing values synchronously with the code path + // they are measuring. + InstrumentKindUpDownCounter + // InstrumentKindHistogram identifies a group of instruments that record a + // distribution of values synchronously with the code path they are + // measuring. + InstrumentKindHistogram + // InstrumentKindObservableCounter identifies a group of instruments that + // record increasing values in an asynchronous callback. + InstrumentKindObservableCounter + // InstrumentKindObservableUpDownCounter identifies a group of instruments + // that record increasing and decreasing values in an asynchronous + // callback. + InstrumentKindObservableUpDownCounter + // InstrumentKindObservableGauge identifies a group of instruments that + // record current values in an asynchronous callback. + InstrumentKindObservableGauge +) + +type nonComparable [0]func() // nolint: unused // This is indeed used. + +// Instrument describes properties an instrument is created with. +type Instrument struct { + // Name is the human-readable identifier of the instrument. + Name string + // Description describes the purpose of the instrument. + Description string + // Kind defines the functional group of the instrument. + Kind InstrumentKind + // Unit is the unit of measurement recorded by the instrument. + Unit string + // Scope identifies the instrumentation that created the instrument. + Scope instrumentation.Scope + + // Ensure forward compatibility if non-comparable fields need to be added. + nonComparable // nolint: unused +} + +// empty returns if all fields of i are their zero-value. +func (i Instrument) empty() bool { + return i.Name == "" && + i.Description == "" && + i.Kind == zeroInstrumentKind && + i.Unit == "" && + i.Scope == zeroScope +} + +// matches returns whether all the non-zero-value fields of i match the +// corresponding fields of other. If i is empty it will match all other, and +// true will always be returned. +func (i Instrument) matches(other Instrument) bool { + return i.matchesName(other) && + i.matchesDescription(other) && + i.matchesKind(other) && + i.matchesUnit(other) && + i.matchesScope(other) +} + +// matchesName returns true if the Name of i is "" or it equals the Name of +// other, otherwise false. +func (i Instrument) matchesName(other Instrument) bool { + return i.Name == "" || i.Name == other.Name +} + +// matchesDescription returns true if the Description of i is "" or it equals +// the Description of other, otherwise false. +func (i Instrument) matchesDescription(other Instrument) bool { + return i.Description == "" || i.Description == other.Description +} + +// matchesKind returns true if the Kind of i is its zero-value or it equals the +// Kind of other, otherwise false. +func (i Instrument) matchesKind(other Instrument) bool { + return i.Kind == zeroInstrumentKind || i.Kind == other.Kind +} + +// matchesUnit returns true if the Unit of i is its zero-value or it equals the +// Unit of other, otherwise false. +func (i Instrument) matchesUnit(other Instrument) bool { + return i.Unit == "" || i.Unit == other.Unit +} + +// matchesScope returns true if the Scope of i is its zero-value or it equals +// the Scope of other, otherwise false. +func (i Instrument) matchesScope(other Instrument) bool { + return (i.Scope.Name == "" || i.Scope.Name == other.Scope.Name) && + (i.Scope.Version == "" || i.Scope.Version == other.Scope.Version) && + (i.Scope.SchemaURL == "" || i.Scope.SchemaURL == other.Scope.SchemaURL) +} + +// Stream describes the stream of data an instrument produces. +type Stream struct { + // Name is the human-readable identifier of the stream. + Name string + // Description describes the purpose of the data. + Description string + // Unit is the unit of measurement recorded. + Unit string + // Aggregation the stream uses for an instrument. + Aggregation Aggregation + // AttributeFilter is an attribute Filter applied to the attributes + // recorded for an instrument's measurement. If the filter returns false + // the attribute will not be recorded, otherwise, if it returns true, it + // will record the attribute. + // + // Use NewAllowKeysFilter from "go.opentelemetry.io/otel/attribute" to + // provide an allow-list of attribute keys here. + AttributeFilter attribute.Filter +} + +// instID are the identifying properties of a instrument. +type instID struct { + // Name is the name of the stream. + Name string + // Description is the description of the stream. + Description string + // Kind defines the functional group of the instrument. + Kind InstrumentKind + // Unit is the unit of the stream. + Unit string + // Number is the number type of the stream. + Number string +} + +// Returns a normalized copy of the instID i. +// +// Instrument names are considered case-insensitive. Standardize the instrument +// name to always be lowercase for the returned instID so it can be compared +// without the name casing affecting the comparison. +func (i instID) normalize() instID { + i.Name = strings.ToLower(i.Name) + return i +} + +type int64Inst struct { + measures []aggregate.Measure[int64] + + embedded.Int64Counter + embedded.Int64UpDownCounter + embedded.Int64Histogram +} + +var ( + _ metric.Int64Counter = (*int64Inst)(nil) + _ metric.Int64UpDownCounter = (*int64Inst)(nil) + _ metric.Int64Histogram = (*int64Inst)(nil) +) + +func (i *int64Inst) Add(ctx context.Context, val int64, opts ...metric.AddOption) { + c := metric.NewAddConfig(opts) + i.aggregate(ctx, val, c.Attributes()) +} + +func (i *int64Inst) Record(ctx context.Context, val int64, opts ...metric.RecordOption) { + c := metric.NewRecordConfig(opts) + i.aggregate(ctx, val, c.Attributes()) +} + +func (i *int64Inst) aggregate(ctx context.Context, val int64, s attribute.Set) { // nolint:revive // okay to shadow pkg with method. + if err := ctx.Err(); err != nil { + return + } + for _, in := range i.measures { + in(ctx, val, s) + } +} + +type float64Inst struct { + measures []aggregate.Measure[float64] + + embedded.Float64Counter + embedded.Float64UpDownCounter + embedded.Float64Histogram +} + +var ( + _ metric.Float64Counter = (*float64Inst)(nil) + _ metric.Float64UpDownCounter = (*float64Inst)(nil) + _ metric.Float64Histogram = (*float64Inst)(nil) +) + +func (i *float64Inst) Add(ctx context.Context, val float64, opts ...metric.AddOption) { + c := metric.NewAddConfig(opts) + i.aggregate(ctx, val, c.Attributes()) +} + +func (i *float64Inst) Record(ctx context.Context, val float64, opts ...metric.RecordOption) { + c := metric.NewRecordConfig(opts) + i.aggregate(ctx, val, c.Attributes()) +} + +func (i *float64Inst) aggregate(ctx context.Context, val float64, s attribute.Set) { + if err := ctx.Err(); err != nil { + return + } + for _, in := range i.measures { + in(ctx, val, s) + } +} + +// observablID is a comparable unique identifier of an observable. +type observablID[N int64 | float64] struct { + name string + description string + kind InstrumentKind + unit string + scope instrumentation.Scope +} + +type float64Observable struct { + metric.Float64Observable + *observable[float64] + + embedded.Float64ObservableCounter + embedded.Float64ObservableUpDownCounter + embedded.Float64ObservableGauge +} + +var ( + _ metric.Float64ObservableCounter = float64Observable{} + _ metric.Float64ObservableUpDownCounter = float64Observable{} + _ metric.Float64ObservableGauge = float64Observable{} +) + +func newFloat64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[float64]) float64Observable { + return float64Observable{ + observable: newObservable(m, kind, name, desc, u, meas), + } +} + +type int64Observable struct { + metric.Int64Observable + *observable[int64] + + embedded.Int64ObservableCounter + embedded.Int64ObservableUpDownCounter + embedded.Int64ObservableGauge +} + +var ( + _ metric.Int64ObservableCounter = int64Observable{} + _ metric.Int64ObservableUpDownCounter = int64Observable{} + _ metric.Int64ObservableGauge = int64Observable{} +) + +func newInt64Observable(m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[int64]) int64Observable { + return int64Observable{ + observable: newObservable(m, kind, name, desc, u, meas), + } +} + +type observable[N int64 | float64] struct { + metric.Observable + observablID[N] + + meter *meter + measures []aggregate.Measure[N] +} + +func newObservable[N int64 | float64](m *meter, kind InstrumentKind, name, desc, u string, meas []aggregate.Measure[N]) *observable[N] { + return &observable[N]{ + observablID: observablID[N]{ + name: name, + description: desc, + kind: kind, + unit: u, + scope: m.scope, + }, + meter: m, + measures: meas, + } +} + +// observe records the val for the set of attrs. +func (o *observable[N]) observe(val N, s attribute.Set) { + for _, in := range o.measures { + in(context.Background(), val, s) + } +} + +var errEmptyAgg = errors.New("no aggregators for observable instrument") + +// registerable returns an error if the observable o should not be registered, +// and nil if it should. An errEmptyAgg error is returned if o is effectively a +// no-op because it does not have any aggregators. Also, an error is returned +// if scope defines a Meter other than the one o was created by. +func (o *observable[N]) registerable(m *meter) error { + if len(o.measures) == 0 { + return errEmptyAgg + } + if m != o.meter { + return fmt.Errorf( + "invalid registration: observable %q from Meter %q, registered with Meter %q", + o.name, + o.scope.Name, + m.scope.Name, + ) + } + return nil +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/instrumentkind_string.go b/vendor/go.opentelemetry.io/otel/sdk/metric/instrumentkind_string.go new file mode 100644 index 0000000000000..d5f9e982c2b90 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/instrumentkind_string.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type=InstrumentKind -trimprefix=InstrumentKind"; DO NOT EDIT. + +package metric + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[instrumentKindUndefined-0] + _ = x[InstrumentKindCounter-1] + _ = x[InstrumentKindUpDownCounter-2] + _ = x[InstrumentKindHistogram-3] + _ = x[InstrumentKindObservableCounter-4] + _ = x[InstrumentKindObservableUpDownCounter-5] + _ = x[InstrumentKindObservableGauge-6] +} + +const _InstrumentKind_name = "instrumentKindUndefinedCounterUpDownCounterHistogramObservableCounterObservableUpDownCounterObservableGauge" + +var _InstrumentKind_index = [...]uint8{0, 23, 30, 43, 52, 69, 92, 107} + +func (i InstrumentKind) String() string { + if i >= InstrumentKind(len(_InstrumentKind_index)-1) { + return "InstrumentKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _InstrumentKind_name[_InstrumentKind_index[i]:_InstrumentKind_index[i+1]] +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go new file mode 100644 index 0000000000000..8dec14237b9b8 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/aggregate.go @@ -0,0 +1,133 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + +import ( + "context" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// now is used to return the current local time while allowing tests to +// override the default time.Now function. +var now = time.Now + +// Measure receives measurements to be aggregated. +type Measure[N int64 | float64] func(context.Context, N, attribute.Set) + +// ComputeAggregation stores the aggregate of measurements into dest and +// returns the number of aggregate data-points output. +type ComputeAggregation func(dest *metricdata.Aggregation) int + +// Builder builds an aggregate function. +type Builder[N int64 | float64] struct { + // Temporality is the temporality used for the returned aggregate function. + // + // If this is not provided a default of cumulative will be used (except for + // the last-value aggregate function where delta is the only appropriate + // temporality). + Temporality metricdata.Temporality + // Filter is the attribute filter the aggregate function will use on the + // input of measurements. + Filter attribute.Filter +} + +func (b Builder[N]) filter(f Measure[N]) Measure[N] { + if b.Filter != nil { + fltr := b.Filter // Copy to make it immutable after assignment. + return func(ctx context.Context, n N, a attribute.Set) { + fAttr, _ := a.Filter(fltr) + f(ctx, n, fAttr) + } + } + return f +} + +// LastValue returns a last-value aggregate function input and output. +// +// The Builder.Temporality is ignored and delta is use always. +func (b Builder[N]) LastValue() (Measure[N], ComputeAggregation) { + // Delta temporality is the only temporality that makes semantic sense for + // a last-value aggregate. + lv := newLastValue[N]() + + return b.filter(lv.measure), func(dest *metricdata.Aggregation) int { + // Ignore if dest is not a metricdata.Gauge. The chance for memory + // reuse of the DataPoints is missed (better luck next time). + gData, _ := (*dest).(metricdata.Gauge[N]) + lv.computeAggregation(&gData.DataPoints) + *dest = gData + + return len(gData.DataPoints) + } +} + +// PrecomputedSum returns a sum aggregate function input and output. The +// arguments passed to the input are expected to be the precomputed sum values. +func (b Builder[N]) PrecomputedSum(monotonic bool) (Measure[N], ComputeAggregation) { + s := newPrecomputedSum[N](monotonic) + switch b.Temporality { + case metricdata.DeltaTemporality: + return b.filter(s.measure), s.delta + default: + return b.filter(s.measure), s.cumulative + } +} + +// Sum returns a sum aggregate function input and output. +func (b Builder[N]) Sum(monotonic bool) (Measure[N], ComputeAggregation) { + s := newSum[N](monotonic) + switch b.Temporality { + case metricdata.DeltaTemporality: + return b.filter(s.measure), s.delta + default: + return b.filter(s.measure), s.cumulative + } +} + +// ExplicitBucketHistogram returns a histogram aggregate function input and +// output. +func (b Builder[N]) ExplicitBucketHistogram(boundaries []float64, noMinMax, noSum bool) (Measure[N], ComputeAggregation) { + h := newHistogram[N](boundaries, noMinMax, noSum) + switch b.Temporality { + case metricdata.DeltaTemporality: + return b.filter(h.measure), h.delta + default: + return b.filter(h.measure), h.cumulative + } +} + +// ExponentialBucketHistogram returns a histogram aggregate function input and +// output. +func (b Builder[N]) ExponentialBucketHistogram(maxSize, maxScale int32, noMinMax, noSum bool) (Measure[N], ComputeAggregation) { + h := newExponentialHistogram[N](maxSize, maxScale, noMinMax, noSum) + switch b.Temporality { + case metricdata.DeltaTemporality: + return b.filter(h.measure), h.delta + default: + return b.filter(h.measure), h.cumulative + } +} + +// reset ensures s has capacity and sets it length. If the capacity of s too +// small, a new slice is returned with the specified capacity and length. +func reset[T any](s []T, length, capacity int) []T { + if cap(s) < capacity { + return make([]T, length, capacity) + } + return s[:length] +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/doc.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/doc.go new file mode 100644 index 0000000000000..e83a2693faf0a --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package aggregate provides aggregate types used compute aggregations and +// cycle the state of metric measurements made by the SDK. These types and +// functionality are meant only for internal SDK use. +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go new file mode 100644 index 0000000000000..98b7dc1e0fad3 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/exponential_histogram.go @@ -0,0 +1,432 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + +import ( + "context" + "errors" + "math" + "sync" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +const ( + expoMaxScale = 20 + expoMinScale = -10 + + smallestNonZeroNormalFloat64 = 0x1p-1022 + + // These redefine the Math constants with a type, so the compiler won't coerce + // them into an int on 32 bit platforms. + maxInt64 int64 = math.MaxInt64 + minInt64 int64 = math.MinInt64 +) + +// expoHistogramDataPoint is a single data point in an exponential histogram. +type expoHistogramDataPoint[N int64 | float64] struct { + count uint64 + min N + max N + sum N + + maxSize int + noMinMax bool + noSum bool + + scale int + + posBuckets expoBuckets + negBuckets expoBuckets + zeroCount uint64 +} + +func newExpoHistogramDataPoint[N int64 | float64](maxSize, maxScale int, noMinMax, noSum bool) *expoHistogramDataPoint[N] { + f := math.MaxFloat64 + max := N(f) // if N is int64, max will overflow to -9223372036854775808 + min := N(-f) + if N(maxInt64) > N(f) { + max = N(maxInt64) + min = N(minInt64) + } + return &expoHistogramDataPoint[N]{ + min: max, + max: min, + maxSize: maxSize, + noMinMax: noMinMax, + noSum: noSum, + scale: maxScale, + } +} + +// record adds a new measurement to the histogram. It will rescale the buckets if needed. +func (p *expoHistogramDataPoint[N]) record(v N) { + p.count++ + + if !p.noMinMax { + if v < p.min { + p.min = v + } + if v > p.max { + p.max = v + } + } + if !p.noSum { + p.sum += v + } + + absV := math.Abs(float64(v)) + + if float64(absV) == 0.0 { + p.zeroCount++ + return + } + + bin := p.getBin(absV) + + bucket := &p.posBuckets + if v < 0 { + bucket = &p.negBuckets + } + + // If the new bin would make the counts larger than maxScale, we need to + // downscale current measurements. + if scaleDelta := p.scaleChange(bin, bucket.startBin, len(bucket.counts)); scaleDelta > 0 { + if p.scale-scaleDelta < expoMinScale { + // With a scale of -10 there is only two buckets for the whole range of float64 values. + // This can only happen if there is a max size of 1. + otel.Handle(errors.New("exponential histogram scale underflow")) + return + } + // Downscale + p.scale -= scaleDelta + p.posBuckets.downscale(scaleDelta) + p.negBuckets.downscale(scaleDelta) + + bin = p.getBin(absV) + } + + bucket.record(bin) +} + +// getBin returns the bin v should be recorded into. +func (p *expoHistogramDataPoint[N]) getBin(v float64) int { + frac, exp := math.Frexp(v) + if p.scale <= 0 { + // Because of the choice of fraction is always 1 power of two higher than we want. + correction := 1 + if frac == .5 { + // If v is an exact power of two the frac will be .5 and the exp + // will be one higher than we want. + correction = 2 + } + return (exp - correction) >> (-p.scale) + } + return exp<= bin { + low = bin + high = startBin + length - 1 + } + + count := 0 + for high-low >= p.maxSize { + low = low >> 1 + high = high >> 1 + count++ + if count > expoMaxScale-expoMinScale { + return count + } + } + return count +} + +// expoBuckets is a set of buckets in an exponential histogram. +type expoBuckets struct { + startBin int + counts []uint64 +} + +// record increments the count for the given bin, and expands the buckets if needed. +// Size changes must be done before calling this function. +func (b *expoBuckets) record(bin int) { + if len(b.counts) == 0 { + b.counts = []uint64{1} + b.startBin = bin + return + } + + endBin := b.startBin + len(b.counts) - 1 + + // if the new bin is inside the current range + if bin >= b.startBin && bin <= endBin { + b.counts[bin-b.startBin]++ + return + } + // if the new bin is before the current start add spaces to the counts + if bin < b.startBin { + origLen := len(b.counts) + newLength := endBin - bin + 1 + shift := b.startBin - bin + + if newLength > cap(b.counts) { + b.counts = append(b.counts, make([]uint64, newLength-len(b.counts))...) + } + + copy(b.counts[shift:origLen+shift], b.counts[:]) + b.counts = b.counts[:newLength] + for i := 1; i < shift; i++ { + b.counts[i] = 0 + } + b.startBin = bin + b.counts[0] = 1 + return + } + // if the new is after the end add spaces to the end + if bin > endBin { + if bin-b.startBin < cap(b.counts) { + b.counts = b.counts[:bin-b.startBin+1] + for i := endBin + 1 - b.startBin; i < len(b.counts); i++ { + b.counts[i] = 0 + } + b.counts[bin-b.startBin] = 1 + return + } + + end := make([]uint64, bin-b.startBin-len(b.counts)+1) + b.counts = append(b.counts, end...) + b.counts[bin-b.startBin] = 1 + } +} + +// downscale shrinks a bucket by a factor of 2*s. It will sum counts into the +// correct lower resolution bucket. +func (b *expoBuckets) downscale(delta int) { + // Example + // delta = 2 + // Original offset: -6 + // Counts: [ 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + // bins: -6 -5, -4, -3, -2, -1, 0, 1, 2, 3, 4 + // new bins:-2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1 + // new Offset: -2 + // new Counts: [4, 14, 30, 10] + + if len(b.counts) <= 1 || delta < 1 { + b.startBin = b.startBin >> delta + return + } + + steps := 1 << delta + offset := b.startBin % steps + offset = (offset + steps) % steps // to make offset positive + for i := 1; i < len(b.counts); i++ { + idx := i + offset + if idx%steps == 0 { + b.counts[idx/steps] = b.counts[i] + continue + } + b.counts[idx/steps] += b.counts[i] + } + + lastIdx := (len(b.counts) - 1 + offset) / steps + b.counts = b.counts[:lastIdx+1] + b.startBin = b.startBin >> delta +} + +// newExponentialHistogram returns an Aggregator that summarizes a set of +// measurements as an exponential histogram. Each histogram is scoped by attributes +// and the aggregation cycle the measurements were made in. +func newExponentialHistogram[N int64 | float64](maxSize, maxScale int32, noMinMax, noSum bool) *expoHistogram[N] { + return &expoHistogram[N]{ + noSum: noSum, + noMinMax: noMinMax, + maxSize: int(maxSize), + maxScale: int(maxScale), + + values: make(map[attribute.Set]*expoHistogramDataPoint[N]), + + start: now(), + } +} + +// expoHistogram summarizes a set of measurements as an histogram with exponentially +// defined buckets. +type expoHistogram[N int64 | float64] struct { + noSum bool + noMinMax bool + maxSize int + maxScale int + + values map[attribute.Set]*expoHistogramDataPoint[N] + valuesMu sync.Mutex + + start time.Time +} + +func (e *expoHistogram[N]) measure(_ context.Context, value N, attr attribute.Set) { + // Ignore NaN and infinity. + if math.IsInf(float64(value), 0) || math.IsNaN(float64(value)) { + return + } + + e.valuesMu.Lock() + defer e.valuesMu.Unlock() + + v, ok := e.values[attr] + if !ok { + v = newExpoHistogramDataPoint[N](e.maxSize, e.maxScale, e.noMinMax, e.noSum) + e.values[attr] = v + } + v.record(value) +} + +func (e *expoHistogram[N]) delta(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed. + // In that case, use the zero-value h and hope for better alignment next cycle. + h, _ := (*dest).(metricdata.ExponentialHistogram[N]) + h.Temporality = metricdata.DeltaTemporality + + e.valuesMu.Lock() + defer e.valuesMu.Unlock() + + n := len(e.values) + hDPts := reset(h.DataPoints, n, n) + + var i int + for a, b := range e.values { + hDPts[i].Attributes = a + hDPts[i].StartTime = e.start + hDPts[i].Time = t + hDPts[i].Count = b.count + hDPts[i].Scale = int32(b.scale) + hDPts[i].ZeroCount = b.zeroCount + hDPts[i].ZeroThreshold = 0.0 + + hDPts[i].PositiveBucket.Offset = int32(b.posBuckets.startBin) + hDPts[i].PositiveBucket.Counts = reset(hDPts[i].PositiveBucket.Counts, len(b.posBuckets.counts), len(b.posBuckets.counts)) + copy(hDPts[i].PositiveBucket.Counts, b.posBuckets.counts) + + hDPts[i].NegativeBucket.Offset = int32(b.negBuckets.startBin) + hDPts[i].NegativeBucket.Counts = reset(hDPts[i].NegativeBucket.Counts, len(b.negBuckets.counts), len(b.negBuckets.counts)) + + if !e.noSum { + hDPts[i].Sum = b.sum + } + if !e.noMinMax { + hDPts[i].Min = metricdata.NewExtrema(b.min) + hDPts[i].Max = metricdata.NewExtrema(b.max) + } + + delete(e.values, a) + i++ + } + e.start = t + h.DataPoints = hDPts + *dest = h + return n +} + +func (e *expoHistogram[N]) cumulative(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed. + // In that case, use the zero-value h and hope for better alignment next cycle. + h, _ := (*dest).(metricdata.ExponentialHistogram[N]) + h.Temporality = metricdata.CumulativeTemporality + + e.valuesMu.Lock() + defer e.valuesMu.Unlock() + + n := len(e.values) + hDPts := reset(h.DataPoints, n, n) + + var i int + for a, b := range e.values { + hDPts[i].Attributes = a + hDPts[i].StartTime = e.start + hDPts[i].Time = t + hDPts[i].Count = b.count + hDPts[i].Scale = int32(b.scale) + hDPts[i].ZeroCount = b.zeroCount + hDPts[i].ZeroThreshold = 0.0 + + hDPts[i].PositiveBucket.Offset = int32(b.posBuckets.startBin) + hDPts[i].PositiveBucket.Counts = reset(hDPts[i].PositiveBucket.Counts, len(b.posBuckets.counts), len(b.posBuckets.counts)) + copy(hDPts[i].PositiveBucket.Counts, b.posBuckets.counts) + + hDPts[i].NegativeBucket.Offset = int32(b.negBuckets.startBin) + hDPts[i].NegativeBucket.Counts = reset(hDPts[i].NegativeBucket.Counts, len(b.negBuckets.counts), len(b.negBuckets.counts)) + + if !e.noSum { + hDPts[i].Sum = b.sum + } + if !e.noMinMax { + hDPts[i].Min = metricdata.NewExtrema(b.min) + hDPts[i].Max = metricdata.NewExtrema(b.max) + } + + i++ + // TODO (#3006): This will use an unbounded amount of memory if there + // are unbounded number of attribute sets being aggregated. Attribute + // sets that become "stale" need to be forgotten so this will not + // overload the system. + } + + h.DataPoints = hDPts + *dest = h + return n +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go new file mode 100644 index 0000000000000..62ec51e1f5ede --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/histogram.go @@ -0,0 +1,231 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + +import ( + "context" + "sort" + "sync" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +type buckets[N int64 | float64] struct { + counts []uint64 + count uint64 + total N + min, max N +} + +// newBuckets returns buckets with n bins. +func newBuckets[N int64 | float64](n int) *buckets[N] { + return &buckets[N]{counts: make([]uint64, n)} +} + +func (b *buckets[N]) sum(value N) { b.total += value } + +func (b *buckets[N]) bin(idx int, value N) { + b.counts[idx]++ + b.count++ + if value < b.min { + b.min = value + } else if value > b.max { + b.max = value + } +} + +// histValues summarizes a set of measurements as an histValues with +// explicitly defined buckets. +type histValues[N int64 | float64] struct { + noSum bool + bounds []float64 + + values map[attribute.Set]*buckets[N] + valuesMu sync.Mutex +} + +func newHistValues[N int64 | float64](bounds []float64, noSum bool) *histValues[N] { + // The responsibility of keeping all buckets correctly associated with the + // passed boundaries is ultimately this type's responsibility. Make a copy + // here so we can always guarantee this. Or, in the case of failure, have + // complete control over the fix. + b := make([]float64, len(bounds)) + copy(b, bounds) + sort.Float64s(b) + return &histValues[N]{ + noSum: noSum, + bounds: b, + values: make(map[attribute.Set]*buckets[N]), + } +} + +// Aggregate records the measurement value, scoped by attr, and aggregates it +// into a histogram. +func (s *histValues[N]) measure(_ context.Context, value N, attr attribute.Set) { + // This search will return an index in the range [0, len(s.bounds)], where + // it will return len(s.bounds) if value is greater than the last element + // of s.bounds. This aligns with the buckets in that the length of buckets + // is len(s.bounds)+1, with the last bucket representing: + // (s.bounds[len(s.bounds)-1], +∞). + idx := sort.SearchFloat64s(s.bounds, float64(value)) + + s.valuesMu.Lock() + defer s.valuesMu.Unlock() + + b, ok := s.values[attr] + if !ok { + // N+1 buckets. For example: + // + // bounds = [0, 5, 10] + // + // Then, + // + // buckets = (-∞, 0], (0, 5.0], (5.0, 10.0], (10.0, +∞) + b = newBuckets[N](len(s.bounds) + 1) + // Ensure min and max are recorded values (not zero), for new buckets. + b.min, b.max = value, value + s.values[attr] = b + } + b.bin(idx, value) + if !s.noSum { + b.sum(value) + } +} + +// newHistogram returns an Aggregator that summarizes a set of measurements as +// an histogram. +func newHistogram[N int64 | float64](boundaries []float64, noMinMax, noSum bool) *histogram[N] { + return &histogram[N]{ + histValues: newHistValues[N](boundaries, noSum), + noMinMax: noMinMax, + start: now(), + } +} + +// histogram summarizes a set of measurements as an histogram with explicitly +// defined buckets. +type histogram[N int64 | float64] struct { + *histValues[N] + + noMinMax bool + start time.Time +} + +func (s *histogram[N]) delta(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.Histogram, memory reuse is missed. In that + // case, use the zero-value h and hope for better alignment next cycle. + h, _ := (*dest).(metricdata.Histogram[N]) + h.Temporality = metricdata.DeltaTemporality + + s.valuesMu.Lock() + defer s.valuesMu.Unlock() + + // Do not allow modification of our copy of bounds. + bounds := make([]float64, len(s.bounds)) + copy(bounds, s.bounds) + + n := len(s.values) + hDPts := reset(h.DataPoints, n, n) + + var i int + for a, b := range s.values { + hDPts[i].Attributes = a + hDPts[i].StartTime = s.start + hDPts[i].Time = t + hDPts[i].Count = b.count + hDPts[i].Bounds = bounds + hDPts[i].BucketCounts = b.counts + + if !s.noSum { + hDPts[i].Sum = b.total + } + + if !s.noMinMax { + hDPts[i].Min = metricdata.NewExtrema(b.min) + hDPts[i].Max = metricdata.NewExtrema(b.max) + } + + // Unused attribute sets do not report. + delete(s.values, a) + i++ + } + // The delta collection cycle resets. + s.start = t + + h.DataPoints = hDPts + *dest = h + + return n +} + +func (s *histogram[N]) cumulative(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.Histogram, memory reuse is missed. In that + // case, use the zero-value h and hope for better alignment next cycle. + h, _ := (*dest).(metricdata.Histogram[N]) + h.Temporality = metricdata.CumulativeTemporality + + s.valuesMu.Lock() + defer s.valuesMu.Unlock() + + // Do not allow modification of our copy of bounds. + bounds := make([]float64, len(s.bounds)) + copy(bounds, s.bounds) + + n := len(s.values) + hDPts := reset(h.DataPoints, n, n) + + var i int + for a, b := range s.values { + // The HistogramDataPoint field values returned need to be copies of + // the buckets value as we will keep updating them. + // + // TODO (#3047): Making copies for bounds and counts incurs a large + // memory allocation footprint. Alternatives should be explored. + counts := make([]uint64, len(b.counts)) + copy(counts, b.counts) + + hDPts[i].Attributes = a + hDPts[i].StartTime = s.start + hDPts[i].Time = t + hDPts[i].Count = b.count + hDPts[i].Bounds = bounds + hDPts[i].BucketCounts = counts + + if !s.noSum { + hDPts[i].Sum = b.total + } + + if !s.noMinMax { + hDPts[i].Min = metricdata.NewExtrema(b.min) + hDPts[i].Max = metricdata.NewExtrema(b.max) + } + i++ + // TODO (#3006): This will use an unbounded amount of memory if there + // are unbounded number of attribute sets being aggregated. Attribute + // sets that become "stale" need to be forgotten so this will not + // overload the system. + } + + h.DataPoints = hDPts + *dest = h + + return n +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go new file mode 100644 index 0000000000000..6af2d606141e4 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/lastvalue.go @@ -0,0 +1,68 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + +import ( + "context" + "sync" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// datapoint is timestamped measurement data. +type datapoint[N int64 | float64] struct { + timestamp time.Time + value N +} + +func newLastValue[N int64 | float64]() *lastValue[N] { + return &lastValue[N]{values: make(map[attribute.Set]datapoint[N])} +} + +// lastValue summarizes a set of measurements as the last one made. +type lastValue[N int64 | float64] struct { + sync.Mutex + + values map[attribute.Set]datapoint[N] +} + +func (s *lastValue[N]) measure(ctx context.Context, value N, attr attribute.Set) { + d := datapoint[N]{timestamp: now(), value: value} + s.Lock() + s.values[attr] = d + s.Unlock() +} + +func (s *lastValue[N]) computeAggregation(dest *[]metricdata.DataPoint[N]) { + s.Lock() + defer s.Unlock() + + n := len(s.values) + *dest = reset(*dest, n, n) + + var i int + for a, v := range s.values { + (*dest)[i].Attributes = a + // The event time is the only meaningful timestamp, StartTime is + // ignored. + (*dest)[i].Time = v.timestamp + (*dest)[i].Value = v.value + // Do not report stale values. + delete(s.values, a) + i++ + } +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go new file mode 100644 index 0000000000000..1e52ff0d1e556 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/aggregate/sum.go @@ -0,0 +1,222 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + +import ( + "context" + "sync" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// valueMap is the storage for sums. +type valueMap[N int64 | float64] struct { + sync.Mutex + values map[attribute.Set]N +} + +func newValueMap[N int64 | float64]() *valueMap[N] { + return &valueMap[N]{values: make(map[attribute.Set]N)} +} + +func (s *valueMap[N]) measure(_ context.Context, value N, attr attribute.Set) { + s.Lock() + s.values[attr] += value + s.Unlock() +} + +// newSum returns an aggregator that summarizes a set of measurements as their +// arithmetic sum. Each sum is scoped by attributes and the aggregation cycle +// the measurements were made in. +func newSum[N int64 | float64](monotonic bool) *sum[N] { + return &sum[N]{ + valueMap: newValueMap[N](), + monotonic: monotonic, + start: now(), + } +} + +// sum summarizes a set of measurements made as their arithmetic sum. +type sum[N int64 | float64] struct { + *valueMap[N] + + monotonic bool + start time.Time +} + +func (s *sum[N]) delta(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.Sum, memory reuse is missed. In that case, + // use the zero-value sData and hope for better alignment next cycle. + sData, _ := (*dest).(metricdata.Sum[N]) + sData.Temporality = metricdata.DeltaTemporality + sData.IsMonotonic = s.monotonic + + s.Lock() + defer s.Unlock() + + n := len(s.values) + dPts := reset(sData.DataPoints, n, n) + + var i int + for attr, value := range s.values { + dPts[i].Attributes = attr + dPts[i].StartTime = s.start + dPts[i].Time = t + dPts[i].Value = value + // Do not report stale values. + delete(s.values, attr) + i++ + } + // The delta collection cycle resets. + s.start = t + + sData.DataPoints = dPts + *dest = sData + + return n +} + +func (s *sum[N]) cumulative(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.Sum, memory reuse is missed. In that case, + // use the zero-value sData and hope for better alignment next cycle. + sData, _ := (*dest).(metricdata.Sum[N]) + sData.Temporality = metricdata.CumulativeTemporality + sData.IsMonotonic = s.monotonic + + s.Lock() + defer s.Unlock() + + n := len(s.values) + dPts := reset(sData.DataPoints, n, n) + + var i int + for attr, value := range s.values { + dPts[i].Attributes = attr + dPts[i].StartTime = s.start + dPts[i].Time = t + dPts[i].Value = value + // TODO (#3006): This will use an unbounded amount of memory if there + // are unbounded number of attribute sets being aggregated. Attribute + // sets that become "stale" need to be forgotten so this will not + // overload the system. + i++ + } + + sData.DataPoints = dPts + *dest = sData + + return n +} + +// newPrecomputedSum returns an aggregator that summarizes a set of +// observatrions as their arithmetic sum. Each sum is scoped by attributes and +// the aggregation cycle the measurements were made in. +func newPrecomputedSum[N int64 | float64](monotonic bool) *precomputedSum[N] { + return &precomputedSum[N]{ + valueMap: newValueMap[N](), + monotonic: monotonic, + start: now(), + } +} + +// precomputedSum summarizes a set of observatrions as their arithmetic sum. +type precomputedSum[N int64 | float64] struct { + *valueMap[N] + + monotonic bool + start time.Time + + reported map[attribute.Set]N +} + +func (s *precomputedSum[N]) delta(dest *metricdata.Aggregation) int { + t := now() + newReported := make(map[attribute.Set]N) + + // If *dest is not a metricdata.Sum, memory reuse is missed. In that case, + // use the zero-value sData and hope for better alignment next cycle. + sData, _ := (*dest).(metricdata.Sum[N]) + sData.Temporality = metricdata.DeltaTemporality + sData.IsMonotonic = s.monotonic + + s.Lock() + defer s.Unlock() + + n := len(s.values) + dPts := reset(sData.DataPoints, n, n) + + var i int + for attr, value := range s.values { + delta := value - s.reported[attr] + + dPts[i].Attributes = attr + dPts[i].StartTime = s.start + dPts[i].Time = t + dPts[i].Value = delta + + newReported[attr] = value + // Unused attribute sets do not report. + delete(s.values, attr) + i++ + } + // Unused attribute sets are forgotten. + s.reported = newReported + // The delta collection cycle resets. + s.start = t + + sData.DataPoints = dPts + *dest = sData + + return n +} + +func (s *precomputedSum[N]) cumulative(dest *metricdata.Aggregation) int { + t := now() + + // If *dest is not a metricdata.Sum, memory reuse is missed. In that case, + // use the zero-value sData and hope for better alignment next cycle. + sData, _ := (*dest).(metricdata.Sum[N]) + sData.Temporality = metricdata.CumulativeTemporality + sData.IsMonotonic = s.monotonic + + s.Lock() + defer s.Unlock() + + n := len(s.values) + dPts := reset(sData.DataPoints, n, n) + + var i int + for attr, value := range s.values { + dPts[i].Attributes = attr + dPts[i].StartTime = s.start + dPts[i].Time = t + dPts[i].Value = value + + // Unused attribute sets do not report. + delete(s.values, attr) + i++ + } + + sData.DataPoints = dPts + *dest = sData + + return n +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/internal/reuse_slice.go b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/reuse_slice.go new file mode 100644 index 0000000000000..9695492b0d111 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/internal/reuse_slice.go @@ -0,0 +1,24 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal // import "go.opentelemetry.io/otel/sdk/metric/internal" + +// ReuseSlice returns a zeroed view of slice if its capacity is greater than or +// equal to n. Otherwise, it returns a new []T with capacity equal to n. +func ReuseSlice[T any](slice []T, n int) []T { + if cap(slice) >= n { + return slice[:n] + } + return make([]T, n) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go new file mode 100644 index 0000000000000..7d524de9ea149 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/manual_reader.go @@ -0,0 +1,214 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// ManualReader is a simple Reader that allows an application to +// read metrics on demand. +type ManualReader struct { + sdkProducer atomic.Value + shutdownOnce sync.Once + + mu sync.Mutex + isShutdown bool + externalProducers atomic.Value + + temporalitySelector TemporalitySelector + aggregationSelector AggregationSelector +} + +// Compile time check the manualReader implements Reader and is comparable. +var _ = map[Reader]struct{}{&ManualReader{}: {}} + +// NewManualReader returns a Reader which is directly called to collect metrics. +func NewManualReader(opts ...ManualReaderOption) *ManualReader { + cfg := newManualReaderConfig(opts) + r := &ManualReader{ + temporalitySelector: cfg.temporalitySelector, + aggregationSelector: cfg.aggregationSelector, + } + r.externalProducers.Store(cfg.producers) + return r +} + +// register stores the sdkProducer which enables the caller +// to read metrics from the SDK on demand. +func (mr *ManualReader) register(p sdkProducer) { + // Only register once. If producer is already set, do nothing. + if !mr.sdkProducer.CompareAndSwap(nil, produceHolder{produce: p.produce}) { + msg := "did not register manual reader" + global.Error(errDuplicateRegister, msg) + } +} + +// temporality reports the Temporality for the instrument kind provided. +func (mr *ManualReader) temporality(kind InstrumentKind) metricdata.Temporality { + return mr.temporalitySelector(kind) +} + +// aggregation returns what Aggregation to use for kind. +func (mr *ManualReader) aggregation(kind InstrumentKind) Aggregation { // nolint:revive // import-shadow for method scoped by type. + return mr.aggregationSelector(kind) +} + +// Shutdown closes any connections and frees any resources used by the reader. +// +// This method is safe to call concurrently. +func (mr *ManualReader) Shutdown(context.Context) error { + err := ErrReaderShutdown + mr.shutdownOnce.Do(func() { + // Any future call to Collect will now return ErrReaderShutdown. + mr.sdkProducer.Store(produceHolder{ + produce: shutdownProducer{}.produce, + }) + mr.mu.Lock() + defer mr.mu.Unlock() + mr.isShutdown = true + // release references to Producer(s) + mr.externalProducers.Store([]Producer{}) + err = nil + }) + return err +} + +// Collect gathers all metric data related to the Reader from +// the SDK and other Producers and stores the result in rm. +// +// Collect will return an error if called after shutdown. +// Collect will return an error if rm is a nil ResourceMetrics. +// Collect will return an error if the context's Done channel is closed. +// +// This method is safe to call concurrently. +func (mr *ManualReader) Collect(ctx context.Context, rm *metricdata.ResourceMetrics) error { + if rm == nil { + return errors.New("manual reader: *metricdata.ResourceMetrics is nil") + } + p := mr.sdkProducer.Load() + if p == nil { + return ErrReaderNotRegistered + } + + ph, ok := p.(produceHolder) + if !ok { + // The atomic.Value is entirely in the periodicReader's control so + // this should never happen. In the unforeseen case that this does + // happen, return an error instead of panicking so a users code does + // not halt in the processes. + err := fmt.Errorf("manual reader: invalid producer: %T", p) + return err + } + + err := ph.produce(ctx, rm) + if err != nil { + return err + } + var errs []error + for _, producer := range mr.externalProducers.Load().([]Producer) { + externalMetrics, err := producer.Produce(ctx) + if err != nil { + errs = append(errs, err) + } + rm.ScopeMetrics = append(rm.ScopeMetrics, externalMetrics...) + } + + global.Debug("ManualReader collection", "Data", rm) + + return unifyErrors(errs) +} + +// MarshalLog returns logging data about the ManualReader. +func (r *ManualReader) MarshalLog() interface{} { + r.mu.Lock() + down := r.isShutdown + r.mu.Unlock() + return struct { + Type string + Registered bool + Shutdown bool + }{ + Type: "ManualReader", + Registered: r.sdkProducer.Load() != nil, + Shutdown: down, + } +} + +// manualReaderConfig contains configuration options for a ManualReader. +type manualReaderConfig struct { + temporalitySelector TemporalitySelector + aggregationSelector AggregationSelector + producers []Producer +} + +// newManualReaderConfig returns a manualReaderConfig configured with options. +func newManualReaderConfig(opts []ManualReaderOption) manualReaderConfig { + cfg := manualReaderConfig{ + temporalitySelector: DefaultTemporalitySelector, + aggregationSelector: DefaultAggregationSelector, + } + for _, opt := range opts { + cfg = opt.applyManual(cfg) + } + return cfg +} + +// ManualReaderOption applies a configuration option value to a ManualReader. +type ManualReaderOption interface { + applyManual(manualReaderConfig) manualReaderConfig +} + +// WithTemporalitySelector sets the TemporalitySelector a reader will use to +// determine the Temporality of an instrument based on its kind. If this +// option is not used, the reader will use the DefaultTemporalitySelector. +func WithTemporalitySelector(selector TemporalitySelector) ManualReaderOption { + return temporalitySelectorOption{selector: selector} +} + +type temporalitySelectorOption struct { + selector func(instrument InstrumentKind) metricdata.Temporality +} + +// applyManual returns a manualReaderConfig with option applied. +func (t temporalitySelectorOption) applyManual(mrc manualReaderConfig) manualReaderConfig { + mrc.temporalitySelector = t.selector + return mrc +} + +// WithAggregationSelector sets the AggregationSelector a reader will use to +// determine the aggregation to use for an instrument based on its kind. If +// this option is not used, the reader will use the DefaultAggregationSelector +// or the aggregation explicitly passed for a view matching an instrument. +func WithAggregationSelector(selector AggregationSelector) ManualReaderOption { + return aggregationSelectorOption{selector: selector} +} + +type aggregationSelectorOption struct { + selector AggregationSelector +} + +// applyManual returns a manualReaderConfig with option applied. +func (t aggregationSelectorOption) applyManual(c manualReaderConfig) manualReaderConfig { + c.aggregationSelector = t.selector + return c +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go b/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go new file mode 100644 index 0000000000000..7f51ec512ad37 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/meter.go @@ -0,0 +1,595 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "errors" + "fmt" + + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" +) + +// ErrInstrumentName indicates the created instrument has an invalid name. +// Valid names must consist of 255 or fewer characters including alphanumeric, _, ., -, / and start with a letter. +var ErrInstrumentName = errors.New("invalid instrument name") + +// meter handles the creation and coordination of all metric instruments. A +// meter represents a single instrumentation scope; all metric telemetry +// produced by an instrumentation scope will use metric instruments from a +// single meter. +type meter struct { + embedded.Meter + + scope instrumentation.Scope + pipes pipelines + + int64Resolver resolver[int64] + float64Resolver resolver[float64] +} + +func newMeter(s instrumentation.Scope, p pipelines) *meter { + // viewCache ensures instrument conflicts, including number conflicts, this + // meter is asked to create are logged to the user. + var viewCache cache[string, instID] + + return &meter{ + scope: s, + pipes: p, + int64Resolver: newResolver[int64](p, &viewCache), + float64Resolver: newResolver[float64](p, &viewCache), + } +} + +// Compile-time check meter implements metric.Meter. +var _ metric.Meter = (*meter)(nil) + +// Int64Counter returns a new instrument identified by name and configured with +// options. The instrument is used to synchronously record increasing int64 +// measurements during a computational operation. +func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption) (metric.Int64Counter, error) { + cfg := metric.NewInt64CounterConfig(options...) + const kind = InstrumentKindCounter + p := int64InstProvider{m} + i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Int64UpDownCounter returns a new instrument identified by name and +// configured with options. The instrument is used to synchronously record +// int64 measurements during a computational operation. +func (m *meter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) { + cfg := metric.NewInt64UpDownCounterConfig(options...) + const kind = InstrumentKindUpDownCounter + p := int64InstProvider{m} + i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Int64Histogram returns a new instrument identified by name and configured +// with options. The instrument is used to synchronously record the +// distribution of int64 measurements during a computational operation. +func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOption) (metric.Int64Histogram, error) { + cfg := metric.NewInt64HistogramConfig(options...) + p := int64InstProvider{m} + i, err := p.lookupHistogram(name, cfg) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Int64ObservableCounter returns a new instrument identified by name and +// configured with options. The instrument is used to asynchronously record +// increasing int64 measurements once per a measurement collection cycle. +// Only the measurements recorded during the collection cycle are exported. +func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) { + cfg := metric.NewInt64ObservableCounterConfig(options...) + const kind = InstrumentKindObservableCounter + p := int64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +// Int64ObservableUpDownCounter returns a new instrument identified by name and +// configured with options. The instrument is used to asynchronously record +// int64 measurements once per a measurement collection cycle. Only the +// measurements recorded during the collection cycle are exported. +func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) { + cfg := metric.NewInt64ObservableUpDownCounterConfig(options...) + const kind = InstrumentKindObservableUpDownCounter + p := int64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +// Int64ObservableGauge returns a new instrument identified by name and +// configured with options. The instrument is used to asynchronously record +// instantaneous int64 measurements once per a measurement collection cycle. +// Only the measurements recorded during the collection cycle are exported. +func (m *meter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) { + cfg := metric.NewInt64ObservableGaugeConfig(options...) + const kind = InstrumentKindObservableGauge + p := int64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +// Float64Counter returns a new instrument identified by name and configured +// with options. The instrument is used to synchronously record increasing +// float64 measurements during a computational operation. +func (m *meter) Float64Counter(name string, options ...metric.Float64CounterOption) (metric.Float64Counter, error) { + cfg := metric.NewFloat64CounterConfig(options...) + const kind = InstrumentKindCounter + p := float64InstProvider{m} + i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Float64UpDownCounter returns a new instrument identified by name and +// configured with options. The instrument is used to synchronously record +// float64 measurements during a computational operation. +func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) { + cfg := metric.NewFloat64UpDownCounterConfig(options...) + const kind = InstrumentKindUpDownCounter + p := float64InstProvider{m} + i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Float64Histogram returns a new instrument identified by name and configured +// with options. The instrument is used to synchronously record the +// distribution of float64 measurements during a computational operation. +func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) { + cfg := metric.NewFloat64HistogramConfig(options...) + p := float64InstProvider{m} + i, err := p.lookupHistogram(name, cfg) + if err != nil { + return i, err + } + + return i, validateInstrumentName(name) +} + +// Float64ObservableCounter returns a new instrument identified by name and +// configured with options. The instrument is used to asynchronously record +// increasing float64 measurements once per a measurement collection cycle. +// Only the measurements recorded during the collection cycle are exported. +func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) { + cfg := metric.NewFloat64ObservableCounterConfig(options...) + const kind = InstrumentKindObservableCounter + p := float64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +// Float64ObservableUpDownCounter returns a new instrument identified by name +// and configured with options. The instrument is used to asynchronously record +// float64 measurements once per a measurement collection cycle. Only the +// measurements recorded during the collection cycle are exported. +func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) { + cfg := metric.NewFloat64ObservableUpDownCounterConfig(options...) + const kind = InstrumentKindObservableUpDownCounter + p := float64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +// Float64ObservableGauge returns a new instrument identified by name and +// configured with options. The instrument is used to asynchronously record +// instantaneous float64 measurements once per a measurement collection cycle. +// Only the measurements recorded during the collection cycle are exported. +func (m *meter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) { + cfg := metric.NewFloat64ObservableGaugeConfig(options...) + const kind = InstrumentKindObservableGauge + p := float64ObservProvider{m} + inst, err := p.lookup(kind, name, cfg.Description(), cfg.Unit()) + if err != nil { + return nil, err + } + p.registerCallbacks(inst, cfg.Callbacks()) + return inst, validateInstrumentName(name) +} + +func validateInstrumentName(name string) error { + if len(name) == 0 { + return fmt.Errorf("%w: %s: is empty", ErrInstrumentName, name) + } + if len(name) > 255 { + return fmt.Errorf("%w: %s: longer than 255 characters", ErrInstrumentName, name) + } + if !isAlpha([]rune(name)[0]) { + return fmt.Errorf("%w: %s: must start with a letter", ErrInstrumentName, name) + } + if len(name) == 1 { + return nil + } + for _, c := range name[1:] { + if !isAlphanumeric(c) && c != '_' && c != '.' && c != '-' && c != '/' { + return fmt.Errorf("%w: %s: must only contain [A-Za-z0-9_.-/]", ErrInstrumentName, name) + } + } + return nil +} + +func isAlpha(c rune) bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') +} + +func isAlphanumeric(c rune) bool { + return isAlpha(c) || ('0' <= c && c <= '9') +} + +// RegisterCallback registers f to be called each collection cycle so it will +// make observations for insts during those cycles. +// +// The only instruments f can make observations for are insts. All other +// observations will be dropped and an error will be logged. +// +// Only instruments from this meter can be registered with f, an error is +// returned if other instrument are provided. +// +// Only observations made in the callback will be exported. Unlike synchronous +// instruments, asynchronous callbacks can "forget" attribute sets that are no +// longer relevant by omitting the observation during the callback. +// +// The returned Registration can be used to unregister f. +func (m *meter) RegisterCallback(f metric.Callback, insts ...metric.Observable) (metric.Registration, error) { + if len(insts) == 0 { + // Don't allocate a observer if not needed. + return noopRegister{}, nil + } + + reg := newObserver() + var errs multierror + for _, inst := range insts { + // Unwrap any global. + if u, ok := inst.(interface { + Unwrap() metric.Observable + }); ok { + inst = u.Unwrap() + } + + switch o := inst.(type) { + case int64Observable: + if err := o.registerable(m); err != nil { + if !errors.Is(err, errEmptyAgg) { + errs.append(err) + } + continue + } + reg.registerInt64(o.observablID) + case float64Observable: + if err := o.registerable(m); err != nil { + if !errors.Is(err, errEmptyAgg) { + errs.append(err) + } + continue + } + reg.registerFloat64(o.observablID) + default: + // Instrument external to the SDK. + return nil, fmt.Errorf("invalid observable: from different implementation") + } + } + + err := errs.errorOrNil() + if reg.len() == 0 { + // All insts use drop aggregation or are invalid. + return noopRegister{}, err + } + + // Some or all instruments were valid. + cback := func(ctx context.Context) error { return f(ctx, reg) } + return m.pipes.registerMultiCallback(cback), err +} + +type observer struct { + embedded.Observer + + float64 map[observablID[float64]]struct{} + int64 map[observablID[int64]]struct{} +} + +func newObserver() observer { + return observer{ + float64: make(map[observablID[float64]]struct{}), + int64: make(map[observablID[int64]]struct{}), + } +} + +func (r observer) len() int { + return len(r.float64) + len(r.int64) +} + +func (r observer) registerFloat64(id observablID[float64]) { + r.float64[id] = struct{}{} +} + +func (r observer) registerInt64(id observablID[int64]) { + r.int64[id] = struct{}{} +} + +var ( + errUnknownObserver = errors.New("unknown observable instrument") + errUnregObserver = errors.New("observable instrument not registered for callback") +) + +func (r observer) ObserveFloat64(o metric.Float64Observable, v float64, opts ...metric.ObserveOption) { + var oImpl float64Observable + switch conv := o.(type) { + case float64Observable: + oImpl = conv + case interface { + Unwrap() metric.Observable + }: + // Unwrap any global. + async := conv.Unwrap() + var ok bool + if oImpl, ok = async.(float64Observable); !ok { + global.Error(errUnknownObserver, "failed to record asynchronous") + return + } + default: + global.Error(errUnknownObserver, "failed to record") + return + } + + if _, registered := r.float64[oImpl.observablID]; !registered { + global.Error(errUnregObserver, "failed to record", + "name", oImpl.name, + "description", oImpl.description, + "unit", oImpl.unit, + "number", fmt.Sprintf("%T", float64(0)), + ) + return + } + c := metric.NewObserveConfig(opts) + oImpl.observe(v, c.Attributes()) +} + +func (r observer) ObserveInt64(o metric.Int64Observable, v int64, opts ...metric.ObserveOption) { + var oImpl int64Observable + switch conv := o.(type) { + case int64Observable: + oImpl = conv + case interface { + Unwrap() metric.Observable + }: + // Unwrap any global. + async := conv.Unwrap() + var ok bool + if oImpl, ok = async.(int64Observable); !ok { + global.Error(errUnknownObserver, "failed to record asynchronous") + return + } + default: + global.Error(errUnknownObserver, "failed to record") + return + } + + if _, registered := r.int64[oImpl.observablID]; !registered { + global.Error(errUnregObserver, "failed to record", + "name", oImpl.name, + "description", oImpl.description, + "unit", oImpl.unit, + "number", fmt.Sprintf("%T", int64(0)), + ) + return + } + c := metric.NewObserveConfig(opts) + oImpl.observe(v, c.Attributes()) +} + +type noopRegister struct{ embedded.Registration } + +func (noopRegister) Unregister() error { + return nil +} + +// int64InstProvider provides int64 OpenTelemetry instruments. +type int64InstProvider struct{ *meter } + +func (p int64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]aggregate.Measure[int64], error) { + inst := Instrument{ + Name: name, + Description: desc, + Unit: u, + Kind: kind, + Scope: p.scope, + } + return p.int64Resolver.Aggregators(inst) +} + +func (p int64InstProvider) histogramAggs(name string, cfg metric.Int64HistogramConfig) ([]aggregate.Measure[int64], error) { + boundaries := cfg.ExplicitBucketBoundaries() + aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err() + if aggError != nil { + // If boundaries are invalid, ignore them. + boundaries = nil + } + inst := Instrument{ + Name: name, + Description: cfg.Description(), + Unit: cfg.Unit(), + Kind: InstrumentKindHistogram, + Scope: p.scope, + } + measures, err := p.int64Resolver.HistogramAggregators(inst, boundaries) + return measures, errors.Join(aggError, err) +} + +// lookup returns the resolved instrumentImpl. +func (p int64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*int64Inst, error) { + aggs, err := p.aggs(kind, name, desc, u) + return &int64Inst{measures: aggs}, err +} + +// lookupHistogram returns the resolved instrumentImpl. +func (p int64InstProvider) lookupHistogram(name string, cfg metric.Int64HistogramConfig) (*int64Inst, error) { + aggs, err := p.histogramAggs(name, cfg) + return &int64Inst{measures: aggs}, err +} + +// float64InstProvider provides float64 OpenTelemetry instruments. +type float64InstProvider struct{ *meter } + +func (p float64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]aggregate.Measure[float64], error) { + inst := Instrument{ + Name: name, + Description: desc, + Unit: u, + Kind: kind, + Scope: p.scope, + } + return p.float64Resolver.Aggregators(inst) +} + +func (p float64InstProvider) histogramAggs(name string, cfg metric.Float64HistogramConfig) ([]aggregate.Measure[float64], error) { + boundaries := cfg.ExplicitBucketBoundaries() + aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err() + if aggError != nil { + // If boundaries are invalid, ignore them. + boundaries = nil + } + inst := Instrument{ + Name: name, + Description: cfg.Description(), + Unit: cfg.Unit(), + Kind: InstrumentKindHistogram, + Scope: p.scope, + } + measures, err := p.float64Resolver.HistogramAggregators(inst, boundaries) + return measures, errors.Join(aggError, err) +} + +// lookup returns the resolved instrumentImpl. +func (p float64InstProvider) lookup(kind InstrumentKind, name, desc, u string) (*float64Inst, error) { + aggs, err := p.aggs(kind, name, desc, u) + return &float64Inst{measures: aggs}, err +} + +// lookupHistogram returns the resolved instrumentImpl. +func (p float64InstProvider) lookupHistogram(name string, cfg metric.Float64HistogramConfig) (*float64Inst, error) { + aggs, err := p.histogramAggs(name, cfg) + return &float64Inst{measures: aggs}, err +} + +type int64ObservProvider struct{ *meter } + +func (p int64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (int64Observable, error) { + aggs, err := (int64InstProvider)(p).aggs(kind, name, desc, u) + return newInt64Observable(p.meter, kind, name, desc, u, aggs), err +} + +func (p int64ObservProvider) registerCallbacks(inst int64Observable, cBacks []metric.Int64Callback) { + if inst.observable == nil || len(inst.measures) == 0 { + // Drop aggregator. + return + } + + for _, cBack := range cBacks { + p.pipes.registerCallback(p.callback(inst, cBack)) + } +} + +func (p int64ObservProvider) callback(i int64Observable, f metric.Int64Callback) func(context.Context) error { + inst := int64Observer{int64Observable: i} + return func(ctx context.Context) error { return f(ctx, inst) } +} + +type int64Observer struct { + embedded.Int64Observer + int64Observable +} + +func (o int64Observer) Observe(val int64, opts ...metric.ObserveOption) { + c := metric.NewObserveConfig(opts) + o.observe(val, c.Attributes()) +} + +type float64ObservProvider struct{ *meter } + +func (p float64ObservProvider) lookup(kind InstrumentKind, name, desc, u string) (float64Observable, error) { + aggs, err := (float64InstProvider)(p).aggs(kind, name, desc, u) + return newFloat64Observable(p.meter, kind, name, desc, u, aggs), err +} + +func (p float64ObservProvider) registerCallbacks(inst float64Observable, cBacks []metric.Float64Callback) { + if inst.observable == nil || len(inst.measures) == 0 { + // Drop aggregator. + return + } + + for _, cBack := range cBacks { + p.pipes.registerCallback(p.callback(inst, cBack)) + } +} + +func (p float64ObservProvider) callback(i float64Observable, f metric.Float64Callback) func(context.Context) error { + inst := float64Observer{float64Observable: i} + return func(ctx context.Context) error { return f(ctx, inst) } +} + +type float64Observer struct { + embedded.Float64Observer + float64Observable +} + +func (o float64Observer) Observe(val float64, opts ...metric.ObserveOption) { + c := metric.NewObserveConfig(opts) + o.observe(val, c.Attributes()) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go new file mode 100644 index 0000000000000..995d42b38f1b7 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/data.go @@ -0,0 +1,293 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metricdata // import "go.opentelemetry.io/otel/sdk/metric/metricdata" + +import ( + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/resource" +) + +// ResourceMetrics is a collection of ScopeMetrics and the associated Resource +// that created them. +type ResourceMetrics struct { + // Resource represents the entity that collected the metrics. + Resource *resource.Resource + // ScopeMetrics are the collection of metrics with unique Scopes. + ScopeMetrics []ScopeMetrics +} + +// ScopeMetrics is a collection of Metrics Produces by a Meter. +type ScopeMetrics struct { + // Scope is the Scope that the Meter was created with. + Scope instrumentation.Scope + // Metrics are a list of aggregations created by the Meter. + Metrics []Metrics +} + +// Metrics is a collection of one or more aggregated timeseries from an Instrument. +type Metrics struct { + // Name is the name of the Instrument that created this data. + Name string + // Description is the description of the Instrument, which can be used in documentation. + Description string + // Unit is the unit in which the Instrument reports. + Unit string + // Data is the aggregated data from an Instrument. + Data Aggregation +} + +// Aggregation is the store of data reported by an Instrument. +// It will be one of: Gauge, Sum, Histogram. +type Aggregation interface { + privateAggregation() +} + +// Gauge represents a measurement of the current value of an instrument. +type Gauge[N int64 | float64] struct { + // DataPoints are the individual aggregated measurements with unique + // Attributes. + DataPoints []DataPoint[N] +} + +func (Gauge[N]) privateAggregation() {} + +// Sum represents the sum of all measurements of values from an instrument. +type Sum[N int64 | float64] struct { + // DataPoints are the individual aggregated measurements with unique + // Attributes. + DataPoints []DataPoint[N] + // Temporality describes if the aggregation is reported as the change from the + // last report time, or the cumulative changes since a fixed start time. + Temporality Temporality + // IsMonotonic represents if this aggregation only increases or decreases. + IsMonotonic bool +} + +func (Sum[N]) privateAggregation() {} + +// DataPoint is a single data point in a timeseries. +type DataPoint[N int64 | float64] struct { + // Attributes is the set of key value pairs that uniquely identify the + // timeseries. + Attributes attribute.Set + // StartTime is when the timeseries was started. (optional) + StartTime time.Time `json:",omitempty"` + // Time is the time when the timeseries was recorded. (optional) + Time time.Time `json:",omitempty"` + // Value is the value of this data point. + Value N + + // Exemplars is the sampled Exemplars collected during the timeseries. + Exemplars []Exemplar[N] `json:",omitempty"` +} + +// Histogram represents the histogram of all measurements of values from an instrument. +type Histogram[N int64 | float64] struct { + // DataPoints are the individual aggregated measurements with unique + // Attributes. + DataPoints []HistogramDataPoint[N] + // Temporality describes if the aggregation is reported as the change from the + // last report time, or the cumulative changes since a fixed start time. + Temporality Temporality +} + +func (Histogram[N]) privateAggregation() {} + +// HistogramDataPoint is a single histogram data point in a timeseries. +type HistogramDataPoint[N int64 | float64] struct { + // Attributes is the set of key value pairs that uniquely identify the + // timeseries. + Attributes attribute.Set + // StartTime is when the timeseries was started. + StartTime time.Time + // Time is the time when the timeseries was recorded. + Time time.Time + + // Count is the number of updates this histogram has been calculated with. + Count uint64 + // Bounds are the upper bounds of the buckets of the histogram. Because the + // last boundary is +infinity this one is implied. + Bounds []float64 + // BucketCounts is the count of each of the buckets. + BucketCounts []uint64 + + // Min is the minimum value recorded. (optional) + Min Extrema[N] + // Max is the maximum value recorded. (optional) + Max Extrema[N] + // Sum is the sum of the values recorded. + Sum N + + // Exemplars is the sampled Exemplars collected during the timeseries. + Exemplars []Exemplar[N] `json:",omitempty"` +} + +// ExponentialHistogram represents the histogram of all measurements of values from an instrument. +type ExponentialHistogram[N int64 | float64] struct { + // DataPoints are the individual aggregated measurements with unique + // attributes. + DataPoints []ExponentialHistogramDataPoint[N] + // Temporality describes if the aggregation is reported as the change from the + // last report time, or the cumulative changes since a fixed start time. + Temporality Temporality +} + +func (ExponentialHistogram[N]) privateAggregation() {} + +// ExponentialHistogramDataPoint is a single exponential histogram data point in a timeseries. +type ExponentialHistogramDataPoint[N int64 | float64] struct { + // Attributes is the set of key value pairs that uniquely identify the + // timeseries. + Attributes attribute.Set + // StartTime is when the timeseries was started. + StartTime time.Time + // Time is the time when the timeseries was recorded. + Time time.Time + + // Count is the number of updates this histogram has been calculated with. + Count uint64 + // Min is the minimum value recorded. (optional) + Min Extrema[N] + // Max is the maximum value recorded. (optional) + Max Extrema[N] + // Sum is the sum of the values recorded. + Sum N + + // Scale describes the resolution of the histogram. Boundaries are + // located at powers of the base, where: + // + // base = 2 ^ (2 ^ -Scale) + Scale int32 + // ZeroCount is the number of values whose absolute value + // is less than or equal to [ZeroThreshold]. + // When ZeroThreshold is 0, this is the number of values that + // cannot be expressed using the standard exponential formula + // as well as values that have been rounded to zero. + // ZeroCount represents the special zero count bucket. + ZeroCount uint64 + + // PositiveBucket is range of positive value bucket counts. + PositiveBucket ExponentialBucket + // NegativeBucket is range of negative value bucket counts. + NegativeBucket ExponentialBucket + + // ZeroThreshold is the width of the zero region. Where the zero region is + // defined as the closed interval [-ZeroThreshold, ZeroThreshold]. + ZeroThreshold float64 + + // Exemplars is the sampled Exemplars collected during the timeseries. + Exemplars []Exemplar[N] `json:",omitempty"` +} + +// ExponentialBucket are a set of bucket counts, encoded in a contiguous array +// of counts. +type ExponentialBucket struct { + // Offset is the bucket index of the first entry in the Counts slice. + Offset int32 + // Counts is an slice where Counts[i] carries the count of the bucket at + // index (Offset+i). Counts[i] is the count of values greater than + // base^(Offset+i) and less than or equal to base^(Offset+i+1). + Counts []uint64 +} + +// Extrema is the minimum or maximum value of a dataset. +type Extrema[N int64 | float64] struct { + value N + valid bool +} + +// NewExtrema returns an Extrema set to v. +func NewExtrema[N int64 | float64](v N) Extrema[N] { + return Extrema[N]{value: v, valid: true} +} + +// Value returns the Extrema value and true if the Extrema is defined. +// Otherwise, if the Extrema is its zero-value, defined will be false. +func (e Extrema[N]) Value() (v N, defined bool) { + return e.value, e.valid +} + +// Exemplar is a measurement sampled from a timeseries providing a typical +// example. +type Exemplar[N int64 | float64] struct { + // FilteredAttributes are the attributes recorded with the measurement but + // filtered out of the timeseries' aggregated data. + FilteredAttributes []attribute.KeyValue + // Time is the time when the measurement was recorded. + Time time.Time + // Value is the measured value. + Value N + // SpanID is the ID of the span that was active during the measurement. If + // no span was active or the span was not sampled this will be empty. + SpanID []byte `json:",omitempty"` + // TraceID is the ID of the trace the active span belonged to during the + // measurement. If no span was active or the span was not sampled this will + // be empty. + TraceID []byte `json:",omitempty"` +} + +// Summary metric data are used to convey quantile summaries, +// a Prometheus (see: https://prometheus.io/docs/concepts/metric_types/#summary) +// data type. +// +// These data points cannot always be merged in a meaningful way. The Summary +// type is only used by bridges from other metrics libraries, and cannot be +// produced using OpenTelemetry instrumentation. +type Summary struct { + // DataPoints are the individual aggregated measurements with unique + // attributes. + DataPoints []SummaryDataPoint +} + +func (Summary) privateAggregation() {} + +// SummaryDataPoint is a single data point in a timeseries that describes the +// time-varying values of a Summary metric. +type SummaryDataPoint struct { + // Attributes is the set of key value pairs that uniquely identify the + // timeseries. + Attributes attribute.Set + + // StartTime is when the timeseries was started. + StartTime time.Time + // Time is the time when the timeseries was recorded. + Time time.Time + + // Count is the number of updates this summary has been calculated with. + Count uint64 + + // Sum is the sum of the values recorded. + Sum float64 + + // (Optional) list of values at different quantiles of the distribution calculated + // from the current snapshot. The quantiles must be strictly increasing. + QuantileValues []QuantileValue +} + +// QuantileValue is the value at a given quantile of a summary. +type QuantileValue struct { + // Quantile is the quantile of this value. + // + // Must be in the interval [0.0, 1.0]. + Quantile float64 + + // Value is the value at the given quantile of a summary. + // + // Quantile values must NOT be negative. + Value float64 +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality.go b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality.go new file mode 100644 index 0000000000000..9fceb18cba7ae --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality.go @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate stringer -type=Temporality + +package metricdata // import "go.opentelemetry.io/otel/sdk/metric/metricdata" + +// Temporality defines the window that an aggregation was calculated over. +type Temporality uint8 + +const ( + // undefinedTemporality represents an unset Temporality. + //nolint:deadcode,unused,varcheck + undefinedTemporality Temporality = iota + + // CumulativeTemporality defines a measurement interval that continues to + // expand forward in time from a starting point. New measurements are + // added to all previous measurements since a start time. + CumulativeTemporality + + // DeltaTemporality defines a measurement interval that resets each cycle. + // Measurements from one cycle are recorded independently, measurements + // from other cycles do not affect them. + DeltaTemporality +) + +// MarshalText returns the byte encoded of t. +func (t Temporality) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality_string.go b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality_string.go new file mode 100644 index 0000000000000..4da833cdce20c --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/temporality_string.go @@ -0,0 +1,25 @@ +// Code generated by "stringer -type=Temporality"; DO NOT EDIT. + +package metricdata + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[undefinedTemporality-0] + _ = x[CumulativeTemporality-1] + _ = x[DeltaTemporality-2] +} + +const _Temporality_name = "undefinedTemporalityCumulativeTemporalityDeltaTemporality" + +var _Temporality_index = [...]uint8{0, 20, 41, 57} + +func (i Temporality) String() string { + if i >= Temporality(len(_Temporality_index)-1) { + return "Temporality(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Temporality_name[_Temporality_index[i]:_Temporality_index[i+1]] +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go new file mode 100644 index 0000000000000..ff86999c75954 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/periodic_reader.go @@ -0,0 +1,381 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// Default periodic reader timing. +const ( + defaultTimeout = time.Millisecond * 30000 + defaultInterval = time.Millisecond * 60000 +) + +// periodicReaderConfig contains configuration options for a PeriodicReader. +type periodicReaderConfig struct { + interval time.Duration + timeout time.Duration + producers []Producer +} + +// newPeriodicReaderConfig returns a periodicReaderConfig configured with +// options. +func newPeriodicReaderConfig(options []PeriodicReaderOption) periodicReaderConfig { + c := periodicReaderConfig{ + interval: envDuration(envInterval, defaultInterval), + timeout: envDuration(envTimeout, defaultTimeout), + } + for _, o := range options { + c = o.applyPeriodic(c) + } + return c +} + +// PeriodicReaderOption applies a configuration option value to a PeriodicReader. +type PeriodicReaderOption interface { + applyPeriodic(periodicReaderConfig) periodicReaderConfig +} + +// periodicReaderOptionFunc applies a set of options to a periodicReaderConfig. +type periodicReaderOptionFunc func(periodicReaderConfig) periodicReaderConfig + +// applyPeriodic returns a periodicReaderConfig with option(s) applied. +func (o periodicReaderOptionFunc) applyPeriodic(conf periodicReaderConfig) periodicReaderConfig { + return o(conf) +} + +// WithTimeout configures the time a PeriodicReader waits for an export to +// complete before canceling it. This includes an export which occurs as part +// of Shutdown or ForceFlush if the user passed context does not have a +// deadline. If the user passed context does have a deadline, it will be used +// instead. +// +// This option overrides any value set for the +// OTEL_METRIC_EXPORT_TIMEOUT environment variable. +// +// If this option is not used or d is less than or equal to zero, 30 seconds +// is used as the default. +func WithTimeout(d time.Duration) PeriodicReaderOption { + return periodicReaderOptionFunc(func(conf periodicReaderConfig) periodicReaderConfig { + if d <= 0 { + return conf + } + conf.timeout = d + return conf + }) +} + +// WithInterval configures the intervening time between exports for a +// PeriodicReader. +// +// This option overrides any value set for the +// OTEL_METRIC_EXPORT_INTERVAL environment variable. +// +// If this option is not used or d is less than or equal to zero, 60 seconds +// is used as the default. +func WithInterval(d time.Duration) PeriodicReaderOption { + return periodicReaderOptionFunc(func(conf periodicReaderConfig) periodicReaderConfig { + if d <= 0 { + return conf + } + conf.interval = d + return conf + }) +} + +// NewPeriodicReader returns a Reader that collects and exports metric data to +// the exporter at a defined interval. By default, the returned Reader will +// collect and export data every 60 seconds, and will cancel any attempts that +// exceed 30 seconds, collect and export combined. The collect and export time +// are not counted towards the interval between attempts. +// +// The Collect method of the returned Reader continues to gather and return +// metric data to the user. It will not automatically send that data to the +// exporter. That is left to the user to accomplish. +func NewPeriodicReader(exporter Exporter, options ...PeriodicReaderOption) *PeriodicReader { + conf := newPeriodicReaderConfig(options) + ctx, cancel := context.WithCancel(context.Background()) + r := &PeriodicReader{ + interval: conf.interval, + timeout: conf.timeout, + exporter: exporter, + flushCh: make(chan chan error), + cancel: cancel, + done: make(chan struct{}), + rmPool: sync.Pool{ + New: func() interface{} { + return &metricdata.ResourceMetrics{} + }, + }, + } + r.externalProducers.Store(conf.producers) + + go func() { + defer func() { close(r.done) }() + r.run(ctx, conf.interval) + }() + + return r +} + +// PeriodicReader is a Reader that continuously collects and exports metric +// data at a set interval. +type PeriodicReader struct { + sdkProducer atomic.Value + + mu sync.Mutex + isShutdown bool + externalProducers atomic.Value + + interval time.Duration + timeout time.Duration + exporter Exporter + flushCh chan chan error + + done chan struct{} + cancel context.CancelFunc + shutdownOnce sync.Once + + rmPool sync.Pool +} + +// Compile time check the periodicReader implements Reader and is comparable. +var _ = map[Reader]struct{}{&PeriodicReader{}: {}} + +// newTicker allows testing override. +var newTicker = time.NewTicker + +// run continuously collects and exports metric data at the specified +// interval. This will run until ctx is canceled or times out. +func (r *PeriodicReader) run(ctx context.Context, interval time.Duration) { + ticker := newTicker(interval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + err := r.collectAndExport(ctx) + if err != nil { + otel.Handle(err) + } + case errCh := <-r.flushCh: + errCh <- r.collectAndExport(ctx) + ticker.Reset(interval) + case <-ctx.Done(): + return + } + } +} + +// register registers p as the producer of this reader. +func (r *PeriodicReader) register(p sdkProducer) { + // Only register once. If producer is already set, do nothing. + if !r.sdkProducer.CompareAndSwap(nil, produceHolder{produce: p.produce}) { + msg := "did not register periodic reader" + global.Error(errDuplicateRegister, msg) + } +} + +// temporality reports the Temporality for the instrument kind provided. +func (r *PeriodicReader) temporality(kind InstrumentKind) metricdata.Temporality { + return r.exporter.Temporality(kind) +} + +// aggregation returns what Aggregation to use for kind. +func (r *PeriodicReader) aggregation(kind InstrumentKind) Aggregation { // nolint:revive // import-shadow for method scoped by type. + return r.exporter.Aggregation(kind) +} + +// collectAndExport gather all metric data related to the periodicReader r from +// the SDK and exports it with r's exporter. +func (r *PeriodicReader) collectAndExport(ctx context.Context) error { + ctx, cancel := context.WithTimeout(ctx, r.timeout) + defer cancel() + + // TODO (#3047): Use a sync.Pool or persistent pointer instead of allocating rm every Collect. + rm := r.rmPool.Get().(*metricdata.ResourceMetrics) + err := r.Collect(ctx, rm) + if err == nil { + err = r.export(ctx, rm) + } + r.rmPool.Put(rm) + return err +} + +// Collect gathers all metric data related to the Reader from +// the SDK and other Producers and stores the result in rm. The metric +// data is not exported to the configured exporter, it is left to the caller to +// handle that if desired. +// +// Collect will return an error if called after shutdown. +// Collect will return an error if rm is a nil ResourceMetrics. +// Collect will return an error if the context's Done channel is closed. +// +// This method is safe to call concurrently. +func (r *PeriodicReader) Collect(ctx context.Context, rm *metricdata.ResourceMetrics) error { + if rm == nil { + return errors.New("periodic reader: *metricdata.ResourceMetrics is nil") + } + // TODO (#3047): When collect is updated to accept output as param, pass rm. + return r.collect(ctx, r.sdkProducer.Load(), rm) +} + +// collect unwraps p as a produceHolder and returns its produce results. +func (r *PeriodicReader) collect(ctx context.Context, p interface{}, rm *metricdata.ResourceMetrics) error { + if p == nil { + return ErrReaderNotRegistered + } + + ph, ok := p.(produceHolder) + if !ok { + // The atomic.Value is entirely in the periodicReader's control so + // this should never happen. In the unforeseen case that this does + // happen, return an error instead of panicking so a users code does + // not halt in the processes. + err := fmt.Errorf("periodic reader: invalid producer: %T", p) + return err + } + + err := ph.produce(ctx, rm) + if err != nil { + return err + } + var errs []error + for _, producer := range r.externalProducers.Load().([]Producer) { + externalMetrics, err := producer.Produce(ctx) + if err != nil { + errs = append(errs, err) + } + rm.ScopeMetrics = append(rm.ScopeMetrics, externalMetrics...) + } + + global.Debug("PeriodicReader collection", "Data", rm) + + return unifyErrors(errs) +} + +// export exports metric data m using r's exporter. +func (r *PeriodicReader) export(ctx context.Context, m *metricdata.ResourceMetrics) error { + return r.exporter.Export(ctx, m) +} + +// ForceFlush flushes pending telemetry. +// +// This method is safe to call concurrently. +func (r *PeriodicReader) ForceFlush(ctx context.Context) error { + // Prioritize the ctx timeout if it is set. + if _, ok := ctx.Deadline(); !ok { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, r.timeout) + defer cancel() + } + + errCh := make(chan error, 1) + select { + case r.flushCh <- errCh: + select { + case err := <-errCh: + if err != nil { + return err + } + close(errCh) + case <-ctx.Done(): + return ctx.Err() + } + case <-r.done: + return ErrReaderShutdown + case <-ctx.Done(): + return ctx.Err() + } + return r.exporter.ForceFlush(ctx) +} + +// Shutdown flushes pending telemetry and then stops the export pipeline. +// +// This method is safe to call concurrently. +func (r *PeriodicReader) Shutdown(ctx context.Context) error { + err := ErrReaderShutdown + r.shutdownOnce.Do(func() { + // Prioritize the ctx timeout if it is set. + if _, ok := ctx.Deadline(); !ok { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, r.timeout) + defer cancel() + } + + // Stop the run loop. + r.cancel() + <-r.done + + // Any future call to Collect will now return ErrReaderShutdown. + ph := r.sdkProducer.Swap(produceHolder{ + produce: shutdownProducer{}.produce, + }) + + if ph != nil { // Reader was registered. + // Flush pending telemetry. + m := r.rmPool.Get().(*metricdata.ResourceMetrics) + err = r.collect(ctx, ph, m) + if err == nil { + err = r.export(ctx, m) + } + r.rmPool.Put(m) + } + + sErr := r.exporter.Shutdown(ctx) + if err == nil || err == ErrReaderShutdown { + err = sErr + } + + r.mu.Lock() + defer r.mu.Unlock() + r.isShutdown = true + // release references to Producer(s) + r.externalProducers.Store([]Producer{}) + }) + return err +} + +// MarshalLog returns logging data about the PeriodicReader. +func (r *PeriodicReader) MarshalLog() interface{} { + r.mu.Lock() + down := r.isShutdown + r.mu.Unlock() + return struct { + Type string + Exporter Exporter + Registered bool + Shutdown bool + Interval time.Duration + Timeout time.Duration + }{ + Type: "PeriodicReader", + Exporter: r.exporter, + Registered: r.sdkProducer.Load() != nil, + Shutdown: down, + Interval: r.interval, + Timeout: r.timeout, + } +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go new file mode 100644 index 0000000000000..48abcc8a7f35e --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/pipeline.go @@ -0,0 +1,656 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "container/list" + "context" + "errors" + "fmt" + "strings" + "sync" + "sync/atomic" + + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" + "go.opentelemetry.io/otel/sdk/instrumentation" + "go.opentelemetry.io/otel/sdk/metric/internal" + "go.opentelemetry.io/otel/sdk/metric/internal/aggregate" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/resource" +) + +var ( + errCreatingAggregators = errors.New("could not create all aggregators") + errIncompatibleAggregation = errors.New("incompatible aggregation") + errUnknownAggregation = errors.New("unrecognized aggregation") +) + +// instrumentSync is a synchronization point between a pipeline and an +// instrument's aggregate function. +type instrumentSync struct { + name string + description string + unit string + compAgg aggregate.ComputeAggregation +} + +func newPipeline(res *resource.Resource, reader Reader, views []View) *pipeline { + if res == nil { + res = resource.Empty() + } + return &pipeline{ + resource: res, + reader: reader, + views: views, + // aggregations is lazy allocated when needed. + } +} + +// pipeline connects all of the instruments created by a meter provider to a Reader. +// This is the object that will be `Reader.register()` when a meter provider is created. +// +// As instruments are created the instrument should be checked if it exists in +// the views of a the Reader, and if so each aggregate function should be added +// to the pipeline. +type pipeline struct { + resource *resource.Resource + + reader Reader + views []View + + sync.Mutex + aggregations map[instrumentation.Scope][]instrumentSync + callbacks []func(context.Context) error + multiCallbacks list.List +} + +// addSync adds the instrumentSync to pipeline p with scope. This method is not +// idempotent. Duplicate calls will result in duplicate additions, it is the +// callers responsibility to ensure this is called with unique values. +func (p *pipeline) addSync(scope instrumentation.Scope, iSync instrumentSync) { + p.Lock() + defer p.Unlock() + if p.aggregations == nil { + p.aggregations = map[instrumentation.Scope][]instrumentSync{ + scope: {iSync}, + } + return + } + p.aggregations[scope] = append(p.aggregations[scope], iSync) +} + +// addCallback registers a single instrument callback to be run when +// `produce()` is called. +func (p *pipeline) addCallback(cback func(context.Context) error) { + p.Lock() + defer p.Unlock() + p.callbacks = append(p.callbacks, cback) +} + +type multiCallback func(context.Context) error + +// addMultiCallback registers a multi-instrument callback to be run when +// `produce()` is called. +func (p *pipeline) addMultiCallback(c multiCallback) (unregister func()) { + p.Lock() + defer p.Unlock() + e := p.multiCallbacks.PushBack(c) + return func() { + p.Lock() + p.multiCallbacks.Remove(e) + p.Unlock() + } +} + +// produce returns aggregated metrics from a single collection. +// +// This method is safe to call concurrently. +func (p *pipeline) produce(ctx context.Context, rm *metricdata.ResourceMetrics) error { + p.Lock() + defer p.Unlock() + + var errs multierror + for _, c := range p.callbacks { + // TODO make the callbacks parallel. ( #3034 ) + if err := c(ctx); err != nil { + errs.append(err) + } + if err := ctx.Err(); err != nil { + rm.Resource = nil + rm.ScopeMetrics = rm.ScopeMetrics[:0] + return err + } + } + for e := p.multiCallbacks.Front(); e != nil; e = e.Next() { + // TODO make the callbacks parallel. ( #3034 ) + f := e.Value.(multiCallback) + if err := f(ctx); err != nil { + errs.append(err) + } + if err := ctx.Err(); err != nil { + // This means the context expired before we finished running callbacks. + rm.Resource = nil + rm.ScopeMetrics = rm.ScopeMetrics[:0] + return err + } + } + + rm.Resource = p.resource + rm.ScopeMetrics = internal.ReuseSlice(rm.ScopeMetrics, len(p.aggregations)) + + i := 0 + for scope, instruments := range p.aggregations { + rm.ScopeMetrics[i].Metrics = internal.ReuseSlice(rm.ScopeMetrics[i].Metrics, len(instruments)) + j := 0 + for _, inst := range instruments { + data := rm.ScopeMetrics[i].Metrics[j].Data + if n := inst.compAgg(&data); n > 0 { + rm.ScopeMetrics[i].Metrics[j].Name = inst.name + rm.ScopeMetrics[i].Metrics[j].Description = inst.description + rm.ScopeMetrics[i].Metrics[j].Unit = inst.unit + rm.ScopeMetrics[i].Metrics[j].Data = data + j++ + } + } + rm.ScopeMetrics[i].Metrics = rm.ScopeMetrics[i].Metrics[:j] + if len(rm.ScopeMetrics[i].Metrics) > 0 { + rm.ScopeMetrics[i].Scope = scope + i++ + } + } + + rm.ScopeMetrics = rm.ScopeMetrics[:i] + + return errs.errorOrNil() +} + +// inserter facilitates inserting of new instruments from a single scope into a +// pipeline. +type inserter[N int64 | float64] struct { + // aggregators is a cache that holds aggregate function inputs whose + // outputs have been inserted into the underlying reader pipeline. This + // cache ensures no duplicate aggregate functions are inserted into the + // reader pipeline and if a new request during an instrument creation asks + // for the same aggregate function input the same instance is returned. + aggregators *cache[instID, aggVal[N]] + + // views is a cache that holds instrument identifiers for all the + // instruments a Meter has created, it is provided from the Meter that owns + // this inserter. This cache ensures during the creation of instruments + // with the same name but different options (e.g. description, unit) a + // warning message is logged. + views *cache[string, instID] + + pipeline *pipeline +} + +func newInserter[N int64 | float64](p *pipeline, vc *cache[string, instID]) *inserter[N] { + if vc == nil { + vc = &cache[string, instID]{} + } + return &inserter[N]{ + aggregators: &cache[instID, aggVal[N]]{}, + views: vc, + pipeline: p, + } +} + +// Instrument inserts the instrument inst with instUnit into a pipeline. All +// views the pipeline contains are matched against, and any matching view that +// creates a unique aggregate function will have its output inserted into the +// pipeline and its input included in the returned slice. +// +// The returned aggregate function inputs are ensured to be deduplicated and +// unique. If another view in another pipeline that is cached by this +// inserter's cache has already inserted the same aggregate function for the +// same instrument, that functions input instance is returned. +// +// If another instrument has already been inserted by this inserter, or any +// other using the same cache, and it conflicts with the instrument being +// inserted in this call, an aggregate function input matching the arguments +// will still be returned but an Info level log message will also be logged to +// the OTel global logger. +// +// If the passed instrument would result in an incompatible aggregate function, +// an error is returned and that aggregate function output is not inserted nor +// is its input returned. +// +// If an instrument is determined to use a Drop aggregation, that instrument is +// not inserted nor returned. +func (i *inserter[N]) Instrument(inst Instrument, readerAggregation Aggregation) ([]aggregate.Measure[N], error) { + var ( + matched bool + measures []aggregate.Measure[N] + ) + + errs := &multierror{wrapped: errCreatingAggregators} + seen := make(map[uint64]struct{}) + for _, v := range i.pipeline.views { + stream, match := v(inst) + if !match { + continue + } + matched = true + in, id, err := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation) + if err != nil { + errs.append(err) + } + if in == nil { // Drop aggregation. + continue + } + if _, ok := seen[id]; ok { + // This aggregate function has already been added. + continue + } + seen[id] = struct{}{} + measures = append(measures, in) + } + + if matched { + return measures, errs.errorOrNil() + } + + // Apply implicit default view if no explicit matched. + stream := Stream{ + Name: inst.Name, + Description: inst.Description, + Unit: inst.Unit, + } + in, _, err := i.cachedAggregator(inst.Scope, inst.Kind, stream, readerAggregation) + if err != nil { + errs.append(err) + } + if in != nil { + // Ensured to have not seen given matched was false. + measures = append(measures, in) + } + return measures, errs.errorOrNil() +} + +var aggIDCount uint64 + +// aggVal is the cached value in an aggregators cache. +type aggVal[N int64 | float64] struct { + ID uint64 + Measure aggregate.Measure[N] + Err error +} + +// readerDefaultAggregation returns the default aggregation for the instrument +// kind based on the reader's aggregation preferences. This is used unless the +// aggregation is overridden with a view. +func (i *inserter[N]) readerDefaultAggregation(kind InstrumentKind) Aggregation { + aggregation := i.pipeline.reader.aggregation(kind) + switch aggregation.(type) { + case nil, AggregationDefault: + // If the reader returns default or nil use the default selector. + aggregation = DefaultAggregationSelector(kind) + default: + // Deep copy and validate before using. + aggregation = aggregation.copy() + if err := aggregation.err(); err != nil { + orig := aggregation + aggregation = DefaultAggregationSelector(kind) + global.Error( + err, "using default aggregation instead", + "aggregation", orig, + "replacement", aggregation, + ) + } + } + return aggregation +} + +// cachedAggregator returns the appropriate aggregate input and output +// functions for an instrument configuration. If the exact instrument has been +// created within the inst.Scope, those aggregate function instances will be +// returned. Otherwise, new computed aggregate functions will be cached and +// returned. +// +// If the instrument configuration conflicts with an instrument that has +// already been created (e.g. description, unit, data type) a warning will be +// logged at the "Info" level with the global OTel logger. Valid new aggregate +// functions for the instrument configuration will still be returned without an +// error. +// +// If the instrument defines an unknown or incompatible aggregation, an error +// is returned. +func (i *inserter[N]) cachedAggregator(scope instrumentation.Scope, kind InstrumentKind, stream Stream, readerAggregation Aggregation) (meas aggregate.Measure[N], aggID uint64, err error) { + switch stream.Aggregation.(type) { + case nil: + // The aggregation was not overridden with a view. Use the aggregation + // provided by the reader. + stream.Aggregation = readerAggregation + case AggregationDefault: + // The view explicitly requested the default aggregation. + stream.Aggregation = DefaultAggregationSelector(kind) + } + + if err := isAggregatorCompatible(kind, stream.Aggregation); err != nil { + return nil, 0, fmt.Errorf( + "creating aggregator with instrumentKind: %d, aggregation %v: %w", + kind, stream.Aggregation, err, + ) + } + + id := i.instID(kind, stream) + // If there is a conflict, the specification says the view should + // still be applied and a warning should be logged. + i.logConflict(id) + + // If there are requests for the same instrument with different name + // casing, the first-seen needs to be returned. Use a normalize ID for the + // cache lookup to ensure the correct comparison. + normID := id.normalize() + cv := i.aggregators.Lookup(normID, func() aggVal[N] { + b := aggregate.Builder[N]{ + Temporality: i.pipeline.reader.temporality(kind), + } + b.Filter = stream.AttributeFilter + in, out, err := i.aggregateFunc(b, stream.Aggregation, kind) + if err != nil { + return aggVal[N]{0, nil, err} + } + if in == nil { // Drop aggregator. + return aggVal[N]{0, nil, nil} + } + i.pipeline.addSync(scope, instrumentSync{ + // Use the first-seen name casing for this and all subsequent + // requests of this instrument. + name: stream.Name, + description: stream.Description, + unit: stream.Unit, + compAgg: out, + }) + id := atomic.AddUint64(&aggIDCount, 1) + return aggVal[N]{id, in, err} + }) + return cv.Measure, cv.ID, cv.Err +} + +// logConflict validates if an instrument with the same case-insensitive name +// as id has already been created. If that instrument conflicts with id, a +// warning is logged. +func (i *inserter[N]) logConflict(id instID) { + // The API specification defines names as case-insensitive. If there is a + // different casing of a name it needs to be a conflict. + name := id.normalize().Name + existing := i.views.Lookup(name, func() instID { return id }) + if id == existing { + return + } + + const msg = "duplicate metric stream definitions" + args := []interface{}{ + "names", fmt.Sprintf("%q, %q", existing.Name, id.Name), + "descriptions", fmt.Sprintf("%q, %q", existing.Description, id.Description), + "kinds", fmt.Sprintf("%s, %s", existing.Kind, id.Kind), + "units", fmt.Sprintf("%s, %s", existing.Unit, id.Unit), + "numbers", fmt.Sprintf("%s, %s", existing.Number, id.Number), + } + + // The specification recommends logging a suggested view to resolve + // conflicts if possible. + // + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/metrics/sdk.md#duplicate-instrument-registration + if id.Unit != existing.Unit || id.Number != existing.Number { + // There is no view resolution for these, don't make a suggestion. + global.Warn(msg, args...) + return + } + + var stream string + if id.Name != existing.Name || id.Kind != existing.Kind { + stream = `Stream{Name: "{{NEW_NAME}}"}` + } else if id.Description != existing.Description { + stream = fmt.Sprintf("Stream{Description: %q}", existing.Description) + } + + inst := fmt.Sprintf( + "Instrument{Name: %q, Description: %q, Kind: %q, Unit: %q}", + id.Name, id.Description, "InstrumentKind"+id.Kind.String(), id.Unit, + ) + args = append(args, "suggested.view", fmt.Sprintf("NewView(%s, %s)", inst, stream)) + + global.Warn(msg, args...) +} + +func (i *inserter[N]) instID(kind InstrumentKind, stream Stream) instID { + var zero N + return instID{ + Name: stream.Name, + Description: stream.Description, + Unit: stream.Unit, + Kind: kind, + Number: fmt.Sprintf("%T", zero), + } +} + +// aggregateFunc returns new aggregate functions matching agg, kind, and +// monotonic. If the agg is unknown or temporality is invalid, an error is +// returned. +func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kind InstrumentKind) (meas aggregate.Measure[N], comp aggregate.ComputeAggregation, err error) { + switch a := agg.(type) { + case AggregationDefault: + return i.aggregateFunc(b, DefaultAggregationSelector(kind), kind) + case AggregationDrop: + // Return nil in and out to signify the drop aggregator. + case AggregationLastValue: + meas, comp = b.LastValue() + case AggregationSum: + switch kind { + case InstrumentKindObservableCounter: + meas, comp = b.PrecomputedSum(true) + case InstrumentKindObservableUpDownCounter: + meas, comp = b.PrecomputedSum(false) + case InstrumentKindCounter, InstrumentKindHistogram: + meas, comp = b.Sum(true) + default: + // InstrumentKindUpDownCounter, InstrumentKindObservableGauge, and + // instrumentKindUndefined or other invalid instrument kinds. + meas, comp = b.Sum(false) + } + case AggregationExplicitBucketHistogram: + var noSum bool + switch kind { + case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge: + // The sum should not be collected for any instrument that can make + // negative measurements: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/metrics/sdk.md#histogram-aggregations + noSum = true + } + meas, comp = b.ExplicitBucketHistogram(a.Boundaries, a.NoMinMax, noSum) + case AggregationBase2ExponentialHistogram: + var noSum bool + switch kind { + case InstrumentKindUpDownCounter, InstrumentKindObservableUpDownCounter, InstrumentKindObservableGauge: + // The sum should not be collected for any instrument that can make + // negative measurements: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/metrics/sdk.md#histogram-aggregations + noSum = true + } + meas, comp = b.ExponentialBucketHistogram(a.MaxSize, a.MaxScale, a.NoMinMax, noSum) + + default: + err = errUnknownAggregation + } + + return meas, comp, err +} + +// isAggregatorCompatible checks if the aggregation can be used by the instrument. +// Current compatibility: +// +// | Instrument Kind | Drop | LastValue | Sum | Histogram | Exponential Histogram | +// |--------------------------|------|-----------|-----|-----------|-----------------------| +// | Counter | ✓ | | ✓ | ✓ | ✓ | +// | UpDownCounter | ✓ | | ✓ | ✓ | ✓ | +// | Histogram | ✓ | | ✓ | ✓ | ✓ | +// | Observable Counter | ✓ | | ✓ | ✓ | ✓ | +// | Observable UpDownCounter | ✓ | | ✓ | ✓ | ✓ | +// | Observable Gauge | ✓ | ✓ | | ✓ | ✓ |. +func isAggregatorCompatible(kind InstrumentKind, agg Aggregation) error { + switch agg.(type) { + case AggregationDefault: + return nil + case AggregationExplicitBucketHistogram, AggregationBase2ExponentialHistogram: + switch kind { + case InstrumentKindCounter, + InstrumentKindUpDownCounter, + InstrumentKindHistogram, + InstrumentKindObservableCounter, + InstrumentKindObservableUpDownCounter, + InstrumentKindObservableGauge: + return nil + default: + return errIncompatibleAggregation + } + case AggregationSum: + switch kind { + case InstrumentKindObservableCounter, InstrumentKindObservableUpDownCounter, InstrumentKindCounter, InstrumentKindHistogram, InstrumentKindUpDownCounter: + return nil + default: + // TODO: review need for aggregation check after + // https://github.com/open-telemetry/opentelemetry-specification/issues/2710 + return errIncompatibleAggregation + } + case AggregationLastValue: + if kind == InstrumentKindObservableGauge { + return nil + } + // TODO: review need for aggregation check after + // https://github.com/open-telemetry/opentelemetry-specification/issues/2710 + return errIncompatibleAggregation + case AggregationDrop: + return nil + default: + // This is used passed checking for default, it should be an error at this point. + return fmt.Errorf("%w: %v", errUnknownAggregation, agg) + } +} + +// pipelines is the group of pipelines connecting Readers with instrument +// measurement. +type pipelines []*pipeline + +func newPipelines(res *resource.Resource, readers []Reader, views []View) pipelines { + pipes := make([]*pipeline, 0, len(readers)) + for _, r := range readers { + p := newPipeline(res, r, views) + r.register(p) + pipes = append(pipes, p) + } + return pipes +} + +func (p pipelines) registerCallback(cback func(context.Context) error) { + for _, pipe := range p { + pipe.addCallback(cback) + } +} + +func (p pipelines) registerMultiCallback(c multiCallback) metric.Registration { + unregs := make([]func(), len(p)) + for i, pipe := range p { + unregs[i] = pipe.addMultiCallback(c) + } + return unregisterFuncs{f: unregs} +} + +type unregisterFuncs struct { + embedded.Registration + f []func() +} + +func (u unregisterFuncs) Unregister() error { + for _, f := range u.f { + f() + } + return nil +} + +// resolver facilitates resolving aggregate functions an instrument calls to +// aggregate measurements with while updating all pipelines that need to pull +// from those aggregations. +type resolver[N int64 | float64] struct { + inserters []*inserter[N] +} + +func newResolver[N int64 | float64](p pipelines, vc *cache[string, instID]) resolver[N] { + in := make([]*inserter[N], len(p)) + for i := range in { + in[i] = newInserter[N](p[i], vc) + } + return resolver[N]{in} +} + +// Aggregators returns the Aggregators that must be updated by the instrument +// defined by key. +func (r resolver[N]) Aggregators(id Instrument) ([]aggregate.Measure[N], error) { + var measures []aggregate.Measure[N] + + errs := &multierror{} + for _, i := range r.inserters { + in, err := i.Instrument(id, i.readerDefaultAggregation(id.Kind)) + if err != nil { + errs.append(err) + } + measures = append(measures, in...) + } + return measures, errs.errorOrNil() +} + +// HistogramAggregators returns the histogram Aggregators that must be updated by the instrument +// defined by key. If boundaries were provided on instrument instantiation, those take precedence +// over boundaries provided by the reader. +func (r resolver[N]) HistogramAggregators(id Instrument, boundaries []float64) ([]aggregate.Measure[N], error) { + var measures []aggregate.Measure[N] + + errs := &multierror{} + for _, i := range r.inserters { + agg := i.readerDefaultAggregation(id.Kind) + if histAgg, ok := agg.(AggregationExplicitBucketHistogram); ok && len(boundaries) > 0 { + histAgg.Boundaries = boundaries + agg = histAgg + } + in, err := i.Instrument(id, agg) + if err != nil { + errs.append(err) + } + measures = append(measures, in...) + } + return measures, errs.errorOrNil() +} + +type multierror struct { + wrapped error + errors []string +} + +func (m *multierror) errorOrNil() error { + if len(m.errors) == 0 { + return nil + } + if m.wrapped == nil { + return errors.New(strings.Join(m.errors, "; ")) + } + return fmt.Errorf("%w: %s", m.wrapped, strings.Join(m.errors, "; ")) +} + +func (m *multierror) append(err error) { + m.errors = append(m.errors, err.Error()) +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go new file mode 100644 index 0000000000000..7d1a9183ce126 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/provider.go @@ -0,0 +1,154 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "sync/atomic" + + "go.opentelemetry.io/otel/internal/global" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" + "go.opentelemetry.io/otel/metric/noop" + "go.opentelemetry.io/otel/sdk/instrumentation" +) + +// MeterProvider handles the creation and coordination of Meters. All Meters +// created by a MeterProvider will be associated with the same Resource, have +// the same Views applied to them, and have their produced metric telemetry +// passed to the configured Readers. +type MeterProvider struct { + embedded.MeterProvider + + pipes pipelines + meters cache[instrumentation.Scope, *meter] + + forceFlush, shutdown func(context.Context) error + stopped atomic.Bool +} + +// Compile-time check MeterProvider implements metric.MeterProvider. +var _ metric.MeterProvider = (*MeterProvider)(nil) + +// NewMeterProvider returns a new and configured MeterProvider. +// +// By default, the returned MeterProvider is configured with the default +// Resource and no Readers. Readers cannot be added after a MeterProvider is +// created. This means the returned MeterProvider, one created with no +// Readers, will perform no operations. +func NewMeterProvider(options ...Option) *MeterProvider { + conf := newConfig(options) + flush, sdown := conf.readerSignals() + + mp := &MeterProvider{ + pipes: newPipelines(conf.res, conf.readers, conf.views), + forceFlush: flush, + shutdown: sdown, + } + // Log after creation so all readers show correctly they are registered. + global.Info("MeterProvider created", + "Resource", conf.res, + "Readers", conf.readers, + "Views", len(conf.views), + ) + return mp +} + +// Meter returns a Meter with the given name and configured with options. +// +// The name should be the name of the instrumentation scope creating +// telemetry. This name may be the same as the instrumented code only if that +// code provides built-in instrumentation. +// +// Calls to the Meter method after Shutdown has been called will return Meters +// that perform no operations. +// +// This method is safe to call concurrently. +func (mp *MeterProvider) Meter(name string, options ...metric.MeterOption) metric.Meter { + if name == "" { + global.Warn("Invalid Meter name.", "name", name) + } + + if mp.stopped.Load() { + return noop.Meter{} + } + + c := metric.NewMeterConfig(options...) + s := instrumentation.Scope{ + Name: name, + Version: c.InstrumentationVersion(), + SchemaURL: c.SchemaURL(), + } + + global.Info("Meter created", + "Name", s.Name, + "Version", s.Version, + "SchemaURL", s.SchemaURL, + ) + + return mp.meters.Lookup(s, func() *meter { + return newMeter(s, mp.pipes) + }) +} + +// ForceFlush flushes all pending telemetry. +// +// This method honors the deadline or cancellation of ctx. An appropriate +// error will be returned in these situations. There is no guaranteed that all +// telemetry be flushed or all resources have been released in these +// situations. +// +// ForceFlush calls ForceFlush(context.Context) error +// on all Readers that implements this method. +// +// This method is safe to call concurrently. +func (mp *MeterProvider) ForceFlush(ctx context.Context) error { + if mp.forceFlush != nil { + return mp.forceFlush(ctx) + } + return nil +} + +// Shutdown shuts down the MeterProvider flushing all pending telemetry and +// releasing any held computational resources. +// +// This call is idempotent. The first call will perform all flush and +// releasing operations. Subsequent calls will perform no action and will +// return an error stating this. +// +// Measurements made by instruments from meters this MeterProvider created +// will not be exported after Shutdown is called. +// +// This method honors the deadline or cancellation of ctx. An appropriate +// error will be returned in these situations. There is no guaranteed that all +// telemetry be flushed or all resources have been released in these +// situations. +// +// This method is safe to call concurrently. +func (mp *MeterProvider) Shutdown(ctx context.Context) error { + // Even though it may seem like there is a synchronization issue between the + // call to `Store` and checking `shutdown`, the Go concurrency model ensures + // that is not the case, as all the atomic operations executed in a program + // behave as though executed in some sequentially consistent order. This + // definition provides the same semantics as C++'s sequentially consistent + // atomics and Java's volatile variables. + // See https://go.dev/ref/mem#atomic and https://pkg.go.dev/sync/atomic. + + mp.stopped.Store(true) + if mp.shutdown != nil { + return mp.shutdown(ctx) + } + return nil +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go b/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go new file mode 100644 index 0000000000000..65cedaf3c0752 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/reader.go @@ -0,0 +1,200 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "context" + "fmt" + + "go.opentelemetry.io/otel/sdk/metric/metricdata" +) + +// errDuplicateRegister is logged by a Reader when an attempt to registered it +// more than once occurs. +var errDuplicateRegister = fmt.Errorf("duplicate reader registration") + +// ErrReaderNotRegistered is returned if Collect or Shutdown are called before +// the reader is registered with a MeterProvider. +var ErrReaderNotRegistered = fmt.Errorf("reader is not registered") + +// ErrReaderShutdown is returned if Collect or Shutdown are called after a +// reader has been Shutdown once. +var ErrReaderShutdown = fmt.Errorf("reader is shutdown") + +// errNonPositiveDuration is logged when an environmental variable +// has non-positive value. +var errNonPositiveDuration = fmt.Errorf("non-positive duration") + +// Reader is the interface used between the SDK and an +// exporter. Control flow is bi-directional through the +// Reader, since the SDK initiates ForceFlush and Shutdown +// while the exporter initiates collection. The Register() method here +// informs the Reader that it can begin reading, signaling the +// start of bi-directional control flow. +// +// Typically, push-based exporters that are periodic will +// implement PeroidicExporter themselves and construct a +// PeriodicReader to satisfy this interface. +// +// Pull-based exporters will typically implement Register +// themselves, since they read on demand. +// +// Warning: methods may be added to this interface in minor releases. +type Reader interface { + // register registers a Reader with a MeterProvider. + // The producer argument allows the Reader to signal the sdk to collect + // and send aggregated metric measurements. + register(sdkProducer) + + // temporality reports the Temporality for the instrument kind provided. + // + // This method needs to be concurrent safe with itself and all the other + // Reader methods. + temporality(InstrumentKind) metricdata.Temporality + + // aggregation returns what Aggregation to use for an instrument kind. + // + // This method needs to be concurrent safe with itself and all the other + // Reader methods. + aggregation(InstrumentKind) Aggregation // nolint:revive // import-shadow for method scoped by type. + + // Collect gathers and returns all metric data related to the Reader from + // the SDK and stores it in out. An error is returned if this is called + // after Shutdown or if out is nil. + // + // This method needs to be concurrent safe, and the cancellation of the + // passed context is expected to be honored. + Collect(ctx context.Context, rm *metricdata.ResourceMetrics) error + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // Shutdown flushes all metric measurements held in an export pipeline and releases any + // held computational resources. + // + // This deadline or cancellation of the passed context are honored. An appropriate + // error will be returned in these situations. There is no guaranteed that all + // telemetry be flushed or all resources have been released in these + // situations. + // + // After Shutdown is called, calls to Collect will perform no operation and instead will return + // an error indicating the shutdown state. + // + // This method needs to be concurrent safe. + Shutdown(context.Context) error + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. +} + +// sdkProducer produces metrics for a Reader. +type sdkProducer interface { + // produce returns aggregated metrics from a single collection. + // + // This method is safe to call concurrently. + produce(context.Context, *metricdata.ResourceMetrics) error +} + +// Producer produces metrics for a Reader from an external source. +type Producer interface { + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. + + // Produce returns aggregated metrics from an external source. + // + // This method should be safe to call concurrently. + Produce(context.Context) ([]metricdata.ScopeMetrics, error) + // DO NOT CHANGE: any modification will not be backwards compatible and + // must never be done outside of a new major release. +} + +// produceHolder is used as an atomic.Value to wrap the non-concrete producer +// type. +type produceHolder struct { + produce func(context.Context, *metricdata.ResourceMetrics) error +} + +// shutdownProducer produces an ErrReaderShutdown error always. +type shutdownProducer struct{} + +// produce returns an ErrReaderShutdown error. +func (p shutdownProducer) produce(context.Context, *metricdata.ResourceMetrics) error { + return ErrReaderShutdown +} + +// TemporalitySelector selects the temporality to use based on the InstrumentKind. +type TemporalitySelector func(InstrumentKind) metricdata.Temporality + +// DefaultTemporalitySelector is the default TemporalitySelector used if +// WithTemporalitySelector is not provided. CumulativeTemporality will be used +// for all instrument kinds if this TemporalitySelector is used. +func DefaultTemporalitySelector(InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality +} + +// AggregationSelector selects the aggregation and the parameters to use for +// that aggregation based on the InstrumentKind. +// +// If the Aggregation returned is nil or DefaultAggregation, the selection from +// DefaultAggregationSelector will be used. +type AggregationSelector func(InstrumentKind) Aggregation + +// DefaultAggregationSelector returns the default aggregation and parameters +// that will be used to summarize measurement made from an instrument of +// InstrumentKind. This AggregationSelector using the following selection +// mapping: Counter ⇨ Sum, Observable Counter ⇨ Sum, UpDownCounter ⇨ Sum, +// Observable UpDownCounter ⇨ Sum, Observable Gauge ⇨ LastValue, +// Histogram ⇨ ExplicitBucketHistogram. +func DefaultAggregationSelector(ik InstrumentKind) Aggregation { + switch ik { + case InstrumentKindCounter, InstrumentKindUpDownCounter, InstrumentKindObservableCounter, InstrumentKindObservableUpDownCounter: + return AggregationSum{} + case InstrumentKindObservableGauge: + return AggregationLastValue{} + case InstrumentKindHistogram: + return AggregationExplicitBucketHistogram{ + Boundaries: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}, + NoMinMax: false, + } + } + panic("unknown instrument kind") +} + +// ReaderOption is an option which can be applied to manual or Periodic +// readers. +type ReaderOption interface { + PeriodicReaderOption + ManualReaderOption +} + +// WithProducers registers producers as an external Producer of metric data +// for this Reader. +func WithProducer(p Producer) ReaderOption { + return producerOption{p: p} +} + +type producerOption struct { + p Producer +} + +// applyManual returns a manualReaderConfig with option applied. +func (o producerOption) applyManual(c manualReaderConfig) manualReaderConfig { + c.producers = append(c.producers, o.p) + return c +} + +// applyPeriodic returns a periodicReaderConfig with option applied. +func (o producerOption) applyPeriodic(c periodicReaderConfig) periodicReaderConfig { + c.producers = append(c.producers, o.p) + return c +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/version.go b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go new file mode 100644 index 0000000000000..edcf7cfc86266 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/version.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +// version is the current release version of the metric SDK in use. +func version() string { + return "1.21.0" +} diff --git a/vendor/go.opentelemetry.io/otel/sdk/metric/view.go b/vendor/go.opentelemetry.io/otel/sdk/metric/view.go new file mode 100644 index 0000000000000..65f243befed89 --- /dev/null +++ b/vendor/go.opentelemetry.io/otel/sdk/metric/view.go @@ -0,0 +1,128 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric // import "go.opentelemetry.io/otel/sdk/metric" + +import ( + "errors" + "regexp" + "strings" + + "go.opentelemetry.io/otel/internal/global" +) + +var ( + errMultiInst = errors.New("name replacement for multiple instruments") + errEmptyView = errors.New("no criteria provided for view") + + emptyView = func(Instrument) (Stream, bool) { return Stream{}, false } +) + +// View is an override to the default behavior of the SDK. It defines how data +// should be collected for certain instruments. It returns true and the exact +// Stream to use for matching Instruments. Otherwise, if the view does not +// match, false is returned. +type View func(Instrument) (Stream, bool) + +// NewView returns a View that applies the Stream mask for all instruments that +// match criteria. The returned View will only apply mask if all non-zero-value +// fields of criteria match the corresponding Instrument passed to the view. If +// no criteria are provided, all field of criteria are their zero-values, a +// view that matches no instruments is returned. If you need to match a +// zero-value field, create a View directly. +// +// The Name field of criteria supports wildcard pattern matching. The "*" +// wildcard is recognized as matching zero or more characters, and "?" is +// recognized as matching exactly one character. For example, a pattern of "*" +// matches all instrument names. +// +// The Stream mask only applies updates for non-zero-value fields. By default, +// the Instrument the View matches against will be use for the Name, +// Description, and Unit of the returned Stream and no Aggregation or +// AttributeFilter are set. All non-zero-value fields of mask are used instead +// of the default. If you need to zero out an Stream field returned from a +// View, create a View directly. +func NewView(criteria Instrument, mask Stream) View { + if criteria.empty() { + global.Error( + errEmptyView, "dropping view", + "mask", mask, + ) + return emptyView + } + + var matchFunc func(Instrument) bool + if strings.ContainsAny(criteria.Name, "*?") { + if mask.Name != "" { + global.Error( + errMultiInst, "dropping view", + "criteria", criteria, + "mask", mask, + ) + return emptyView + } + + // Handle branching here in NewView instead of criteria.matches so + // criteria.matches remains inlinable for the simple case. + pattern := regexp.QuoteMeta(criteria.Name) + pattern = "^" + pattern + "$" + pattern = strings.ReplaceAll(pattern, `\?`, ".") + pattern = strings.ReplaceAll(pattern, `\*`, ".*") + re := regexp.MustCompile(pattern) + matchFunc = func(i Instrument) bool { + return re.MatchString(i.Name) && + criteria.matchesDescription(i) && + criteria.matchesKind(i) && + criteria.matchesUnit(i) && + criteria.matchesScope(i) + } + } else { + matchFunc = criteria.matches + } + + var agg Aggregation + if mask.Aggregation != nil { + agg = mask.Aggregation.copy() + if err := agg.err(); err != nil { + global.Error( + err, "not using aggregation with view", + "criteria", criteria, + "mask", mask, + ) + agg = nil + } + } + + return func(i Instrument) (Stream, bool) { + if matchFunc(i) { + return Stream{ + Name: nonZero(mask.Name, i.Name), + Description: nonZero(mask.Description, i.Description), + Unit: nonZero(mask.Unit, i.Unit), + Aggregation: agg, + AttributeFilter: mask.AttributeFilter, + }, true + } + return Stream{}, false + } +} + +// nonZero returns v if it is non-zero-valued, otherwise alt. +func nonZero[T comparable](v, alt T) T { + var zero T + if v != zero { + return v + } + return alt +} diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go new file mode 100644 index 0000000000000..8e13d157c2c77 --- /dev/null +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.go @@ -0,0 +1,371 @@ +// Copyright 2019, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.6 +// source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto + +package v1 + +import ( + v1 "go.opentelemetry.io/proto/otlp/metrics/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ExportMetricsServiceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An array of ResourceMetrics. + // For data coming from a single resource this array will typically contain one + // element. Intermediary nodes (such as OpenTelemetry Collector) that receive + // data from multiple origins typically batch the data before forwarding further and + // in that case this array will contain multiple elements. + ResourceMetrics []*v1.ResourceMetrics `protobuf:"bytes,1,rep,name=resource_metrics,json=resourceMetrics,proto3" json:"resource_metrics,omitempty"` +} + +func (x *ExportMetricsServiceRequest) Reset() { + *x = ExportMetricsServiceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExportMetricsServiceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExportMetricsServiceRequest) ProtoMessage() {} + +func (x *ExportMetricsServiceRequest) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExportMetricsServiceRequest.ProtoReflect.Descriptor instead. +func (*ExportMetricsServiceRequest) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescGZIP(), []int{0} +} + +func (x *ExportMetricsServiceRequest) GetResourceMetrics() []*v1.ResourceMetrics { + if x != nil { + return x.ResourceMetrics + } + return nil +} + +type ExportMetricsServiceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The details of a partially successful export request. + // + // If the request is only partially accepted + // (i.e. when the server accepts only parts of the data and rejects the rest) + // the server MUST initialize the `partial_success` field and MUST + // set the `rejected_` with the number of items it rejected. + // + // Servers MAY also make use of the `partial_success` field to convey + // warnings/suggestions to senders even when the request was fully accepted. + // In such cases, the `rejected_` MUST have a value of `0` and + // the `error_message` MUST be non-empty. + // + // A `partial_success` message with an empty value (rejected_ = 0 and + // `error_message` = "") is equivalent to it not being set/present. Senders + // SHOULD interpret it the same way as in the full success case. + PartialSuccess *ExportMetricsPartialSuccess `protobuf:"bytes,1,opt,name=partial_success,json=partialSuccess,proto3" json:"partial_success,omitempty"` +} + +func (x *ExportMetricsServiceResponse) Reset() { + *x = ExportMetricsServiceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExportMetricsServiceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExportMetricsServiceResponse) ProtoMessage() {} + +func (x *ExportMetricsServiceResponse) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExportMetricsServiceResponse.ProtoReflect.Descriptor instead. +func (*ExportMetricsServiceResponse) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescGZIP(), []int{1} +} + +func (x *ExportMetricsServiceResponse) GetPartialSuccess() *ExportMetricsPartialSuccess { + if x != nil { + return x.PartialSuccess + } + return nil +} + +type ExportMetricsPartialSuccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The number of rejected data points. + // + // A `rejected_` field holding a `0` value indicates that the + // request was fully accepted. + RejectedDataPoints int64 `protobuf:"varint,1,opt,name=rejected_data_points,json=rejectedDataPoints,proto3" json:"rejected_data_points,omitempty"` + // A developer-facing human-readable message in English. It should be used + // either to explain why the server rejected parts of the data during a partial + // success or to convey warnings/suggestions during a full success. The message + // should offer guidance on how users can address such issues. + // + // error_message is an optional field. An error_message with an empty value + // is equivalent to it not being set. + ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` +} + +func (x *ExportMetricsPartialSuccess) Reset() { + *x = ExportMetricsPartialSuccess{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExportMetricsPartialSuccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExportMetricsPartialSuccess) ProtoMessage() {} + +func (x *ExportMetricsPartialSuccess) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExportMetricsPartialSuccess.ProtoReflect.Descriptor instead. +func (*ExportMetricsPartialSuccess) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ExportMetricsPartialSuccess) GetRejectedDataPoints() int64 { + if x != nil { + return x.RejectedDataPoints + } + return 0 +} + +func (x *ExportMetricsPartialSuccess) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + +var File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto protoreflect.FileDescriptor + +var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc = []byte{ + 0x0a, 0x3e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x28, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2c, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x79, 0x0a, 0x1b, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x1c, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x22, 0x74, 0x0a, 0x1b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x12, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xac, 0x01, 0x0a, 0x0e, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x99, 0x01, + 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x45, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x46, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xa4, 0x01, 0x0a, 0x2b, 0x69, 0x6f, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x13, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x33, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, + 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2f, 0x76, 0x31, 0xaa, 0x02, 0x28, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x56, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescOnce sync.Once + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData = file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc +) + +func file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescGZIP() []byte { + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescOnce.Do(func() { + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData) + }) + return file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDescData +} + +var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes = []interface{}{ + (*ExportMetricsServiceRequest)(nil), // 0: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest + (*ExportMetricsServiceResponse)(nil), // 1: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse + (*ExportMetricsPartialSuccess)(nil), // 2: opentelemetry.proto.collector.metrics.v1.ExportMetricsPartialSuccess + (*v1.ResourceMetrics)(nil), // 3: opentelemetry.proto.metrics.v1.ResourceMetrics +} +var file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_depIdxs = []int32{ + 3, // 0: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest.resource_metrics:type_name -> opentelemetry.proto.metrics.v1.ResourceMetrics + 2, // 1: opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse.partial_success:type_name -> opentelemetry.proto.collector.metrics.v1.ExportMetricsPartialSuccess + 0, // 2: opentelemetry.proto.collector.metrics.v1.MetricsService.Export:input_type -> opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest + 1, // 3: opentelemetry.proto.collector.metrics.v1.MetricsService.Export:output_type -> opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse + 3, // [3:4] is the sub-list for method output_type + 2, // [2:3] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_init() } +func file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_init() { + if File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExportMetricsServiceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExportMetricsServiceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExportMetricsPartialSuccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes, + DependencyIndexes: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_depIdxs, + MessageInfos: file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_msgTypes, + }.Build() + File_opentelemetry_proto_collector_metrics_v1_metrics_service_proto = out.File + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_rawDesc = nil + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_goTypes = nil + file_opentelemetry_proto_collector_metrics_v1_metrics_service_proto_depIdxs = nil +} diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go new file mode 100644 index 0000000000000..c42f1454ed2d5 --- /dev/null +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service.pb.gw.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto + +/* +Package v1 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package v1 + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client MetricsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ExportMetricsServiceRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Export(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, server MetricsServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ExportMetricsServiceRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Export(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterMetricsServiceHandlerServer registers the http handlers for service MetricsService to "mux". +// UnaryRPC :call MetricsServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMetricsServiceHandlerFromEndpoint instead. +func RegisterMetricsServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MetricsServiceServer) error { + + mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_MetricsService_Export_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetricsService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterMetricsServiceHandlerFromEndpoint is same as RegisterMetricsServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterMetricsServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterMetricsServiceHandler(ctx, mux, conn) +} + +// RegisterMetricsServiceHandler registers the http handlers for service MetricsService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterMetricsServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterMetricsServiceHandlerClient(ctx, mux, NewMetricsServiceClient(conn)) +} + +// RegisterMetricsServiceHandlerClient registers the http handlers for service MetricsService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MetricsServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MetricsServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "MetricsServiceClient" to call the correct interceptors. +func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MetricsServiceClient) error { + + mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", runtime.WithHTTPPathPattern("/v1/metrics")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_MetricsService_Export_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetricsService_Export_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_MetricsService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "metrics"}, "")) +) + +var ( + forward_MetricsService_Export_0 = runtime.ForwardResponseMessage +) diff --git a/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go new file mode 100644 index 0000000000000..31d25fc15ac66 --- /dev/null +++ b/vendor/go.opentelemetry.io/proto/otlp/collector/metrics/v1/metrics_service_grpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.1.0 +// - protoc v3.21.6 +// source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// MetricsServiceClient is the client API for MetricsService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MetricsServiceClient interface { + // For performance reasons, it is recommended to keep this RPC + // alive for the entire life of the application. + Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error) +} + +type metricsServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMetricsServiceClient(cc grpc.ClientConnInterface) MetricsServiceClient { + return &metricsServiceClient{cc} +} + +func (c *metricsServiceClient) Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error) { + out := new(ExportMetricsServiceResponse) + err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MetricsServiceServer is the server API for MetricsService service. +// All implementations must embed UnimplementedMetricsServiceServer +// for forward compatibility +type MetricsServiceServer interface { + // For performance reasons, it is recommended to keep this RPC + // alive for the entire life of the application. + Export(context.Context, *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error) + mustEmbedUnimplementedMetricsServiceServer() +} + +// UnimplementedMetricsServiceServer must be embedded to have forward compatible implementations. +type UnimplementedMetricsServiceServer struct { +} + +func (UnimplementedMetricsServiceServer) Export(context.Context, *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") +} +func (UnimplementedMetricsServiceServer) mustEmbedUnimplementedMetricsServiceServer() {} + +// UnsafeMetricsServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MetricsServiceServer will +// result in compilation errors. +type UnsafeMetricsServiceServer interface { + mustEmbedUnimplementedMetricsServiceServer() +} + +func RegisterMetricsServiceServer(s grpc.ServiceRegistrar, srv MetricsServiceServer) { + s.RegisterService(&MetricsService_ServiceDesc, srv) +} + +func _MetricsService_Export_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExportMetricsServiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetricsServiceServer).Export(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetricsServiceServer).Export(ctx, req.(*ExportMetricsServiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// MetricsService_ServiceDesc is the grpc.ServiceDesc for MetricsService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MetricsService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "opentelemetry.proto.collector.metrics.v1.MetricsService", + HandlerType: (*MetricsServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Export", + Handler: _MetricsService_Export_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "opentelemetry/proto/collector/metrics/v1/metrics_service.proto", +} diff --git a/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go b/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go new file mode 100644 index 0000000000000..dfa59a678545a --- /dev/null +++ b/vendor/go.opentelemetry.io/proto/otlp/metrics/v1/metrics.pb.go @@ -0,0 +1,2489 @@ +// Copyright 2019, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.6 +// source: opentelemetry/proto/metrics/v1/metrics.proto + +package v1 + +import ( + v11 "go.opentelemetry.io/proto/otlp/common/v1" + v1 "go.opentelemetry.io/proto/otlp/resource/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// AggregationTemporality defines how a metric aggregator reports aggregated +// values. It describes how those values relate to the time interval over +// which they are aggregated. +type AggregationTemporality int32 + +const ( + // UNSPECIFIED is the default AggregationTemporality, it MUST not be used. + AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED AggregationTemporality = 0 + // DELTA is an AggregationTemporality for a metric aggregator which reports + // changes since last report time. Successive metrics contain aggregation of + // values from continuous and non-overlapping intervals. + // + // The values for a DELTA metric are based only on the time interval + // associated with one measurement cycle. There is no dependency on + // previous measurements like is the case for CUMULATIVE metrics. + // + // For example, consider a system measuring the number of requests that + // it receives and reports the sum of these requests every second as a + // DELTA metric: + // + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0+1 to + // t_0+2 with a value of 2. + AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA AggregationTemporality = 1 + // CUMULATIVE is an AggregationTemporality for a metric aggregator which + // reports changes since a fixed start time. This means that current values + // of a CUMULATIVE metric depend on all previous measurements since the + // start time. Because of this, the sender is required to retain this state + // in some form. If this state is lost or invalidated, the CUMULATIVE metric + // values MUST be reset and a new fixed start time following the last + // reported measurement time sent MUST be used. + // + // For example, consider a system measuring the number of requests that + // it receives and reports the sum of these requests every second as a + // CUMULATIVE metric: + // + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+2 with a value of 5. + // 9. The system experiences a fault and loses state. + // 10. The system recovers and resumes receiving at time=t_1. + // 11. A request is received, the system measures 1 request. + // 12. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_1 to + // t_0+1 with a value of 1. + // + // Note: Even though, when reporting changes since last report time, using + // CUMULATIVE is valid, it is not recommended. This may cause problems for + // systems that do not use start_time to determine when the aggregation + // value was reset (e.g. Prometheus). + AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE AggregationTemporality = 2 +) + +// Enum value maps for AggregationTemporality. +var ( + AggregationTemporality_name = map[int32]string{ + 0: "AGGREGATION_TEMPORALITY_UNSPECIFIED", + 1: "AGGREGATION_TEMPORALITY_DELTA", + 2: "AGGREGATION_TEMPORALITY_CUMULATIVE", + } + AggregationTemporality_value = map[string]int32{ + "AGGREGATION_TEMPORALITY_UNSPECIFIED": 0, + "AGGREGATION_TEMPORALITY_DELTA": 1, + "AGGREGATION_TEMPORALITY_CUMULATIVE": 2, + } +) + +func (x AggregationTemporality) Enum() *AggregationTemporality { + p := new(AggregationTemporality) + *p = x + return p +} + +func (x AggregationTemporality) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AggregationTemporality) Descriptor() protoreflect.EnumDescriptor { + return file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes[0].Descriptor() +} + +func (AggregationTemporality) Type() protoreflect.EnumType { + return &file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes[0] +} + +func (x AggregationTemporality) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AggregationTemporality.Descriptor instead. +func (AggregationTemporality) EnumDescriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{0} +} + +// DataPointFlags is defined as a protobuf 'uint32' type and is to be used as a +// bit-field representing 32 distinct boolean flags. Each flag defined in this +// enum is a bit-mask. To test the presence of a single flag in the flags of +// a data point, for example, use an expression like: +// +// (point.flags & DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK) == DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK +// +type DataPointFlags int32 + +const ( + // The zero value for the enum. Should not be used for comparisons. + // Instead use bitwise "and" with the appropriate mask as shown above. + DataPointFlags_DATA_POINT_FLAGS_DO_NOT_USE DataPointFlags = 0 + // This DataPoint is valid but has no recorded value. This value + // SHOULD be used to reflect explicitly missing data in a series, as + // for an equivalent to the Prometheus "staleness marker". + DataPointFlags_DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK DataPointFlags = 1 +) + +// Enum value maps for DataPointFlags. +var ( + DataPointFlags_name = map[int32]string{ + 0: "DATA_POINT_FLAGS_DO_NOT_USE", + 1: "DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK", + } + DataPointFlags_value = map[string]int32{ + "DATA_POINT_FLAGS_DO_NOT_USE": 0, + "DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK": 1, + } +) + +func (x DataPointFlags) Enum() *DataPointFlags { + p := new(DataPointFlags) + *p = x + return p +} + +func (x DataPointFlags) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DataPointFlags) Descriptor() protoreflect.EnumDescriptor { + return file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes[1].Descriptor() +} + +func (DataPointFlags) Type() protoreflect.EnumType { + return &file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes[1] +} + +func (x DataPointFlags) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DataPointFlags.Descriptor instead. +func (DataPointFlags) EnumDescriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{1} +} + +// MetricsData represents the metrics data that can be stored in a persistent +// storage, OR can be embedded by other protocols that transfer OTLP metrics +// data but do not implement the OTLP protocol. +// +// The main difference between this message and collector protocol is that +// in this message there will not be any "control" or "metadata" specific to +// OTLP protocol. +// +// When new fields are added into this message, the OTLP request MUST be updated +// as well. +type MetricsData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An array of ResourceMetrics. + // For data coming from a single resource this array will typically contain + // one element. Intermediary nodes that receive data from multiple origins + // typically batch the data before forwarding further and in that case this + // array will contain multiple elements. + ResourceMetrics []*ResourceMetrics `protobuf:"bytes,1,rep,name=resource_metrics,json=resourceMetrics,proto3" json:"resource_metrics,omitempty"` +} + +func (x *MetricsData) Reset() { + *x = MetricsData{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MetricsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MetricsData) ProtoMessage() {} + +func (x *MetricsData) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetricsData.ProtoReflect.Descriptor instead. +func (*MetricsData) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{0} +} + +func (x *MetricsData) GetResourceMetrics() []*ResourceMetrics { + if x != nil { + return x.ResourceMetrics + } + return nil +} + +// A collection of ScopeMetrics from a Resource. +type ResourceMetrics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The resource for the metrics in this message. + // If this field is not set then no resource info is known. + Resource *v1.Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // A list of metrics that originate from a resource. + ScopeMetrics []*ScopeMetrics `protobuf:"bytes,2,rep,name=scope_metrics,json=scopeMetrics,proto3" json:"scope_metrics,omitempty"` + // This schema_url applies to the data in the "resource" field. It does not apply + // to the data in the "scope_metrics" field which have their own schema_url field. + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` +} + +func (x *ResourceMetrics) Reset() { + *x = ResourceMetrics{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResourceMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceMetrics) ProtoMessage() {} + +func (x *ResourceMetrics) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceMetrics.ProtoReflect.Descriptor instead. +func (*ResourceMetrics) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{1} +} + +func (x *ResourceMetrics) GetResource() *v1.Resource { + if x != nil { + return x.Resource + } + return nil +} + +func (x *ResourceMetrics) GetScopeMetrics() []*ScopeMetrics { + if x != nil { + return x.ScopeMetrics + } + return nil +} + +func (x *ResourceMetrics) GetSchemaUrl() string { + if x != nil { + return x.SchemaUrl + } + return "" +} + +// A collection of Metrics produced by an Scope. +type ScopeMetrics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The instrumentation scope information for the metrics in this message. + // Semantically when InstrumentationScope isn't set, it is equivalent with + // an empty instrumentation scope name (unknown). + Scope *v11.InstrumentationScope `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` + // A list of metrics that originate from an instrumentation library. + Metrics []*Metric `protobuf:"bytes,2,rep,name=metrics,proto3" json:"metrics,omitempty"` + // This schema_url applies to all metrics in the "metrics" field. + SchemaUrl string `protobuf:"bytes,3,opt,name=schema_url,json=schemaUrl,proto3" json:"schema_url,omitempty"` +} + +func (x *ScopeMetrics) Reset() { + *x = ScopeMetrics{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScopeMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScopeMetrics) ProtoMessage() {} + +func (x *ScopeMetrics) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScopeMetrics.ProtoReflect.Descriptor instead. +func (*ScopeMetrics) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{2} +} + +func (x *ScopeMetrics) GetScope() *v11.InstrumentationScope { + if x != nil { + return x.Scope + } + return nil +} + +func (x *ScopeMetrics) GetMetrics() []*Metric { + if x != nil { + return x.Metrics + } + return nil +} + +func (x *ScopeMetrics) GetSchemaUrl() string { + if x != nil { + return x.SchemaUrl + } + return "" +} + +// Defines a Metric which has one or more timeseries. The following is a +// brief summary of the Metric data model. For more details, see: +// +// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md +// +// +// The data model and relation between entities is shown in the +// diagram below. Here, "DataPoint" is the term used to refer to any +// one of the specific data point value types, and "points" is the term used +// to refer to any one of the lists of points contained in the Metric. +// +// - Metric is composed of a metadata and data. +// - Metadata part contains a name, description, unit. +// - Data is one of the possible types (Sum, Gauge, Histogram, Summary). +// - DataPoint contains timestamps, attributes, and one of the possible value type +// fields. +// +// Metric +// +------------+ +// |name | +// |description | +// |unit | +------------------------------------+ +// |data |---> |Gauge, Sum, Histogram, Summary, ... | +// +------------+ +------------------------------------+ +// +// Data [One of Gauge, Sum, Histogram, Summary, ...] +// +-----------+ +// |... | // Metadata about the Data. +// |points |--+ +// +-----------+ | +// | +---------------------------+ +// | |DataPoint 1 | +// v |+------+------+ +------+ | +// +-----+ ||label |label |...|label | | +// | 1 |-->||value1|value2|...|valueN| | +// +-----+ |+------+------+ +------+ | +// | . | |+-----+ | +// | . | ||value| | +// | . | |+-----+ | +// | . | +---------------------------+ +// | . | . +// | . | . +// | . | . +// | . | +---------------------------+ +// | . | |DataPoint M | +// +-----+ |+------+------+ +------+ | +// | M |-->||label |label |...|label | | +// +-----+ ||value1|value2|...|valueN| | +// |+------+------+ +------+ | +// |+-----+ | +// ||value| | +// |+-----+ | +// +---------------------------+ +// +// Each distinct type of DataPoint represents the output of a specific +// aggregation function, the result of applying the DataPoint's +// associated function of to one or more measurements. +// +// All DataPoint types have three common fields: +// - Attributes includes key-value pairs associated with the data point +// - TimeUnixNano is required, set to the end time of the aggregation +// - StartTimeUnixNano is optional, but strongly encouraged for DataPoints +// having an AggregationTemporality field, as discussed below. +// +// Both TimeUnixNano and StartTimeUnixNano values are expressed as +// UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. +// +// # TimeUnixNano +// +// This field is required, having consistent interpretation across +// DataPoint types. TimeUnixNano is the moment corresponding to when +// the data point's aggregate value was captured. +// +// Data points with the 0 value for TimeUnixNano SHOULD be rejected +// by consumers. +// +// # StartTimeUnixNano +// +// StartTimeUnixNano in general allows detecting when a sequence of +// observations is unbroken. This field indicates to consumers the +// start time for points with cumulative and delta +// AggregationTemporality, and it should be included whenever possible +// to support correct rate calculation. Although it may be omitted +// when the start time is truly unknown, setting StartTimeUnixNano is +// strongly encouraged. +type Metric struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // name of the metric, including its DNS name prefix. It must be unique. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // description of the metric, which can be used in documentation. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // unit in which the metric value is reported. Follows the format + // described by http://unitsofmeasure.org/ucum.html. + Unit string `protobuf:"bytes,3,opt,name=unit,proto3" json:"unit,omitempty"` + // Data determines the aggregation type (if any) of the metric, what is the + // reported value type for the data points, as well as the relatationship to + // the time interval over which they are reported. + // + // Types that are assignable to Data: + // *Metric_Gauge + // *Metric_Sum + // *Metric_Histogram + // *Metric_ExponentialHistogram + // *Metric_Summary + Data isMetric_Data `protobuf_oneof:"data"` +} + +func (x *Metric) Reset() { + *x = Metric{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Metric) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metric) ProtoMessage() {} + +func (x *Metric) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Metric.ProtoReflect.Descriptor instead. +func (*Metric) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{3} +} + +func (x *Metric) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Metric) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Metric) GetUnit() string { + if x != nil { + return x.Unit + } + return "" +} + +func (m *Metric) GetData() isMetric_Data { + if m != nil { + return m.Data + } + return nil +} + +func (x *Metric) GetGauge() *Gauge { + if x, ok := x.GetData().(*Metric_Gauge); ok { + return x.Gauge + } + return nil +} + +func (x *Metric) GetSum() *Sum { + if x, ok := x.GetData().(*Metric_Sum); ok { + return x.Sum + } + return nil +} + +func (x *Metric) GetHistogram() *Histogram { + if x, ok := x.GetData().(*Metric_Histogram); ok { + return x.Histogram + } + return nil +} + +func (x *Metric) GetExponentialHistogram() *ExponentialHistogram { + if x, ok := x.GetData().(*Metric_ExponentialHistogram); ok { + return x.ExponentialHistogram + } + return nil +} + +func (x *Metric) GetSummary() *Summary { + if x, ok := x.GetData().(*Metric_Summary); ok { + return x.Summary + } + return nil +} + +type isMetric_Data interface { + isMetric_Data() +} + +type Metric_Gauge struct { + Gauge *Gauge `protobuf:"bytes,5,opt,name=gauge,proto3,oneof"` +} + +type Metric_Sum struct { + Sum *Sum `protobuf:"bytes,7,opt,name=sum,proto3,oneof"` +} + +type Metric_Histogram struct { + Histogram *Histogram `protobuf:"bytes,9,opt,name=histogram,proto3,oneof"` +} + +type Metric_ExponentialHistogram struct { + ExponentialHistogram *ExponentialHistogram `protobuf:"bytes,10,opt,name=exponential_histogram,json=exponentialHistogram,proto3,oneof"` +} + +type Metric_Summary struct { + Summary *Summary `protobuf:"bytes,11,opt,name=summary,proto3,oneof"` +} + +func (*Metric_Gauge) isMetric_Data() {} + +func (*Metric_Sum) isMetric_Data() {} + +func (*Metric_Histogram) isMetric_Data() {} + +func (*Metric_ExponentialHistogram) isMetric_Data() {} + +func (*Metric_Summary) isMetric_Data() {} + +// Gauge represents the type of a scalar metric that always exports the +// "current value" for every data point. It should be used for an "unknown" +// aggregation. +// +// A Gauge does not support different aggregation temporalities. Given the +// aggregation is unknown, points cannot be combined using the same +// aggregation, regardless of aggregation temporalities. Therefore, +// AggregationTemporality is not included. Consequently, this also means +// "StartTimeUnixNano" is ignored for all data points. +type Gauge struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataPoints []*NumberDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` +} + +func (x *Gauge) Reset() { + *x = Gauge{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Gauge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Gauge) ProtoMessage() {} + +func (x *Gauge) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Gauge.ProtoReflect.Descriptor instead. +func (*Gauge) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{4} +} + +func (x *Gauge) GetDataPoints() []*NumberDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +// Sum represents the type of a scalar metric that is calculated as a sum of all +// reported measurements over a time interval. +type Sum struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataPoints []*NumberDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + // aggregation_temporality describes if the aggregator reports delta changes + // since last report time, or cumulative changes since a fixed start time. + AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` + // If "true" means that the sum is monotonic. + IsMonotonic bool `protobuf:"varint,3,opt,name=is_monotonic,json=isMonotonic,proto3" json:"is_monotonic,omitempty"` +} + +func (x *Sum) Reset() { + *x = Sum{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Sum) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Sum) ProtoMessage() {} + +func (x *Sum) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Sum.ProtoReflect.Descriptor instead. +func (*Sum) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{5} +} + +func (x *Sum) GetDataPoints() []*NumberDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +func (x *Sum) GetAggregationTemporality() AggregationTemporality { + if x != nil { + return x.AggregationTemporality + } + return AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED +} + +func (x *Sum) GetIsMonotonic() bool { + if x != nil { + return x.IsMonotonic + } + return false +} + +// Histogram represents the type of a metric that is calculated by aggregating +// as a Histogram of all reported measurements over a time interval. +type Histogram struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataPoints []*HistogramDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + // aggregation_temporality describes if the aggregator reports delta changes + // since last report time, or cumulative changes since a fixed start time. + AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` +} + +func (x *Histogram) Reset() { + *x = Histogram{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Histogram) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Histogram) ProtoMessage() {} + +func (x *Histogram) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Histogram.ProtoReflect.Descriptor instead. +func (*Histogram) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{6} +} + +func (x *Histogram) GetDataPoints() []*HistogramDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +func (x *Histogram) GetAggregationTemporality() AggregationTemporality { + if x != nil { + return x.AggregationTemporality + } + return AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED +} + +// ExponentialHistogram represents the type of a metric that is calculated by aggregating +// as a ExponentialHistogram of all reported double measurements over a time interval. +type ExponentialHistogram struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataPoints []*ExponentialHistogramDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + // aggregation_temporality describes if the aggregator reports delta changes + // since last report time, or cumulative changes since a fixed start time. + AggregationTemporality AggregationTemporality `protobuf:"varint,2,opt,name=aggregation_temporality,json=aggregationTemporality,proto3,enum=opentelemetry.proto.metrics.v1.AggregationTemporality" json:"aggregation_temporality,omitempty"` +} + +func (x *ExponentialHistogram) Reset() { + *x = ExponentialHistogram{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExponentialHistogram) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExponentialHistogram) ProtoMessage() {} + +func (x *ExponentialHistogram) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExponentialHistogram.ProtoReflect.Descriptor instead. +func (*ExponentialHistogram) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{7} +} + +func (x *ExponentialHistogram) GetDataPoints() []*ExponentialHistogramDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +func (x *ExponentialHistogram) GetAggregationTemporality() AggregationTemporality { + if x != nil { + return x.AggregationTemporality + } + return AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED +} + +// Summary metric data are used to convey quantile summaries, +// a Prometheus (see: https://prometheus.io/docs/concepts/metric_types/#summary) +// and OpenMetrics (see: https://github.com/OpenObservability/OpenMetrics/blob/4dbf6075567ab43296eed941037c12951faafb92/protos/prometheus.proto#L45) +// data type. These data points cannot always be merged in a meaningful way. +// While they can be useful in some applications, histogram data points are +// recommended for new applications. +type Summary struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataPoints []*SummaryDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` +} + +func (x *Summary) Reset() { + *x = Summary{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Summary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Summary) ProtoMessage() {} + +func (x *Summary) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Summary.ProtoReflect.Descriptor instead. +func (*Summary) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{8} +} + +func (x *Summary) GetDataPoints() []*SummaryDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +// NumberDataPoint is a single data point in a timeseries that describes the +// time-varying scalar value of a metric. +type NumberDataPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of key/value pairs that uniquely identify the timeseries from + // where this point belongs. The list may be empty (may contain 0 elements). + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + Attributes []*v11.KeyValue `protobuf:"bytes,7,rep,name=attributes,proto3" json:"attributes,omitempty"` + // StartTimeUnixNano is optional but strongly encouraged, see the + // the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"` + // TimeUnixNano is required, see the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` + // The value itself. A point is considered invalid when one of the recognized + // value fields is not present inside this oneof. + // + // Types that are assignable to Value: + // *NumberDataPoint_AsDouble + // *NumberDataPoint_AsInt + Value isNumberDataPoint_Value `protobuf_oneof:"value"` + // (Optional) List of exemplars collected from + // measurements that were used to form the data point + Exemplars []*Exemplar `protobuf:"bytes,5,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + // Flags that apply to this specific data point. See DataPointFlags + // for the available flags and their meaning. + Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` +} + +func (x *NumberDataPoint) Reset() { + *x = NumberDataPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NumberDataPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NumberDataPoint) ProtoMessage() {} + +func (x *NumberDataPoint) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NumberDataPoint.ProtoReflect.Descriptor instead. +func (*NumberDataPoint) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{9} +} + +func (x *NumberDataPoint) GetAttributes() []*v11.KeyValue { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *NumberDataPoint) GetStartTimeUnixNano() uint64 { + if x != nil { + return x.StartTimeUnixNano + } + return 0 +} + +func (x *NumberDataPoint) GetTimeUnixNano() uint64 { + if x != nil { + return x.TimeUnixNano + } + return 0 +} + +func (m *NumberDataPoint) GetValue() isNumberDataPoint_Value { + if m != nil { + return m.Value + } + return nil +} + +func (x *NumberDataPoint) GetAsDouble() float64 { + if x, ok := x.GetValue().(*NumberDataPoint_AsDouble); ok { + return x.AsDouble + } + return 0 +} + +func (x *NumberDataPoint) GetAsInt() int64 { + if x, ok := x.GetValue().(*NumberDataPoint_AsInt); ok { + return x.AsInt + } + return 0 +} + +func (x *NumberDataPoint) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +func (x *NumberDataPoint) GetFlags() uint32 { + if x != nil { + return x.Flags + } + return 0 +} + +type isNumberDataPoint_Value interface { + isNumberDataPoint_Value() +} + +type NumberDataPoint_AsDouble struct { + AsDouble float64 `protobuf:"fixed64,4,opt,name=as_double,json=asDouble,proto3,oneof"` +} + +type NumberDataPoint_AsInt struct { + AsInt int64 `protobuf:"fixed64,6,opt,name=as_int,json=asInt,proto3,oneof"` +} + +func (*NumberDataPoint_AsDouble) isNumberDataPoint_Value() {} + +func (*NumberDataPoint_AsInt) isNumberDataPoint_Value() {} + +// HistogramDataPoint is a single data point in a timeseries that describes the +// time-varying values of a Histogram. A Histogram contains summary statistics +// for a population of values, it may optionally contain the distribution of +// those values across a set of buckets. +// +// If the histogram contains the distribution of values, then both +// "explicit_bounds" and "bucket counts" fields must be defined. +// If the histogram does not contain the distribution of values, then both +// "explicit_bounds" and "bucket_counts" must be omitted and only "count" and +// "sum" are known. +type HistogramDataPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of key/value pairs that uniquely identify the timeseries from + // where this point belongs. The list may be empty (may contain 0 elements). + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + Attributes []*v11.KeyValue `protobuf:"bytes,9,rep,name=attributes,proto3" json:"attributes,omitempty"` + // StartTimeUnixNano is optional but strongly encouraged, see the + // the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"` + // TimeUnixNano is required, see the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` + // count is the number of values in the population. Must be non-negative. This + // value must be equal to the sum of the "count" fields in buckets if a + // histogram is provided. + Count uint64 `protobuf:"fixed64,4,opt,name=count,proto3" json:"count,omitempty"` + // sum of the values in the population. If count is zero then this field + // must be zero. + // + // Note: Sum should only be filled out when measuring non-negative discrete + // events, and is assumed to be monotonic over the values of these events. + // Negative events *can* be recorded, but sum should not be filled out when + // doing so. This is specifically to enforce compatibility w/ OpenMetrics, + // see: https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#histogram + Sum *float64 `protobuf:"fixed64,5,opt,name=sum,proto3,oneof" json:"sum,omitempty"` + // bucket_counts is an optional field contains the count values of histogram + // for each bucket. + // + // The sum of the bucket_counts must equal the value in the count field. + // + // The number of elements in bucket_counts array must be by one greater than + // the number of elements in explicit_bounds array. + BucketCounts []uint64 `protobuf:"fixed64,6,rep,packed,name=bucket_counts,json=bucketCounts,proto3" json:"bucket_counts,omitempty"` + // explicit_bounds specifies buckets with explicitly defined bounds for values. + // + // The boundaries for bucket at index i are: + // + // (-infinity, explicit_bounds[i]] for i == 0 + // (explicit_bounds[i-1], explicit_bounds[i]] for 0 < i < size(explicit_bounds) + // (explicit_bounds[i-1], +infinity) for i == size(explicit_bounds) + // + // The values in the explicit_bounds array must be strictly increasing. + // + // Histogram buckets are inclusive of their upper boundary, except the last + // bucket where the boundary is at infinity. This format is intentionally + // compatible with the OpenMetrics histogram definition. + ExplicitBounds []float64 `protobuf:"fixed64,7,rep,packed,name=explicit_bounds,json=explicitBounds,proto3" json:"explicit_bounds,omitempty"` + // (Optional) List of exemplars collected from + // measurements that were used to form the data point + Exemplars []*Exemplar `protobuf:"bytes,8,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + // Flags that apply to this specific data point. See DataPointFlags + // for the available flags and their meaning. + Flags uint32 `protobuf:"varint,10,opt,name=flags,proto3" json:"flags,omitempty"` + // min is the minimum value over (start_time, end_time]. + Min *float64 `protobuf:"fixed64,11,opt,name=min,proto3,oneof" json:"min,omitempty"` + // max is the maximum value over (start_time, end_time]. + Max *float64 `protobuf:"fixed64,12,opt,name=max,proto3,oneof" json:"max,omitempty"` +} + +func (x *HistogramDataPoint) Reset() { + *x = HistogramDataPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HistogramDataPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HistogramDataPoint) ProtoMessage() {} + +func (x *HistogramDataPoint) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HistogramDataPoint.ProtoReflect.Descriptor instead. +func (*HistogramDataPoint) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{10} +} + +func (x *HistogramDataPoint) GetAttributes() []*v11.KeyValue { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *HistogramDataPoint) GetStartTimeUnixNano() uint64 { + if x != nil { + return x.StartTimeUnixNano + } + return 0 +} + +func (x *HistogramDataPoint) GetTimeUnixNano() uint64 { + if x != nil { + return x.TimeUnixNano + } + return 0 +} + +func (x *HistogramDataPoint) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *HistogramDataPoint) GetSum() float64 { + if x != nil && x.Sum != nil { + return *x.Sum + } + return 0 +} + +func (x *HistogramDataPoint) GetBucketCounts() []uint64 { + if x != nil { + return x.BucketCounts + } + return nil +} + +func (x *HistogramDataPoint) GetExplicitBounds() []float64 { + if x != nil { + return x.ExplicitBounds + } + return nil +} + +func (x *HistogramDataPoint) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +func (x *HistogramDataPoint) GetFlags() uint32 { + if x != nil { + return x.Flags + } + return 0 +} + +func (x *HistogramDataPoint) GetMin() float64 { + if x != nil && x.Min != nil { + return *x.Min + } + return 0 +} + +func (x *HistogramDataPoint) GetMax() float64 { + if x != nil && x.Max != nil { + return *x.Max + } + return 0 +} + +// ExponentialHistogramDataPoint is a single data point in a timeseries that describes the +// time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains +// summary statistics for a population of values, it may optionally contain the +// distribution of those values across a set of buckets. +// +type ExponentialHistogramDataPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of key/value pairs that uniquely identify the timeseries from + // where this point belongs. The list may be empty (may contain 0 elements). + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + Attributes []*v11.KeyValue `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty"` + // StartTimeUnixNano is optional but strongly encouraged, see the + // the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"` + // TimeUnixNano is required, see the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` + // count is the number of values in the population. Must be + // non-negative. This value must be equal to the sum of the "bucket_counts" + // values in the positive and negative Buckets plus the "zero_count" field. + Count uint64 `protobuf:"fixed64,4,opt,name=count,proto3" json:"count,omitempty"` + // sum of the values in the population. If count is zero then this field + // must be zero. + // + // Note: Sum should only be filled out when measuring non-negative discrete + // events, and is assumed to be monotonic over the values of these events. + // Negative events *can* be recorded, but sum should not be filled out when + // doing so. This is specifically to enforce compatibility w/ OpenMetrics, + // see: https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#histogram + Sum *float64 `protobuf:"fixed64,5,opt,name=sum,proto3,oneof" json:"sum,omitempty"` + // scale describes the resolution of the histogram. Boundaries are + // located at powers of the base, where: + // + // base = (2^(2^-scale)) + // + // The histogram bucket identified by `index`, a signed integer, + // contains values that are greater than (base^index) and + // less than or equal to (base^(index+1)). + // + // The positive and negative ranges of the histogram are expressed + // separately. Negative values are mapped by their absolute value + // into the negative range using the same scale as the positive range. + // + // scale is not restricted by the protocol, as the permissible + // values depend on the range of the data. + Scale int32 `protobuf:"zigzag32,6,opt,name=scale,proto3" json:"scale,omitempty"` + // zero_count is the count of values that are either exactly zero or + // within the region considered zero by the instrumentation at the + // tolerated degree of precision. This bucket stores values that + // cannot be expressed using the standard exponential formula as + // well as values that have been rounded to zero. + // + // Implementations MAY consider the zero bucket to have probability + // mass equal to (zero_count / count). + ZeroCount uint64 `protobuf:"fixed64,7,opt,name=zero_count,json=zeroCount,proto3" json:"zero_count,omitempty"` + // positive carries the positive range of exponential bucket counts. + Positive *ExponentialHistogramDataPoint_Buckets `protobuf:"bytes,8,opt,name=positive,proto3" json:"positive,omitempty"` + // negative carries the negative range of exponential bucket counts. + Negative *ExponentialHistogramDataPoint_Buckets `protobuf:"bytes,9,opt,name=negative,proto3" json:"negative,omitempty"` + // Flags that apply to this specific data point. See DataPointFlags + // for the available flags and their meaning. + Flags uint32 `protobuf:"varint,10,opt,name=flags,proto3" json:"flags,omitempty"` + // (Optional) List of exemplars collected from + // measurements that were used to form the data point + Exemplars []*Exemplar `protobuf:"bytes,11,rep,name=exemplars,proto3" json:"exemplars,omitempty"` + // min is the minimum value over (start_time, end_time]. + Min *float64 `protobuf:"fixed64,12,opt,name=min,proto3,oneof" json:"min,omitempty"` + // max is the maximum value over (start_time, end_time]. + Max *float64 `protobuf:"fixed64,13,opt,name=max,proto3,oneof" json:"max,omitempty"` + // ZeroThreshold may be optionally set to convey the width of the zero + // region. Where the zero region is defined as the closed interval + // [-ZeroThreshold, ZeroThreshold]. + // When ZeroThreshold is 0, zero count bucket stores values that cannot be + // expressed using the standard exponential formula as well as values that + // have been rounded to zero. + ZeroThreshold float64 `protobuf:"fixed64,14,opt,name=zero_threshold,json=zeroThreshold,proto3" json:"zero_threshold,omitempty"` +} + +func (x *ExponentialHistogramDataPoint) Reset() { + *x = ExponentialHistogramDataPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExponentialHistogramDataPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExponentialHistogramDataPoint) ProtoMessage() {} + +func (x *ExponentialHistogramDataPoint) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExponentialHistogramDataPoint.ProtoReflect.Descriptor instead. +func (*ExponentialHistogramDataPoint) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{11} +} + +func (x *ExponentialHistogramDataPoint) GetAttributes() []*v11.KeyValue { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *ExponentialHistogramDataPoint) GetStartTimeUnixNano() uint64 { + if x != nil { + return x.StartTimeUnixNano + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetTimeUnixNano() uint64 { + if x != nil { + return x.TimeUnixNano + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetSum() float64 { + if x != nil && x.Sum != nil { + return *x.Sum + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetScale() int32 { + if x != nil { + return x.Scale + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetZeroCount() uint64 { + if x != nil { + return x.ZeroCount + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetPositive() *ExponentialHistogramDataPoint_Buckets { + if x != nil { + return x.Positive + } + return nil +} + +func (x *ExponentialHistogramDataPoint) GetNegative() *ExponentialHistogramDataPoint_Buckets { + if x != nil { + return x.Negative + } + return nil +} + +func (x *ExponentialHistogramDataPoint) GetFlags() uint32 { + if x != nil { + return x.Flags + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetExemplars() []*Exemplar { + if x != nil { + return x.Exemplars + } + return nil +} + +func (x *ExponentialHistogramDataPoint) GetMin() float64 { + if x != nil && x.Min != nil { + return *x.Min + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetMax() float64 { + if x != nil && x.Max != nil { + return *x.Max + } + return 0 +} + +func (x *ExponentialHistogramDataPoint) GetZeroThreshold() float64 { + if x != nil { + return x.ZeroThreshold + } + return 0 +} + +// SummaryDataPoint is a single data point in a timeseries that describes the +// time-varying values of a Summary metric. +type SummaryDataPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of key/value pairs that uniquely identify the timeseries from + // where this point belongs. The list may be empty (may contain 0 elements). + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + Attributes []*v11.KeyValue `protobuf:"bytes,7,rep,name=attributes,proto3" json:"attributes,omitempty"` + // StartTimeUnixNano is optional but strongly encouraged, see the + // the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"` + // TimeUnixNano is required, see the detailed comments above Metric. + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` + // count is the number of values in the population. Must be non-negative. + Count uint64 `protobuf:"fixed64,4,opt,name=count,proto3" json:"count,omitempty"` + // sum of the values in the population. If count is zero then this field + // must be zero. + // + // Note: Sum should only be filled out when measuring non-negative discrete + // events, and is assumed to be monotonic over the values of these events. + // Negative events *can* be recorded, but sum should not be filled out when + // doing so. This is specifically to enforce compatibility w/ OpenMetrics, + // see: https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#summary + Sum float64 `protobuf:"fixed64,5,opt,name=sum,proto3" json:"sum,omitempty"` + // (Optional) list of values at different quantiles of the distribution calculated + // from the current snapshot. The quantiles must be strictly increasing. + QuantileValues []*SummaryDataPoint_ValueAtQuantile `protobuf:"bytes,6,rep,name=quantile_values,json=quantileValues,proto3" json:"quantile_values,omitempty"` + // Flags that apply to this specific data point. See DataPointFlags + // for the available flags and their meaning. + Flags uint32 `protobuf:"varint,8,opt,name=flags,proto3" json:"flags,omitempty"` +} + +func (x *SummaryDataPoint) Reset() { + *x = SummaryDataPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SummaryDataPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SummaryDataPoint) ProtoMessage() {} + +func (x *SummaryDataPoint) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SummaryDataPoint.ProtoReflect.Descriptor instead. +func (*SummaryDataPoint) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{12} +} + +func (x *SummaryDataPoint) GetAttributes() []*v11.KeyValue { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *SummaryDataPoint) GetStartTimeUnixNano() uint64 { + if x != nil { + return x.StartTimeUnixNano + } + return 0 +} + +func (x *SummaryDataPoint) GetTimeUnixNano() uint64 { + if x != nil { + return x.TimeUnixNano + } + return 0 +} + +func (x *SummaryDataPoint) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *SummaryDataPoint) GetSum() float64 { + if x != nil { + return x.Sum + } + return 0 +} + +func (x *SummaryDataPoint) GetQuantileValues() []*SummaryDataPoint_ValueAtQuantile { + if x != nil { + return x.QuantileValues + } + return nil +} + +func (x *SummaryDataPoint) GetFlags() uint32 { + if x != nil { + return x.Flags + } + return 0 +} + +// A representation of an exemplar, which is a sample input measurement. +// Exemplars also hold information about the environment when the measurement +// was recorded, for example the span and trace ID of the active span when the +// exemplar was recorded. +type Exemplar struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of key/value pairs that were filtered out by the aggregator, but + // recorded alongside the original measurement. Only key/value pairs that were + // filtered out by the aggregator should be included + FilteredAttributes []*v11.KeyValue `protobuf:"bytes,7,rep,name=filtered_attributes,json=filteredAttributes,proto3" json:"filtered_attributes,omitempty"` + // time_unix_nano is the exact time when this exemplar was recorded + // + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January + // 1970. + TimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"` + // The value of the measurement that was recorded. An exemplar is + // considered invalid when one of the recognized value fields is not present + // inside this oneof. + // + // Types that are assignable to Value: + // *Exemplar_AsDouble + // *Exemplar_AsInt + Value isExemplar_Value `protobuf_oneof:"value"` + // (Optional) Span ID of the exemplar trace. + // span_id may be missing if the measurement is not recorded inside a trace + // or if the trace is not sampled. + SpanId []byte `protobuf:"bytes,4,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"` + // (Optional) Trace ID of the exemplar trace. + // trace_id may be missing if the measurement is not recorded inside a trace + // or if the trace is not sampled. + TraceId []byte `protobuf:"bytes,5,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` +} + +func (x *Exemplar) Reset() { + *x = Exemplar{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Exemplar) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Exemplar) ProtoMessage() {} + +func (x *Exemplar) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exemplar.ProtoReflect.Descriptor instead. +func (*Exemplar) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{13} +} + +func (x *Exemplar) GetFilteredAttributes() []*v11.KeyValue { + if x != nil { + return x.FilteredAttributes + } + return nil +} + +func (x *Exemplar) GetTimeUnixNano() uint64 { + if x != nil { + return x.TimeUnixNano + } + return 0 +} + +func (m *Exemplar) GetValue() isExemplar_Value { + if m != nil { + return m.Value + } + return nil +} + +func (x *Exemplar) GetAsDouble() float64 { + if x, ok := x.GetValue().(*Exemplar_AsDouble); ok { + return x.AsDouble + } + return 0 +} + +func (x *Exemplar) GetAsInt() int64 { + if x, ok := x.GetValue().(*Exemplar_AsInt); ok { + return x.AsInt + } + return 0 +} + +func (x *Exemplar) GetSpanId() []byte { + if x != nil { + return x.SpanId + } + return nil +} + +func (x *Exemplar) GetTraceId() []byte { + if x != nil { + return x.TraceId + } + return nil +} + +type isExemplar_Value interface { + isExemplar_Value() +} + +type Exemplar_AsDouble struct { + AsDouble float64 `protobuf:"fixed64,3,opt,name=as_double,json=asDouble,proto3,oneof"` +} + +type Exemplar_AsInt struct { + AsInt int64 `protobuf:"fixed64,6,opt,name=as_int,json=asInt,proto3,oneof"` +} + +func (*Exemplar_AsDouble) isExemplar_Value() {} + +func (*Exemplar_AsInt) isExemplar_Value() {} + +// Buckets are a set of bucket counts, encoded in a contiguous array +// of counts. +type ExponentialHistogramDataPoint_Buckets struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Offset is the bucket index of the first entry in the bucket_counts array. + // + // Note: This uses a varint encoding as a simple form of compression. + Offset int32 `protobuf:"zigzag32,1,opt,name=offset,proto3" json:"offset,omitempty"` + // bucket_counts is an array of count values, where bucket_counts[i] carries + // the count of the bucket at index (offset+i). bucket_counts[i] is the count + // of values greater than base^(offset+i) and less than or equal to + // base^(offset+i+1). + // + // Note: By contrast, the explicit HistogramDataPoint uses + // fixed64. This field is expected to have many buckets, + // especially zeros, so uint64 has been selected to ensure + // varint encoding. + BucketCounts []uint64 `protobuf:"varint,2,rep,packed,name=bucket_counts,json=bucketCounts,proto3" json:"bucket_counts,omitempty"` +} + +func (x *ExponentialHistogramDataPoint_Buckets) Reset() { + *x = ExponentialHistogramDataPoint_Buckets{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExponentialHistogramDataPoint_Buckets) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExponentialHistogramDataPoint_Buckets) ProtoMessage() {} + +func (x *ExponentialHistogramDataPoint_Buckets) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExponentialHistogramDataPoint_Buckets.ProtoReflect.Descriptor instead. +func (*ExponentialHistogramDataPoint_Buckets) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{11, 0} +} + +func (x *ExponentialHistogramDataPoint_Buckets) GetOffset() int32 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *ExponentialHistogramDataPoint_Buckets) GetBucketCounts() []uint64 { + if x != nil { + return x.BucketCounts + } + return nil +} + +// Represents the value at a given quantile of a distribution. +// +// To record Min and Max values following conventions are used: +// - The 1.0 quantile is equivalent to the maximum value observed. +// - The 0.0 quantile is equivalent to the minimum value observed. +// +// See the following issue for more context: +// https://github.com/open-telemetry/opentelemetry-proto/issues/125 +type SummaryDataPoint_ValueAtQuantile struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The quantile of a distribution. Must be in the interval + // [0.0, 1.0]. + Quantile float64 `protobuf:"fixed64,1,opt,name=quantile,proto3" json:"quantile,omitempty"` + // The value at the given quantile of a distribution. + // + // Quantile values must NOT be negative. + Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *SummaryDataPoint_ValueAtQuantile) Reset() { + *x = SummaryDataPoint_ValueAtQuantile{} + if protoimpl.UnsafeEnabled { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SummaryDataPoint_ValueAtQuantile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SummaryDataPoint_ValueAtQuantile) ProtoMessage() {} + +func (x *SummaryDataPoint_ValueAtQuantile) ProtoReflect() protoreflect.Message { + mi := &file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SummaryDataPoint_ValueAtQuantile.ProtoReflect.Descriptor instead. +func (*SummaryDataPoint_ValueAtQuantile) Descriptor() ([]byte, []int) { + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *SummaryDataPoint_ValueAtQuantile) GetQuantile() float64 { + if x != nil { + return x.Quantile + } + return 0 +} + +func (x *SummaryDataPoint_ValueAtQuantile) GetValue() float64 { + if x != nil { + return x.Value + } + return 0 +} + +var File_opentelemetry_proto_metrics_v1_metrics_proto protoreflect.FileDescriptor + +var file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc = []byte{ + 0x0a, 0x2c, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x76, 0x31, + 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, + 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2a, + 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x69, 0x0a, 0x0b, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, 0x5a, 0x0a, 0x10, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xd2, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x45, 0x0a, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x51, 0x0a, 0x0d, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x0c, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x75, 0x72, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x55, + 0x72, 0x6c, 0x4a, 0x06, 0x08, 0xe8, 0x07, 0x10, 0xe9, 0x07, 0x22, 0xba, 0x01, 0x0a, 0x0c, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x49, 0x0a, 0x05, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x72, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, + 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, + 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x55, 0x72, 0x6c, 0x22, 0xe1, 0x03, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x3d, 0x0a, 0x05, + 0x67, 0x61, 0x75, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x75, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x03, 0x73, + 0x75, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x6d, 0x48, 0x00, 0x52, + 0x03, 0x73, 0x75, 0x6d, 0x12, 0x49, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x48, 0x00, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, + 0x6b, 0x0a, 0x15, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x48, 0x00, 0x52, 0x14, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x43, 0x0a, 0x07, + 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x48, 0x00, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x42, 0x06, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, + 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0x59, 0x0a, 0x05, 0x47, + 0x61, 0x75, 0x67, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x03, 0x53, 0x75, 0x6d, 0x12, 0x50, + 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x12, 0x6f, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, + 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x16, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x6d, 0x6f, 0x6e, 0x6f, 0x74, 0x6f, 0x6e, 0x69, + 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x4d, 0x6f, 0x6e, 0x6f, 0x74, + 0x6f, 0x6e, 0x69, 0x63, 0x22, 0xd1, 0x01, 0x0a, 0x09, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x12, 0x53, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, + 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x6f, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, + 0x52, 0x16, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, + 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xe7, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x12, 0x5e, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x12, 0x6f, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, + 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x16, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x22, 0x5c, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x51, 0x0a, + 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, + 0x22, 0xd6, 0x02, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, + 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, + 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x11, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x24, + 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, + 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x1d, 0x0a, 0x09, 0x61, 0x73, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x08, 0x61, 0x73, 0x44, 0x6f, 0x75, + 0x62, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x10, 0x48, 0x00, 0x52, 0x05, 0x61, 0x73, 0x49, 0x6e, 0x74, 0x12, 0x46, 0x0a, 0x09, + 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xd9, 0x03, 0x0a, 0x12, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x09, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, + 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x03, 0x73, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, + 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x06, 0x52, 0x0c, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x01, 0x52, 0x0e, 0x65, 0x78, 0x70, + 0x6c, 0x69, 0x63, 0x69, 0x74, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x46, 0x0a, 0x09, 0x65, + 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x69, 0x6e, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x48, 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x88, 0x01, 0x01, + 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x48, 0x02, 0x52, + 0x03, 0x6d, 0x61, 0x78, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x73, 0x75, 0x6d, 0x42, + 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x69, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x61, 0x78, 0x4a, + 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xfa, 0x05, 0x0a, 0x1d, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, + 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, + 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x11, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, + 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, + 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x0a, + 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x03, 0x73, 0x75, + 0x6d, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x11, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x7a, 0x65, + 0x72, 0x6f, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x06, 0x52, 0x09, + 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x61, 0x0a, 0x08, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x61, 0x0a, 0x08, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x48, 0x69, 0x73, 0x74, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x08, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x46, 0x0a, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x72, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x72, 0x52, 0x09, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x73, 0x12, 0x15, 0x0a, + 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x48, 0x01, 0x52, 0x03, 0x6d, 0x69, + 0x6e, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x01, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x7a, + 0x65, 0x72, 0x6f, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x0d, 0x7a, 0x65, 0x72, 0x6f, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x1a, 0x46, 0x0a, 0x07, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, 0x06, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0c, 0x62, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x73, + 0x75, 0x6d, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x69, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, + 0x61, 0x78, 0x22, 0xa6, 0x03, 0x0a, 0x10, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x44, 0x61, + 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, + 0x6e, 0x69, 0x78, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x11, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, + 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x55, + 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x73, 0x75, 0x6d, 0x12, + 0x69, 0x0a, 0x0f, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x41, 0x74, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x52, 0x0e, 0x71, 0x75, 0x61, 0x6e, + 0x74, 0x69, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x1a, 0x43, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x41, 0x74, 0x51, 0x75, 0x61, 0x6e, 0x74, + 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x85, 0x02, 0x0a, 0x08, + 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, 0x58, 0x0a, 0x13, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, + 0x6e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65, + 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x1d, 0x0a, 0x09, 0x61, 0x73, 0x5f, 0x64, + 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x08, 0x61, + 0x73, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x73, 0x5f, 0x69, 0x6e, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, 0x48, 0x00, 0x52, 0x05, 0x61, 0x73, 0x49, 0x6e, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72, 0x61, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x74, 0x72, 0x61, + 0x63, 0x65, 0x49, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4a, 0x04, 0x08, + 0x01, 0x10, 0x02, 0x2a, 0x8c, 0x01, 0x0a, 0x16, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x27, + 0x0a, 0x23, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x45, + 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x41, 0x47, 0x47, 0x52, 0x45, + 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x4c, 0x49, + 0x54, 0x59, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x01, 0x12, 0x26, 0x0a, 0x22, 0x41, 0x47, + 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, + 0x41, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x55, 0x4d, 0x55, 0x4c, 0x41, 0x54, 0x49, 0x56, 0x45, + 0x10, 0x02, 0x2a, 0x5e, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a, 0x1b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, 0x49, + 0x4e, 0x54, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x4f, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, + 0x55, 0x53, 0x45, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x27, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x50, 0x4f, + 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x4c, 0x41, 0x47, 0x53, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x45, 0x43, + 0x4f, 0x52, 0x44, 0x45, 0x44, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5f, 0x4d, 0x41, 0x53, 0x4b, + 0x10, 0x01, 0x42, 0x7f, 0x0a, 0x21, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x6f, 0x74, 0x6c, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, + 0x76, 0x31, 0xaa, 0x02, 0x1e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescOnce sync.Once + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData = file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc +) + +func file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescGZIP() []byte { + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescOnce.Do(func() { + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData) + }) + return file_opentelemetry_proto_metrics_v1_metrics_proto_rawDescData +} + +var file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes = []interface{}{ + (AggregationTemporality)(0), // 0: opentelemetry.proto.metrics.v1.AggregationTemporality + (DataPointFlags)(0), // 1: opentelemetry.proto.metrics.v1.DataPointFlags + (*MetricsData)(nil), // 2: opentelemetry.proto.metrics.v1.MetricsData + (*ResourceMetrics)(nil), // 3: opentelemetry.proto.metrics.v1.ResourceMetrics + (*ScopeMetrics)(nil), // 4: opentelemetry.proto.metrics.v1.ScopeMetrics + (*Metric)(nil), // 5: opentelemetry.proto.metrics.v1.Metric + (*Gauge)(nil), // 6: opentelemetry.proto.metrics.v1.Gauge + (*Sum)(nil), // 7: opentelemetry.proto.metrics.v1.Sum + (*Histogram)(nil), // 8: opentelemetry.proto.metrics.v1.Histogram + (*ExponentialHistogram)(nil), // 9: opentelemetry.proto.metrics.v1.ExponentialHistogram + (*Summary)(nil), // 10: opentelemetry.proto.metrics.v1.Summary + (*NumberDataPoint)(nil), // 11: opentelemetry.proto.metrics.v1.NumberDataPoint + (*HistogramDataPoint)(nil), // 12: opentelemetry.proto.metrics.v1.HistogramDataPoint + (*ExponentialHistogramDataPoint)(nil), // 13: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint + (*SummaryDataPoint)(nil), // 14: opentelemetry.proto.metrics.v1.SummaryDataPoint + (*Exemplar)(nil), // 15: opentelemetry.proto.metrics.v1.Exemplar + (*ExponentialHistogramDataPoint_Buckets)(nil), // 16: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.Buckets + (*SummaryDataPoint_ValueAtQuantile)(nil), // 17: opentelemetry.proto.metrics.v1.SummaryDataPoint.ValueAtQuantile + (*v1.Resource)(nil), // 18: opentelemetry.proto.resource.v1.Resource + (*v11.InstrumentationScope)(nil), // 19: opentelemetry.proto.common.v1.InstrumentationScope + (*v11.KeyValue)(nil), // 20: opentelemetry.proto.common.v1.KeyValue +} +var file_opentelemetry_proto_metrics_v1_metrics_proto_depIdxs = []int32{ + 3, // 0: opentelemetry.proto.metrics.v1.MetricsData.resource_metrics:type_name -> opentelemetry.proto.metrics.v1.ResourceMetrics + 18, // 1: opentelemetry.proto.metrics.v1.ResourceMetrics.resource:type_name -> opentelemetry.proto.resource.v1.Resource + 4, // 2: opentelemetry.proto.metrics.v1.ResourceMetrics.scope_metrics:type_name -> opentelemetry.proto.metrics.v1.ScopeMetrics + 19, // 3: opentelemetry.proto.metrics.v1.ScopeMetrics.scope:type_name -> opentelemetry.proto.common.v1.InstrumentationScope + 5, // 4: opentelemetry.proto.metrics.v1.ScopeMetrics.metrics:type_name -> opentelemetry.proto.metrics.v1.Metric + 6, // 5: opentelemetry.proto.metrics.v1.Metric.gauge:type_name -> opentelemetry.proto.metrics.v1.Gauge + 7, // 6: opentelemetry.proto.metrics.v1.Metric.sum:type_name -> opentelemetry.proto.metrics.v1.Sum + 8, // 7: opentelemetry.proto.metrics.v1.Metric.histogram:type_name -> opentelemetry.proto.metrics.v1.Histogram + 9, // 8: opentelemetry.proto.metrics.v1.Metric.exponential_histogram:type_name -> opentelemetry.proto.metrics.v1.ExponentialHistogram + 10, // 9: opentelemetry.proto.metrics.v1.Metric.summary:type_name -> opentelemetry.proto.metrics.v1.Summary + 11, // 10: opentelemetry.proto.metrics.v1.Gauge.data_points:type_name -> opentelemetry.proto.metrics.v1.NumberDataPoint + 11, // 11: opentelemetry.proto.metrics.v1.Sum.data_points:type_name -> opentelemetry.proto.metrics.v1.NumberDataPoint + 0, // 12: opentelemetry.proto.metrics.v1.Sum.aggregation_temporality:type_name -> opentelemetry.proto.metrics.v1.AggregationTemporality + 12, // 13: opentelemetry.proto.metrics.v1.Histogram.data_points:type_name -> opentelemetry.proto.metrics.v1.HistogramDataPoint + 0, // 14: opentelemetry.proto.metrics.v1.Histogram.aggregation_temporality:type_name -> opentelemetry.proto.metrics.v1.AggregationTemporality + 13, // 15: opentelemetry.proto.metrics.v1.ExponentialHistogram.data_points:type_name -> opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint + 0, // 16: opentelemetry.proto.metrics.v1.ExponentialHistogram.aggregation_temporality:type_name -> opentelemetry.proto.metrics.v1.AggregationTemporality + 14, // 17: opentelemetry.proto.metrics.v1.Summary.data_points:type_name -> opentelemetry.proto.metrics.v1.SummaryDataPoint + 20, // 18: opentelemetry.proto.metrics.v1.NumberDataPoint.attributes:type_name -> opentelemetry.proto.common.v1.KeyValue + 15, // 19: opentelemetry.proto.metrics.v1.NumberDataPoint.exemplars:type_name -> opentelemetry.proto.metrics.v1.Exemplar + 20, // 20: opentelemetry.proto.metrics.v1.HistogramDataPoint.attributes:type_name -> opentelemetry.proto.common.v1.KeyValue + 15, // 21: opentelemetry.proto.metrics.v1.HistogramDataPoint.exemplars:type_name -> opentelemetry.proto.metrics.v1.Exemplar + 20, // 22: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.attributes:type_name -> opentelemetry.proto.common.v1.KeyValue + 16, // 23: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.positive:type_name -> opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.Buckets + 16, // 24: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.negative:type_name -> opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.Buckets + 15, // 25: opentelemetry.proto.metrics.v1.ExponentialHistogramDataPoint.exemplars:type_name -> opentelemetry.proto.metrics.v1.Exemplar + 20, // 26: opentelemetry.proto.metrics.v1.SummaryDataPoint.attributes:type_name -> opentelemetry.proto.common.v1.KeyValue + 17, // 27: opentelemetry.proto.metrics.v1.SummaryDataPoint.quantile_values:type_name -> opentelemetry.proto.metrics.v1.SummaryDataPoint.ValueAtQuantile + 20, // 28: opentelemetry.proto.metrics.v1.Exemplar.filtered_attributes:type_name -> opentelemetry.proto.common.v1.KeyValue + 29, // [29:29] is the sub-list for method output_type + 29, // [29:29] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name +} + +func init() { file_opentelemetry_proto_metrics_v1_metrics_proto_init() } +func file_opentelemetry_proto_metrics_v1_metrics_proto_init() { + if File_opentelemetry_proto_metrics_v1_metrics_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetricsData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResourceMetrics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScopeMetrics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metric); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Gauge); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Sum); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Histogram); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExponentialHistogram); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Summary); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NumberDataPoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HistogramDataPoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExponentialHistogramDataPoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SummaryDataPoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Exemplar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExponentialHistogramDataPoint_Buckets); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SummaryDataPoint_ValueAtQuantile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[3].OneofWrappers = []interface{}{ + (*Metric_Gauge)(nil), + (*Metric_Sum)(nil), + (*Metric_Histogram)(nil), + (*Metric_ExponentialHistogram)(nil), + (*Metric_Summary)(nil), + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[9].OneofWrappers = []interface{}{ + (*NumberDataPoint_AsDouble)(nil), + (*NumberDataPoint_AsInt)(nil), + } + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[10].OneofWrappers = []interface{}{} + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[11].OneofWrappers = []interface{}{} + file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes[13].OneofWrappers = []interface{}{ + (*Exemplar_AsDouble)(nil), + (*Exemplar_AsInt)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc, + NumEnums: 2, + NumMessages: 16, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes, + DependencyIndexes: file_opentelemetry_proto_metrics_v1_metrics_proto_depIdxs, + EnumInfos: file_opentelemetry_proto_metrics_v1_metrics_proto_enumTypes, + MessageInfos: file_opentelemetry_proto_metrics_v1_metrics_proto_msgTypes, + }.Build() + File_opentelemetry_proto_metrics_v1_metrics_proto = out.File + file_opentelemetry_proto_metrics_v1_metrics_proto_rawDesc = nil + file_opentelemetry_proto_metrics_v1_metrics_proto_goTypes = nil + file_opentelemetry_proto_metrics_v1_metrics_proto_depIdxs = nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4e25781e31693..a60b3c6ccc4f0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -251,7 +251,7 @@ github.com/containerd/cgroups/v3/cgroup1 github.com/containerd/cgroups/v3/cgroup1/stats github.com/containerd/cgroups/v3/cgroup2 github.com/containerd/cgroups/v3/cgroup2/stats -# github.com/containerd/console v1.0.3 +# github.com/containerd/console v1.0.4 ## explicit; go 1.13 github.com/containerd/console # github.com/containerd/containerd v1.7.13 @@ -386,7 +386,7 @@ github.com/containerd/nydus-snapshotter/pkg/converter github.com/containerd/nydus-snapshotter/pkg/converter/tool github.com/containerd/nydus-snapshotter/pkg/errdefs github.com/containerd/nydus-snapshotter/pkg/label -# github.com/containerd/stargz-snapshotter/estargz v0.14.3 +# github.com/containerd/stargz-snapshotter/estargz v0.15.1 ## explicit; go 1.19 github.com/containerd/stargz-snapshotter/estargz github.com/containerd/stargz-snapshotter/estargz/errorutil @@ -408,6 +408,9 @@ github.com/containernetworking/cni/pkg/types/create github.com/containernetworking/cni/pkg/types/internal github.com/containernetworking/cni/pkg/utils github.com/containernetworking/cni/pkg/version +# github.com/containernetworking/plugins v1.4.0 +## explicit; go 1.20 +github.com/containernetworking/plugins/pkg/ns # github.com/coreos/go-systemd/v22 v22.5.0 ## explicit; go 1.12 github.com/coreos/go-systemd/v22/activation @@ -441,7 +444,6 @@ github.com/docker/distribution/manifest/ocischema github.com/docker/distribution/manifest/schema1 github.com/docker/distribution/manifest/schema2 github.com/docker/distribution/metrics -github.com/docker/distribution/reference github.com/docker/distribution/registry/api/errcode github.com/docker/distribution/registry/api/v2 github.com/docker/distribution/registry/client @@ -698,8 +700,8 @@ github.com/mitchellh/hashstructure/v2 # github.com/mitchellh/reflectwalk v1.0.2 ## explicit github.com/mitchellh/reflectwalk -# github.com/moby/buildkit v0.12.5 -## explicit; go 1.20 +# github.com/moby/buildkit v0.13.0-rc2 +## explicit; go 1.21 github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/types github.com/moby/buildkit/cache @@ -718,6 +720,7 @@ github.com/moby/buildkit/client/buildid github.com/moby/buildkit/client/connhelper github.com/moby/buildkit/client/llb github.com/moby/buildkit/client/llb/imagemetaresolver +github.com/moby/buildkit/client/llb/sourceresolver github.com/moby/buildkit/client/ociindex github.com/moby/buildkit/cmd/buildkitd/config github.com/moby/buildkit/control @@ -732,7 +735,6 @@ github.com/moby/buildkit/exporter github.com/moby/buildkit/exporter/attestation github.com/moby/buildkit/exporter/containerimage github.com/moby/buildkit/exporter/containerimage/exptypes -github.com/moby/buildkit/exporter/containerimage/image github.com/moby/buildkit/exporter/exptypes github.com/moby/buildkit/exporter/local github.com/moby/buildkit/exporter/oci @@ -744,7 +746,6 @@ github.com/moby/buildkit/frontend/attestations/sbom github.com/moby/buildkit/frontend/dockerfile/builder github.com/moby/buildkit/frontend/dockerfile/command github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb -github.com/moby/buildkit/frontend/dockerfile/dockerignore github.com/moby/buildkit/frontend/dockerfile/instructions github.com/moby/buildkit/frontend/dockerfile/parser github.com/moby/buildkit/frontend/dockerfile/shell @@ -802,6 +803,8 @@ github.com/moby/buildkit/util/bklog github.com/moby/buildkit/util/compression github.com/moby/buildkit/util/cond github.com/moby/buildkit/util/contentutil +github.com/moby/buildkit/util/converter +github.com/moby/buildkit/util/converter/tarconverter github.com/moby/buildkit/util/entitlements github.com/moby/buildkit/util/entitlements/security github.com/moby/buildkit/util/estargz @@ -843,6 +846,7 @@ github.com/moby/buildkit/util/tracing/otlptracegrpc github.com/moby/buildkit/util/tracing/transform github.com/moby/buildkit/util/urlutil github.com/moby/buildkit/util/wildcard +github.com/moby/buildkit/util/windows github.com/moby/buildkit/util/winlayers github.com/moby/buildkit/version github.com/moby/buildkit/worker @@ -1063,8 +1067,8 @@ github.com/syndtr/gocapability/capability # github.com/tinylib/msgp v1.1.8 ## explicit; go 1.15 github.com/tinylib/msgp/msgp -# github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb -## explicit; go 1.19 +# github.com/tonistiigi/fsutil v0.0.0-20240223190444-7a889f53dbf6 +## explicit; go 1.20 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy github.com/tonistiigi/fsutil/types @@ -1185,6 +1189,25 @@ go.opentelemetry.io/otel/internal/global go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/semconv/v1.17.0 go.opentelemetry.io/otel/semconv/v1.21.0 +# go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 +## explicit; go 1.20 +go.opentelemetry.io/otel/exporters/otlp/otlpmetric +# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 +## explicit; go 1.20 +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform +# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 +## explicit; go 1.20 +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/transform # go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 ## explicit; go 1.20 go.opentelemetry.io/otel/exporters/otlp/otlptrace @@ -1203,10 +1226,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/envconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/retry +# go.opentelemetry.io/otel/exporters/prometheus v0.42.0 +## explicit; go 1.20 +go.opentelemetry.io/otel/exporters/prometheus # go.opentelemetry.io/otel/metric v1.21.0 ## explicit; go 1.20 go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric/embedded +go.opentelemetry.io/otel/metric/noop # go.opentelemetry.io/otel/sdk v1.21.0 ## explicit; go 1.20 go.opentelemetry.io/otel/sdk @@ -1216,6 +1243,12 @@ go.opentelemetry.io/otel/sdk/internal/env go.opentelemetry.io/otel/sdk/resource go.opentelemetry.io/otel/sdk/trace go.opentelemetry.io/otel/sdk/trace/tracetest +# go.opentelemetry.io/otel/sdk/metric v1.21.0 +## explicit; go 1.20 +go.opentelemetry.io/otel/sdk/metric +go.opentelemetry.io/otel/sdk/metric/internal +go.opentelemetry.io/otel/sdk/metric/internal/aggregate +go.opentelemetry.io/otel/sdk/metric/metricdata # go.opentelemetry.io/otel/trace v1.21.0 ## explicit; go 1.20 go.opentelemetry.io/otel/trace @@ -1223,8 +1256,10 @@ go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/noop # go.opentelemetry.io/proto/otlp v1.0.0 ## explicit; go 1.17 +go.opentelemetry.io/proto/otlp/collector/metrics/v1 go.opentelemetry.io/proto/otlp/collector/trace/v1 go.opentelemetry.io/proto/otlp/common/v1 +go.opentelemetry.io/proto/otlp/metrics/v1 go.opentelemetry.io/proto/otlp/resource/v1 go.opentelemetry.io/proto/otlp/trace/v1 # go.uber.org/atomic v1.9.0