From 932e7ceecf85aa15b9f855eec47d62c4e8cd254f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:13:15 +0100 Subject: [PATCH] build(deps): bump dagger/dagger-for-github from 6.14.0 to 7.0.1 (#1224) * build(deps): bump dagger/dagger-for-github from 6.14.0 to 7.0.0 Bumps [dagger/dagger-for-github](https://github.com/dagger/dagger-for-github) from 6.14.0 to 7.0.0. - [Release notes](https://github.com/dagger/dagger-for-github/releases) - [Commits](https://github.com/dagger/dagger-for-github/compare/ad6a4e308a42fb2cf9be8b060f9aba9d57d4c9aa...a320953b08a879f11d75f5dcc5d6f80740666be9) --- updated-dependencies: - dependency-name: dagger/dagger-for-github dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump go version in acceptance tests * Update dagger to 0.14.0 * Update to dagger action 7.0.1 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Horst Gutmann --- .github/workflows/acceptance-tests.yml | 4 +- acceptance-tests/go.mod | 2 +- dagger.json | 5 +- dagger/dagger.gen.go | 17 +- dagger/go.mod | 5 +- dagger/go.sum | 6 + dagger/internal/dagger/dagger.gen.go | 1371 ++++++++++++++---------- dagger/internal/telemetry/attrs.go | 6 + dagger/internal/telemetry/init.go | 148 ++- dagger/internal/telemetry/logging.go | 2 +- dagger/internal/telemetry/metrics.go | 61 ++ dagger/internal/telemetry/transform.go | 527 ++++++++- go.work.sum | 9 +- 13 files changed, 1527 insertions(+), 636 deletions(-) create mode 100644 dagger/internal/telemetry/metrics.go diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index bad0989a8..bd2b92fa4 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -17,9 +17,9 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Call Dagger Function id: dagger - uses: dagger/dagger-for-github@ad6a4e308a42fb2cf9be8b060f9aba9d57d4c9aa # v6.14.0 + uses: dagger/dagger-for-github@e5153f5610d82ac9f3f848f3a25ad9d696641068 # v7.0.1 with: - version: "0.12.7" + version: "0.14.0" verb: call dagger-flags: "--silent" args: "acceptance-tests --root-dir .:source-files --acceptance-tests-dir ./acceptance-tests" diff --git a/acceptance-tests/go.mod b/acceptance-tests/go.mod index 44f521e40..dac55558e 100644 --- a/acceptance-tests/go.mod +++ b/acceptance-tests/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/tanka/acceptance-tests -go 1.22.4 +go 1.23.0 require ( github.com/stretchr/testify v1.9.0 diff --git a/dagger.json b/dagger.json index f4053ad5e..de31c32ed 100644 --- a/dagger.json +++ b/dagger.json @@ -1,14 +1,15 @@ { "name": "tanka", + "engineVersion": "v0.14.0", "sdk": "go", "dependencies": [ { "name": "k3s", - "source": "github.com/marcosnils/daggerverse/k3s@e0bd6b9f5519c49db4b6eb0689927214720976f9" + "source": "github.com/marcosnils/daggerverse/k3s@e0bd6b9f5519c49db4b6eb0689927214720976f9", + "pin": "e0bd6b9f5519c49db4b6eb0689927214720976f9" } ], "source": "dagger", - "engineVersion": "v0.12.7", "views": [ { "name": "source-files", diff --git a/dagger/dagger.gen.go b/dagger/dagger.gen.go index a7e9c195d..4e9cd97b7 100644 --- a/dagger/dagger.gen.go +++ b/dagger/dagger.gen.go @@ -199,20 +199,23 @@ func invoke(ctx context.Context, parentJSON []byte, parentName string, fnName st case "": return dag.Module(). WithObject( - dag.TypeDef().WithObject("Tanka"). + dag.TypeDef().WithObject("Tanka", dagger.TypeDefWithObjectOpts{SourceMap: dag.SourceMap("main.go", 13, 6)}). WithFunction( dag.Function("Build", dag.TypeDef().WithObject("Container")). - WithArg("rootDir", dag.TypeDef().WithObject("Directory"))). + WithSourceMap(dag.SourceMap("main.go", 15, 1)). + WithArg("rootDir", dag.TypeDef().WithObject("Directory"), dagger.FunctionWithArgOpts{SourceMap: dag.SourceMap("main.go", 15, 44)})). WithFunction( dag.Function("GetGoVersion", - dag.TypeDef().WithKind(dagger.StringKind)). - WithArg("file", dag.TypeDef().WithObject("File"))). + dag.TypeDef().WithKind(dagger.TypeDefKindStringKind)). + WithSourceMap(dag.SourceMap("main.go", 20, 1)). + WithArg("file", dag.TypeDef().WithObject("File"), dagger.FunctionWithArgOpts{SourceMap: dag.SourceMap("main.go", 20, 51)})). WithFunction( dag.Function("AcceptanceTests", - dag.TypeDef().WithKind(dagger.StringKind)). - WithArg("rootDir", dag.TypeDef().WithObject("Directory")). - WithArg("acceptanceTestsDir", dag.TypeDef().WithObject("Directory")))), nil + dag.TypeDef().WithKind(dagger.TypeDefKindStringKind)). + WithSourceMap(dag.SourceMap("main.go", 36, 1)). + WithArg("rootDir", dag.TypeDef().WithObject("Directory"), dagger.FunctionWithArgOpts{SourceMap: dag.SourceMap("main.go", 36, 54)}). + WithArg("acceptanceTestsDir", dag.TypeDef().WithObject("Directory"), dagger.FunctionWithArgOpts{SourceMap: dag.SourceMap("main.go", 36, 81)}))), nil default: return nil, fmt.Errorf("unknown object %s", parentName) } diff --git a/dagger/go.mod b/dagger/go.mod index 7f5168d39..0213789d6 100644 --- a/dagger/go.mod +++ b/dagger/go.mod @@ -26,10 +26,13 @@ require ( github.com/sosodev/duration v1.3.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.5.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.5.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect go.opentelemetry.io/otel/log v0.5.0 - go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 go.opentelemetry.io/otel/sdk/log v0.5.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/proto/otlp v1.3.1 golang.org/x/net v0.30.0 // indirect golang.org/x/sys v0.27.0 // indirect diff --git a/dagger/go.sum b/dagger/go.sum index bec61913f..43c20e462 100644 --- a/dagger/go.sum +++ b/dagger/go.sum @@ -43,6 +43,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-2024051809000 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88/go.mod h1:JGG8ebaMO5nXOPnvKEl+DiA4MGwFjCbjsxT1WHIEBPY= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 h1:ccBrA8nCY5mM0y5uO7FT0ze4S0TuFcWdDB2FxGMTjkI= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0/go.mod h1:/9pb6634zi2Lk8LYg9Q0X8Ar6jka4dkFOylBLbVQPCE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 h1:bFgvUr3/O4PHj3VQcFEuYKvRZJX1SJDQ+11JXuSB3/w= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0/go.mod h1:xJntEd2KL6Qdg5lwp97HMLQDVeAhrYxmzFseAMDPQ8I= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 h1:CIHWikMsN3wO+wq1Tp5VGdVRTcON+DmOJSfDjXypKOc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0/go.mod h1:TNupZ6cxqyFEpLXAZW7On+mLFL0/g0TE3unIYL91xWc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= @@ -57,6 +61,8 @@ go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5l go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk/log v0.3.0 h1:GEjJ8iftz2l+XO1GF2856r7yYVh74URiF9JMcAacr5U= go.opentelemetry.io/otel/sdk/log v0.3.0/go.mod h1:BwCxtmux6ACLuys1wlbc0+vGBd+xytjmjajwqqIul2g= +go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= +go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= diff --git a/dagger/internal/dagger/dagger.gen.go b/dagger/internal/dagger/dagger.gen.go index 9b54e15b1..a76cffe68 100644 --- a/dagger/internal/dagger/dagger.gen.go +++ b/dagger/internal/dagger/dagger.gen.go @@ -131,15 +131,6 @@ type ContainerID string // The `CurrentModuleID` scalar type represents an identifier for an object of type CurrentModule. type CurrentModuleID string -// The `DaggerEngineCacheEntryID` scalar type represents an identifier for an object of type DaggerEngineCacheEntry. -type DaggerEngineCacheEntryID string - -// The `DaggerEngineCacheEntrySetID` scalar type represents an identifier for an object of type DaggerEngineCacheEntrySet. -type DaggerEngineCacheEntrySetID string - -// The `DaggerEngineCacheID` scalar type represents an identifier for an object of type DaggerEngineCache. -type DaggerEngineCacheID string - // The `DirectoryID` scalar type represents an identifier for an object of type Directory. type DirectoryID string @@ -238,6 +229,9 @@ type ServiceID string // The `SocketID` scalar type represents an identifier for an object of type Socket. type SocketID string +// The `SourceMapID` scalar type represents an identifier for an object of type SourceMap. +type SourceMapID string + // The `TerminalID` scalar type represents an identifier for an object of type Terminal. type TerminalID string @@ -346,6 +340,7 @@ type Container struct { query *querybuilder.Selection envVariable *string + exitCode *int export *string id *ContainerID imageRef *string @@ -355,6 +350,7 @@ type Container struct { stderr *string stdout *string sync *ContainerID + up *Void user *string workdir *string } @@ -478,11 +474,23 @@ func (r *Container) DefaultArgs(ctx context.Context) ([]string, error) { return response, q.Execute(ctx) } +// ContainerDirectoryOpts contains options for Container.Directory +type ContainerDirectoryOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves a directory at the given path. // // Mounts are included. -func (r *Container) Directory(path string) *Directory { +func (r *Container) Directory(path string, opts ...ContainerDirectoryOpts) *Directory { q := r.query.Select("directory") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Directory{ @@ -547,6 +555,21 @@ func (r *Container) EnvVariables(ctx context.Context) ([]EnvVariable, error) { return convert(response), nil } +// The exit code of the last executed command. +// +// Returns an error if no command was set. +func (r *Container) ExitCode(ctx context.Context) (int, error) { + if r.exitCode != nil { + return *r.exitCode, nil + } + q := r.query.Select("exitCode") + + var response int + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + // EXPERIMENTAL API! Subject to change/removal at any time. // // Configures all available GPUs on the host to be accessible to this container. @@ -588,6 +611,8 @@ type ContainerExportOpts struct { // // Defaults to OCI, which is largely compatible with most recent container runtimes, but Docker may be needed for older runtimes without OCI support. MediaTypes ImageMediaTypes + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Writes the container as an OCI tarball to the destination file path on the host. @@ -611,6 +636,10 @@ func (r *Container) Export(ctx context.Context, path string, opts ...ContainerEx if !querybuilder.IsZeroValue(opts[i].MediaTypes) { q = q.Arg("mediaTypes", opts[i].MediaTypes) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) @@ -655,11 +684,23 @@ func (r *Container) ExposedPorts(ctx context.Context) ([]Port, error) { return convert(response), nil } +// ContainerFileOpts contains options for Container.File +type ContainerFileOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool +} + // Retrieves a file at the given path. // // Mounts are included. -func (r *Container) File(path string) *File { +func (r *Container) File(path string, opts ...ContainerFileOpts) *File { q := r.query.Select("file") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &File{ @@ -819,36 +860,6 @@ func (r *Container) Mounts(ctx context.Context) ([]string, error) { return response, q.Execute(ctx) } -// ContainerPipelineOpts contains options for Container.Pipeline -type ContainerPipelineOpts struct { - // Description of the sub-pipeline. - Description string - // Labels to apply to the sub-pipeline. - Labels []PipelineLabel -} - -// Creates a named sub-pipeline. -// -// Deprecated: Explicit pipeline creation is now a no-op -func (r *Container) Pipeline(name string, opts ...ContainerPipelineOpts) *Container { - q := r.query.Select("pipeline") - for i := len(opts) - 1; i >= 0; i-- { - // `description` optional argument - if !querybuilder.IsZeroValue(opts[i].Description) { - q = q.Arg("description", opts[i].Description) - } - // `labels` optional argument - if !querybuilder.IsZeroValue(opts[i].Labels) { - q = q.Arg("labels", opts[i].Labels) - } - } - q = q.Arg("name", name) - - return &Container{ - query: q, - } -} - // The platform this container executes and publishes as. func (r *Container) Platform(ctx context.Context) (Platform, error) { if r.platform != nil { @@ -921,7 +932,7 @@ func (r *Container) Rootfs() *Directory { // The error stream of the last executed command. // -// Will execute default command if none is set, or error if there's no default. +// Returns an error if no command was set. func (r *Container) Stderr(ctx context.Context) (string, error) { if r.stderr != nil { return *r.stderr, nil @@ -936,7 +947,7 @@ func (r *Container) Stderr(ctx context.Context) (string, error) { // The output stream of the last executed command. // -// Will execute default command if none is set, or error if there's no default. +// Returns an error if no command was set. func (r *Container) Stdout(ctx context.Context) (string, error) { if r.stdout != nil { return *r.stdout, nil @@ -999,6 +1010,38 @@ func (r *Container) Terminal(opts ...ContainerTerminalOpts) *Container { } } +// ContainerUpOpts contains options for Container.Up +type ContainerUpOpts struct { + // List of frontend/backend port mappings to forward. + // + // Frontend is the port accepting traffic on the host, backend is the service port. + Ports []PortForward + // Bind each tunnel port to a random port on the host. + Random bool +} + +// Starts a Service and creates a tunnel that forwards traffic from the caller's network to that service. +// +// Be sure to set any exposed ports before calling this api. +func (r *Container) Up(ctx context.Context, opts ...ContainerUpOpts) error { + if r.up != nil { + return nil + } + q := r.query.Select("up") + for i := len(opts) - 1; i >= 0; i-- { + // `ports` optional argument + if !querybuilder.IsZeroValue(opts[i].Ports) { + q = q.Arg("ports", opts[i].Ports) + } + // `random` optional argument + if !querybuilder.IsZeroValue(opts[i].Random) { + q = q.Arg("random", opts[i].Random) + } + } + + return q.Execute(ctx) +} + // Retrieves the user to be set for all commands. func (r *Container) User(ctx context.Context) (string, error) { if r.user != nil { @@ -1012,6 +1055,17 @@ func (r *Container) User(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// Retrieves this container plus the given OCI anotation. +func (r *Container) WithAnnotation(name string, value string) *Container { + q := r.query.Select("withAnnotation") + q = q.Arg("name", name) + q = q.Arg("value", value) + + return &Container{ + query: q, + } +} + // Configures default arguments for future commands. func (r *Container) WithDefaultArgs(args []string) *Container { q := r.query.Select("withDefaultArgs") @@ -1064,6 +1118,8 @@ type ContainerWithDirectoryOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Retrieves this container plus a directory written at the given path. @@ -1083,6 +1139,10 @@ func (r *Container) WithDirectory(path string, directory *Directory, opts ...Con if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("directory", directory) @@ -1116,7 +1176,7 @@ func (r *Container) WithEntrypoint(args []string, opts ...ContainerWithEntrypoin // ContainerWithEnvVariableOpts contains options for Container.WithEnvVariable type ContainerWithEnvVariableOpts struct { - // Replace `${VAR}` or `$VAR` in the value according to the current environment variables defined in the container (e.g., "/opt/bin:$PATH"). + // Replace "${VAR}" or "$VAR" in the value according to the current environment variables defined in the container (e.g. "/opt/bin:$PATH"). Expand bool } @@ -1139,8 +1199,6 @@ func (r *Container) WithEnvVariable(name string, value string, opts ...Container // ContainerWithExecOpts contains options for Container.WithExec type ContainerWithExecOpts struct { - // DEPRECATED: For true this can be removed. For false, use `useEntrypoint` instead. - SkipEntrypoint bool // If the container has an entrypoint, prepend it to the args. UseEntrypoint bool // Content to write to the command's standard input before closing (e.g., "Hello world"). @@ -1149,22 +1207,26 @@ type ContainerWithExecOpts struct { RedirectStdout string // Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr"). RedirectStderr string + // Exit codes this command is allowed to exit with without error + Expect ReturnType // Provides Dagger access to the executed command. // // Do not use this option unless you trust the command being executed; the command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. ExperimentalPrivilegedNesting bool // Execute the command with all root capabilities. This is similar to running a command with "sudo" or executing "docker run" with the "--privileged" flag. Containerization does not provide any security guarantees when using this option. It should only be used when absolutely necessary and only with trusted commands. InsecureRootCapabilities bool + // Replace "${VAR}" or "$VAR" in the args according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool + // If set, skip the automatic init process injected into containers by default. + // + // This should only be used if the user requires that their exec process be the pid 1 process in the container. Otherwise it may result in unexpected behavior. + NoInit bool } // Retrieves this container after executing the specified command inside it. func (r *Container) WithExec(args []string, opts ...ContainerWithExecOpts) *Container { q := r.query.Select("withExec") for i := len(opts) - 1; i >= 0; i-- { - // `skipEntrypoint` optional argument - if !querybuilder.IsZeroValue(opts[i].SkipEntrypoint) { - q = q.Arg("skipEntrypoint", opts[i].SkipEntrypoint) - } // `useEntrypoint` optional argument if !querybuilder.IsZeroValue(opts[i].UseEntrypoint) { q = q.Arg("useEntrypoint", opts[i].UseEntrypoint) @@ -1181,6 +1243,10 @@ func (r *Container) WithExec(args []string, opts ...ContainerWithExecOpts) *Cont if !querybuilder.IsZeroValue(opts[i].RedirectStderr) { q = q.Arg("redirectStderr", opts[i].RedirectStderr) } + // `expect` optional argument + if !querybuilder.IsZeroValue(opts[i].Expect) { + q = q.Arg("expect", opts[i].Expect) + } // `experimentalPrivilegedNesting` optional argument if !querybuilder.IsZeroValue(opts[i].ExperimentalPrivilegedNesting) { q = q.Arg("experimentalPrivilegedNesting", opts[i].ExperimentalPrivilegedNesting) @@ -1189,6 +1255,14 @@ func (r *Container) WithExec(args []string, opts ...ContainerWithExecOpts) *Cont if !querybuilder.IsZeroValue(opts[i].InsecureRootCapabilities) { q = q.Arg("insecureRootCapabilities", opts[i].InsecureRootCapabilities) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + // `noInit` optional argument + if !querybuilder.IsZeroValue(opts[i].NoInit) { + q = q.Arg("noInit", opts[i].NoInit) + } } q = q.Arg("args", args) @@ -1247,6 +1321,8 @@ type ContainerWithFileOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool } // Retrieves this container plus the contents of the given file copied to the given path. @@ -1262,6 +1338,10 @@ func (r *Container) WithFile(path string, source *File, opts ...ContainerWithFil if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("source", source) @@ -1281,6 +1361,8 @@ type ContainerWithFilesOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool } // Retrieves this container plus the contents of the given files copied to the given path. @@ -1295,6 +1377,10 @@ func (r *Container) WithFiles(path string, sources []*File, opts ...ContainerWit if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("sources", sources) @@ -1304,15 +1390,6 @@ func (r *Container) WithFiles(path string, sources []*File, opts ...ContainerWit } } -// Indicate that subsequent operations should be featured more prominently in the UI. -func (r *Container) WithFocus() *Container { - q := r.query.Select("withFocus") - - return &Container{ - query: q, - } -} - // Retrieves this container plus the given label. func (r *Container) WithLabel(name string, value string) *Container { q := r.query.Select("withLabel") @@ -1338,6 +1415,8 @@ type ContainerWithMountedCacheOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Retrieves this container plus a cache volume mounted at the given path. @@ -1357,6 +1436,10 @@ func (r *Container) WithMountedCache(path string, cache *CacheVolume, opts ...Co if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("cache", cache) @@ -1374,6 +1457,8 @@ type ContainerWithMountedDirectoryOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Retrieves this container plus a directory mounted at the given path. @@ -1385,6 +1470,10 @@ func (r *Container) WithMountedDirectory(path string, source *Directory, opts .. if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("source", source) @@ -1402,6 +1491,8 @@ type ContainerWithMountedFileOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool } // Retrieves this container plus a file mounted at the given path. @@ -1413,6 +1504,10 @@ func (r *Container) WithMountedFile(path string, source *File, opts ...Container if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("source", source) @@ -1434,6 +1529,8 @@ type ContainerWithMountedSecretOpts struct { // // This option requires an owner to be set to be active. Mode int + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Retrieves this container plus a secret mounted into a file at the given path. @@ -1449,6 +1546,10 @@ func (r *Container) WithMountedSecret(path string, source *Secret, opts ...Conta if !querybuilder.IsZeroValue(opts[i].Mode) { q = q.Arg("mode", opts[i].Mode) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("source", source) @@ -1458,9 +1559,27 @@ func (r *Container) WithMountedSecret(path string, source *Secret, opts ...Conta } } +// ContainerWithMountedTempOpts contains options for Container.WithMountedTemp +type ContainerWithMountedTempOpts struct { + // Size of the temporary directory in bytes. + Size int + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves this container plus a temporary directory mounted at the given path. Any writes will be ephemeral to a single withExec call; they will not be persisted to subsequent withExecs. -func (r *Container) WithMountedTemp(path string) *Container { +func (r *Container) WithMountedTemp(path string, opts ...ContainerWithMountedTempOpts) *Container { q := r.query.Select("withMountedTemp") + for i := len(opts) - 1; i >= 0; i-- { + // `size` optional argument + if !querybuilder.IsZeroValue(opts[i].Size) { + q = q.Arg("size", opts[i].Size) + } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1478,6 +1597,8 @@ type ContainerWithNewFileOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool } // Retrieves this container plus a new file written at the given path. @@ -1492,6 +1613,10 @@ func (r *Container) WithNewFile(path string, contents string, opts ...ContainerW if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("contents", contents) @@ -1563,6 +1688,8 @@ type ContainerWithUnixSocketOpts struct { // // If the group is omitted, it defaults to the same as the user. Owner string + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool } // Retrieves this container plus a socket forwarded to the given Unix socket path. @@ -1574,6 +1701,10 @@ func (r *Container) WithUnixSocket(path string, source *Socket, opts ...Containe if !querybuilder.IsZeroValue(opts[i].Owner) { q = q.Arg("owner", opts[i].Owner) } + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } } q = q.Arg("path", path) q = q.Arg("source", source) @@ -1593,9 +1724,21 @@ func (r *Container) WithUser(name string) *Container { } } +// ContainerWithWorkdirOpts contains options for Container.WithWorkdir +type ContainerWithWorkdirOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves this container with a different working directory. -func (r *Container) WithWorkdir(path string) *Container { +func (r *Container) WithWorkdir(path string, opts ...ContainerWithWorkdirOpts) *Container { q := r.query.Select("withWorkdir") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1603,6 +1746,16 @@ func (r *Container) WithWorkdir(path string) *Container { } } +// Retrieves this container minus the given OCI annotation. +func (r *Container) WithoutAnnotation(name string) *Container { + q := r.query.Select("withoutAnnotation") + q = q.Arg("name", name) + + return &Container{ + query: q, + } +} + // Retrieves this container with unset default arguments for future commands. func (r *Container) WithoutDefaultArgs() *Container { q := r.query.Select("withoutDefaultArgs") @@ -1612,9 +1765,21 @@ func (r *Container) WithoutDefaultArgs() *Container { } } +// ContainerWithoutDirectoryOpts contains options for Container.WithoutDirectory +type ContainerWithoutDirectoryOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves this container with the directory at the given path removed. -func (r *Container) WithoutDirectory(path string) *Container { +func (r *Container) WithoutDirectory(path string, opts ...ContainerWithoutDirectoryOpts) *Container { q := r.query.Select("withoutDirectory") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1675,9 +1840,21 @@ func (r *Container) WithoutExposedPort(port int, opts ...ContainerWithoutExposed } } +// ContainerWithoutFileOpts contains options for Container.WithoutFile +type ContainerWithoutFileOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool +} + // Retrieves this container with the file at the given path removed. -func (r *Container) WithoutFile(path string) *Container { +func (r *Container) WithoutFile(path string, opts ...ContainerWithoutFileOpts) *Container { q := r.query.Select("withoutFile") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1685,11 +1862,22 @@ func (r *Container) WithoutFile(path string) *Container { } } -// Indicate that subsequent operations should not be featured more prominently in the UI. -// -// This is the initial state of all containers. -func (r *Container) WithoutFocus() *Container { - q := r.query.Select("withoutFocus") +// ContainerWithoutFilesOpts contains options for Container.WithoutFiles +type ContainerWithoutFilesOpts struct { + // Replace "${VAR}" or "$VAR" in the value of paths according to the current environment variables defined in the container (e.g. "/$VAR/foo.txt"). + Expand bool +} + +// Retrieves this container with the files at the given paths removed. +func (r *Container) WithoutFiles(paths []string, opts ...ContainerWithoutFilesOpts) *Container { + q := r.query.Select("withoutFiles") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } + q = q.Arg("paths", paths) return &Container{ query: q, @@ -1706,9 +1894,21 @@ func (r *Container) WithoutLabel(name string) *Container { } } +// ContainerWithoutMountOpts contains options for Container.WithoutMount +type ContainerWithoutMountOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves this container after unmounting everything at the given path. -func (r *Container) WithoutMount(path string) *Container { +func (r *Container) WithoutMount(path string, opts ...ContainerWithoutMountOpts) *Container { q := r.query.Select("withoutMount") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1736,9 +1936,21 @@ func (r *Container) WithoutSecretVariable(name string) *Container { } } +// ContainerWithoutUnixSocketOpts contains options for Container.WithoutUnixSocket +type ContainerWithoutUnixSocketOpts struct { + // Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). + Expand bool +} + // Retrieves this container with a previously added Unix socket removed. -func (r *Container) WithoutUnixSocket(path string) *Container { +func (r *Container) WithoutUnixSocket(path string, opts ...ContainerWithoutUnixSocketOpts) *Container { q := r.query.Select("withoutUnixSocket") + for i := len(opts) - 1; i >= 0; i-- { + // `expand` optional argument + if !querybuilder.IsZeroValue(opts[i].Expand) { + q = q.Arg("expand", opts[i].Expand) + } + } q = q.Arg("path", path) return &Container{ @@ -1904,390 +2116,40 @@ func (r *CurrentModule) WorkdirFile(path string) *File { } } -// A cache storage for the Dagger engine -type DaggerEngineCache struct { +// A directory. +type Directory struct { query *querybuilder.Selection - id *DaggerEngineCacheID - keepBytes *int - prune *Void + digest *string + export *string + id *DirectoryID + sync *DirectoryID } +type WithDirectoryFunc func(r *Directory) *Directory -func (r *DaggerEngineCache) WithGraphQLQuery(q *querybuilder.Selection) *DaggerEngineCache { - return &DaggerEngineCache{ - query: q, - } +// With calls the provided function with current Directory. +// +// This is useful for reusability and readability by not breaking the calling chain. +func (r *Directory) With(f WithDirectoryFunc) *Directory { + return f(r) } -// The current set of entries in the cache -func (r *DaggerEngineCache) EntrySet() *DaggerEngineCacheEntrySet { - q := r.query.Select("entrySet") - - return &DaggerEngineCacheEntrySet{ +func (r *Directory) WithGraphQLQuery(q *querybuilder.Selection) *Directory { + return &Directory{ query: q, } } -// A unique identifier for this DaggerEngineCache. -func (r *DaggerEngineCache) ID(ctx context.Context) (DaggerEngineCacheID, error) { - if r.id != nil { - return *r.id, nil - } - q := r.query.Select("id") - - var response DaggerEngineCacheID - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// XXX_GraphQLType is an internal function. It returns the native GraphQL type name -func (r *DaggerEngineCache) XXX_GraphQLType() string { - return "DaggerEngineCache" -} - -// XXX_GraphQLIDType is an internal function. It returns the native GraphQL type name for the ID of this object -func (r *DaggerEngineCache) XXX_GraphQLIDType() string { - return "DaggerEngineCacheID" -} - -// XXX_GraphQLID is an internal function. It returns the underlying type ID -func (r *DaggerEngineCache) XXX_GraphQLID(ctx context.Context) (string, error) { - id, err := r.ID(ctx) - if err != nil { - return "", err - } - return string(id), nil -} - -func (r *DaggerEngineCache) MarshalJSON() ([]byte, error) { - id, err := r.ID(marshalCtx) - if err != nil { - return nil, err - } - return json.Marshal(id) -} -func (r *DaggerEngineCache) UnmarshalJSON(bs []byte) error { - var id string - err := json.Unmarshal(bs, &id) - if err != nil { - return err - } - *r = *dag.LoadDaggerEngineCacheFromID(DaggerEngineCacheID(id)) - return nil -} - -// The maximum bytes to keep in the cache without pruning, after which automatic pruning may kick in. -func (r *DaggerEngineCache) KeepBytes(ctx context.Context) (int, error) { - if r.keepBytes != nil { - return *r.keepBytes, nil - } - q := r.query.Select("keepBytes") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// Prune the cache of releaseable entries -func (r *DaggerEngineCache) Prune(ctx context.Context) error { - if r.prune != nil { - return nil - } - q := r.query.Select("prune") - - return q.Execute(ctx) -} - -// An individual cache entry in a cache entry set -type DaggerEngineCacheEntry struct { - query *querybuilder.Selection - - activelyUsed *bool - createdTimeUnixNano *int - description *string - diskSpaceBytes *int - id *DaggerEngineCacheEntryID - mostRecentUseTimeUnixNano *int -} - -func (r *DaggerEngineCacheEntry) WithGraphQLQuery(q *querybuilder.Selection) *DaggerEngineCacheEntry { - return &DaggerEngineCacheEntry{ - query: q, - } -} - -// Whether the cache entry is actively being used. -func (r *DaggerEngineCacheEntry) ActivelyUsed(ctx context.Context) (bool, error) { - if r.activelyUsed != nil { - return *r.activelyUsed, nil - } - q := r.query.Select("activelyUsed") - - var response bool - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// The time the cache entry was created, in Unix nanoseconds. -func (r *DaggerEngineCacheEntry) CreatedTimeUnixNano(ctx context.Context) (int, error) { - if r.createdTimeUnixNano != nil { - return *r.createdTimeUnixNano, nil - } - q := r.query.Select("createdTimeUnixNano") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// The description of the cache entry. -func (r *DaggerEngineCacheEntry) Description(ctx context.Context) (string, error) { - if r.description != nil { - return *r.description, nil - } - q := r.query.Select("description") - - var response string - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// The disk space used by the cache entry. -func (r *DaggerEngineCacheEntry) DiskSpaceBytes(ctx context.Context) (int, error) { - if r.diskSpaceBytes != nil { - return *r.diskSpaceBytes, nil - } - q := r.query.Select("diskSpaceBytes") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// A unique identifier for this DaggerEngineCacheEntry. -func (r *DaggerEngineCacheEntry) ID(ctx context.Context) (DaggerEngineCacheEntryID, error) { - if r.id != nil { - return *r.id, nil - } - q := r.query.Select("id") - - var response DaggerEngineCacheEntryID - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// XXX_GraphQLType is an internal function. It returns the native GraphQL type name -func (r *DaggerEngineCacheEntry) XXX_GraphQLType() string { - return "DaggerEngineCacheEntry" -} - -// XXX_GraphQLIDType is an internal function. It returns the native GraphQL type name for the ID of this object -func (r *DaggerEngineCacheEntry) XXX_GraphQLIDType() string { - return "DaggerEngineCacheEntryID" -} - -// XXX_GraphQLID is an internal function. It returns the underlying type ID -func (r *DaggerEngineCacheEntry) XXX_GraphQLID(ctx context.Context) (string, error) { - id, err := r.ID(ctx) - if err != nil { - return "", err - } - return string(id), nil -} - -func (r *DaggerEngineCacheEntry) MarshalJSON() ([]byte, error) { - id, err := r.ID(marshalCtx) - if err != nil { - return nil, err - } - return json.Marshal(id) -} -func (r *DaggerEngineCacheEntry) UnmarshalJSON(bs []byte) error { - var id string - err := json.Unmarshal(bs, &id) - if err != nil { - return err - } - *r = *dag.LoadDaggerEngineCacheEntryFromID(DaggerEngineCacheEntryID(id)) - return nil -} - -// The most recent time the cache entry was used, in Unix nanoseconds. -func (r *DaggerEngineCacheEntry) MostRecentUseTimeUnixNano(ctx context.Context) (int, error) { - if r.mostRecentUseTimeUnixNano != nil { - return *r.mostRecentUseTimeUnixNano, nil - } - q := r.query.Select("mostRecentUseTimeUnixNano") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// A set of cache entries returned by a query to a cache -type DaggerEngineCacheEntrySet struct { - query *querybuilder.Selection - - diskSpaceBytes *int - entryCount *int - id *DaggerEngineCacheEntrySetID -} - -func (r *DaggerEngineCacheEntrySet) WithGraphQLQuery(q *querybuilder.Selection) *DaggerEngineCacheEntrySet { - return &DaggerEngineCacheEntrySet{ - query: q, - } -} - -// The total disk space used by the cache entries in this set. -func (r *DaggerEngineCacheEntrySet) DiskSpaceBytes(ctx context.Context) (int, error) { - if r.diskSpaceBytes != nil { - return *r.diskSpaceBytes, nil - } - q := r.query.Select("diskSpaceBytes") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// The list of individual cache entries in the set -func (r *DaggerEngineCacheEntrySet) Entries(ctx context.Context) ([]DaggerEngineCacheEntry, error) { - q := r.query.Select("entries") - - q = q.Select("id") - - type entries struct { - Id DaggerEngineCacheEntryID - } - - convert := func(fields []entries) []DaggerEngineCacheEntry { - out := []DaggerEngineCacheEntry{} - - for i := range fields { - val := DaggerEngineCacheEntry{id: &fields[i].Id} - val.query = q.Root().Select("loadDaggerEngineCacheEntryFromID").Arg("id", fields[i].Id) - out = append(out, val) - } - - return out - } - var response []entries - - q = q.Bind(&response) - - err := q.Execute(ctx) - if err != nil { - return nil, err - } - - return convert(response), nil -} - -// The number of cache entries in this set. -func (r *DaggerEngineCacheEntrySet) EntryCount(ctx context.Context) (int, error) { - if r.entryCount != nil { - return *r.entryCount, nil - } - q := r.query.Select("entryCount") - - var response int - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// A unique identifier for this DaggerEngineCacheEntrySet. -func (r *DaggerEngineCacheEntrySet) ID(ctx context.Context) (DaggerEngineCacheEntrySetID, error) { - if r.id != nil { - return *r.id, nil - } - q := r.query.Select("id") - - var response DaggerEngineCacheEntrySetID - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - -// XXX_GraphQLType is an internal function. It returns the native GraphQL type name -func (r *DaggerEngineCacheEntrySet) XXX_GraphQLType() string { - return "DaggerEngineCacheEntrySet" -} - -// XXX_GraphQLIDType is an internal function. It returns the native GraphQL type name for the ID of this object -func (r *DaggerEngineCacheEntrySet) XXX_GraphQLIDType() string { - return "DaggerEngineCacheEntrySetID" -} - -// XXX_GraphQLID is an internal function. It returns the underlying type ID -func (r *DaggerEngineCacheEntrySet) XXX_GraphQLID(ctx context.Context) (string, error) { - id, err := r.ID(ctx) - if err != nil { - return "", err - } - return string(id), nil -} - -func (r *DaggerEngineCacheEntrySet) MarshalJSON() ([]byte, error) { - id, err := r.ID(marshalCtx) - if err != nil { - return nil, err - } - return json.Marshal(id) -} -func (r *DaggerEngineCacheEntrySet) UnmarshalJSON(bs []byte) error { - var id string - err := json.Unmarshal(bs, &id) - if err != nil { - return err - } - *r = *dag.LoadDaggerEngineCacheEntrySetFromID(DaggerEngineCacheEntrySetID(id)) - return nil -} - -// A directory. -type Directory struct { - query *querybuilder.Selection - - export *string - id *DirectoryID - sync *DirectoryID -} -type WithDirectoryFunc func(r *Directory) *Directory - -// With calls the provided function with current Directory. -// -// This is useful for reusability and readability by not breaking the calling chain. -func (r *Directory) With(f WithDirectoryFunc) *Directory { - return f(r) -} - -func (r *Directory) WithGraphQLQuery(q *querybuilder.Selection) *Directory { - return &Directory{ - query: q, - } -} - -// DirectoryAsModuleOpts contains options for Directory.AsModule -type DirectoryAsModuleOpts struct { - // An optional subpath of the directory which contains the module's configuration file. - // - // This is needed when the module code is in a subdirectory but requires parent directories to be loaded in order to execute. For example, the module source code may need a go.mod, project.toml, package.json, etc. file from a parent directory. - // - // If not set, the module source code is loaded from the root of the directory. - SourceRootPath string - // The engine version to upgrade to. - EngineVersion string +// DirectoryAsModuleOpts contains options for Directory.AsModule +type DirectoryAsModuleOpts struct { + // An optional subpath of the directory which contains the module's configuration file. + // + // This is needed when the module code is in a subdirectory but requires parent directories to be loaded in order to execute. For example, the module source code may need a go.mod, project.toml, package.json, etc. file from a parent directory. + // + // If not set, the module source code is loaded from the root of the directory. + SourceRootPath string + // The engine version to upgrade to. + EngineVersion string } // Load the directory as a Dagger module @@ -2320,6 +2182,19 @@ func (r *Directory) Diff(other *Directory) *Directory { } } +// Return the directory's digest. The format of the digest is not guaranteed to be stable between releases of Dagger. It is guaranteed to be stable between invocations of the same Dagger engine. +func (r *Directory) Digest(ctx context.Context) (string, error) { + if r.digest != nil { + return *r.digest, nil + } + q := r.query.Select("digest") + + var response string + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + // Retrieves a directory at the given path. func (r *Directory) Directory(path string) *Directory { q := r.query.Select("directory") @@ -2495,36 +2370,6 @@ func (r *Directory) UnmarshalJSON(bs []byte) error { return nil } -// DirectoryPipelineOpts contains options for Directory.Pipeline -type DirectoryPipelineOpts struct { - // Description of the sub-pipeline. - Description string - // Labels to apply to the sub-pipeline. - Labels []PipelineLabel -} - -// Creates a named sub-pipeline. -// -// Deprecated: Explicit pipeline creation is now a no-op -func (r *Directory) Pipeline(name string, opts ...DirectoryPipelineOpts) *Directory { - q := r.query.Select("pipeline") - for i := len(opts) - 1; i >= 0; i-- { - // `description` optional argument - if !querybuilder.IsZeroValue(opts[i].Description) { - q = q.Arg("description", opts[i].Description) - } - // `labels` optional argument - if !querybuilder.IsZeroValue(opts[i].Labels) { - q = q.Arg("labels", opts[i].Labels) - } - } - q = q.Arg("name", name) - - return &Directory{ - query: q, - } -} - // Force evaluation in the engine. func (r *Directory) Sync(ctx context.Context) (*Directory, error) { q := r.query.Select("sync") @@ -2731,6 +2576,16 @@ func (r *Directory) WithoutFile(path string) *Directory { } } +// Retrieves this directory with the files at the given paths removed. +func (r *Directory) WithoutFiles(paths []string) *Directory { + q := r.query.Select("withoutFiles") + q = q.Arg("paths", paths) + + return &Directory{ + query: q, + } +} + // A definition of a custom enum defined in a Module. type EnumTypeDef struct { query *querybuilder.Selection @@ -2822,6 +2677,15 @@ func (r *EnumTypeDef) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this enum declaration. +func (r *EnumTypeDef) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // If this EnumTypeDef is associated with a Module, the name of the module. Unset otherwise. func (r *EnumTypeDef) SourceModuleName(ctx context.Context) (string, error) { if r.sourceModuleName != nil { @@ -2958,6 +2822,15 @@ func (r *EnumValueTypeDef) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this enum value declaration. +func (r *EnumValueTypeDef) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // An environment variable name and value. type EnvVariable struct { query *querybuilder.Selection @@ -3140,6 +3013,15 @@ func (r *FieldTypeDef) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this field declaration. +func (r *FieldTypeDef) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // The type of the field. func (r *FieldTypeDef) TypeDef() *TypeDef { q := r.query.Select("typeDef") @@ -3490,6 +3372,15 @@ func (r *Function) ReturnType() *TypeDef { } } +// The location of this function declaration. +func (r *Function) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // FunctionWithArgOpts contains options for Function.WithArg type FunctionWithArgOpts struct { // A doc string for the argument, if any @@ -3500,6 +3391,8 @@ type FunctionWithArgOpts struct { DefaultPath string // Patterns to ignore when loading the contextual argument value. Ignore []string + + SourceMap *SourceMap } // Returns the function with the provided argument @@ -3523,6 +3416,10 @@ func (r *Function) WithArg(name string, typeDef *TypeDef, opts ...FunctionWithAr if !querybuilder.IsZeroValue(opts[i].Ignore) { q = q.Arg("ignore", opts[i].Ignore) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("name", name) q = q.Arg("typeDef", typeDef) @@ -3542,6 +3439,17 @@ func (r *Function) WithDescription(description string) *Function { } } +// Returns the function with the given source map. +func (r *Function) WithSourceMap(sourceMap *SourceMap) *Function { + assertNotNil("sourceMap", sourceMap) + q := r.query.Select("withSourceMap") + q = q.Arg("sourceMap", sourceMap) + + return &Function{ + query: q, + } +} + // An argument accepted by a function. // // This is a specification for an argument at function definition time, not an argument passed at function call time. @@ -3672,6 +3580,15 @@ func (r *FunctionArg) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this arg declaration. +func (r *FunctionArg) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // The type of the argument. func (r *FunctionArg) TypeDef() *TypeDef { q := r.query.Select("typeDef") @@ -4044,7 +3961,6 @@ type GitModuleSource struct { query *querybuilder.Selection cloneRef *string - cloneURL *string commit *string htmlRepoURL *string htmlURL *string @@ -4073,21 +3989,6 @@ func (r *GitModuleSource) CloneRef(ctx context.Context) (string, error) { return response, q.Execute(ctx) } -// The URL to clone the root of the git repo from -// -// Deprecated: Use CloneRef instead. CloneRef supports both URL-style and SCP-like SSH references -func (r *GitModuleSource) CloneURL(ctx context.Context) (string, error) { - if r.cloneURL != nil { - return *r.cloneURL, nil - } - q := r.query.Select("cloneURL") - - var response string - - q = q.Bind(&response) - return response, q.Execute(ctx) -} - // The resolved commit of the git repo this source points to. func (r *GitModuleSource) Commit(ctx context.Context) (string, error) { if r.commit != nil { @@ -4300,9 +4201,21 @@ func (r *GitRef) UnmarshalJSON(bs []byte) error { return nil } +// GitRefTreeOpts contains options for GitRef.Tree +type GitRefTreeOpts struct { + // Set to true to discard .git directory. + DiscardGitDir bool +} + // The filesystem tree at this ref. -func (r *GitRef) Tree() *Directory { +func (r *GitRef) Tree(opts ...GitRefTreeOpts) *Directory { q := r.query.Select("tree") + for i := len(opts) - 1; i >= 0; i-- { + // `discardGitDir` optional argument + if !querybuilder.IsZeroValue(opts[i].DiscardGitDir) { + q = q.Arg("discardGitDir", opts[i].DiscardGitDir) + } + } return &Directory{ query: q, @@ -4708,6 +4621,15 @@ func (r *InterfaceTypeDef) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this interface declaration. +func (r *InterfaceTypeDef) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // If this InterfaceTypeDef is associated with a Module, the name of the module. Unset otherwise. func (r *InterfaceTypeDef) SourceModuleName(ctx context.Context) (string, error) { if r.sourceModuleName != nil { @@ -5604,6 +5526,7 @@ type ModuleSource struct { asString *string configExists *bool + digest *string id *ModuleSourceID kind *ModuleSourceKind moduleName *string @@ -5734,6 +5657,19 @@ func (r *ModuleSource) Dependencies(ctx context.Context) ([]ModuleDependency, er return convert(response), nil } +// Return the module source's content digest. The format of the digest is not guaranteed to be stable between releases of Dagger. It is guaranteed to be stable between invocations of the same Dagger engine. +func (r *ModuleSource) Digest(ctx context.Context) (string, error) { + if r.digest != nil { + return *r.digest, nil + } + q := r.query.Select("digest") + + var response string + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + // The directory containing the module configuration and source code (source code may be in a subdir). func (r *ModuleSource) Directory(path string) *Directory { q := r.query.Select("directory") @@ -5860,6 +5796,8 @@ func (r *ModuleSource) ResolveDependency(dep *ModuleSource) *ModuleSource { type ModuleSourceResolveDirectoryFromCallerOpts struct { // If set, the name of the view to apply to the path. ViewName string + // Patterns to ignore when loading the directory. + Ignore []string } // Load a directory from the caller optionally with a given view applied. @@ -5870,6 +5808,10 @@ func (r *ModuleSource) ResolveDirectoryFromCaller(path string, opts ...ModuleSou if !querybuilder.IsZeroValue(opts[i].ViewName) { q = q.Arg("viewName", opts[i].ViewName) } + // `ignore` optional argument + if !querybuilder.IsZeroValue(opts[i].Ignore) { + q = q.Arg("ignore", opts[i].Ignore) + } } q = q.Arg("path", path) @@ -6291,6 +6233,15 @@ func (r *ObjectTypeDef) Name(ctx context.Context) (string, error) { return response, q.Execute(ctx) } +// The location of this object declaration. +func (r *ObjectTypeDef) SourceMap() *SourceMap { + q := r.query.Select("sourceMap") + + return &SourceMap{ + query: q, + } +} + // If this ObjectTypeDef is associated with a Module, the name of the module. Unset otherwise. func (r *ObjectTypeDef) SourceModuleName(ctx context.Context) (string, error) { if r.sourceModuleName != nil { @@ -6422,15 +6373,6 @@ func (r *Port) Protocol(ctx context.Context) (NetworkProtocol, error) { return response, q.Execute(ctx) } -type WithClientFunc func(r *Client) *Client - -// With calls the provided function with current Client. -// -// This is useful for reusability and readability by not breaking the calling chain. -func (r *Client) With(f WithClientFunc) *Client { - return f(r) -} - func (r *Client) WithGraphQLQuery(q *querybuilder.Selection) *Client { return &Client{ query: q, @@ -6591,7 +6533,7 @@ func (r *Client) GeneratedCode(code *Directory) *GeneratedCode { // GitOpts contains options for Client.Git type GitOpts struct { - // Set to true to keep .git directory. + // DEPRECATED: Set to true to keep .git directory. KeepGitDir bool // A service which must be started before the repo is fetched. ExperimentalServiceHost *Service @@ -6701,36 +6643,6 @@ func (r *Client) LoadCurrentModuleFromID(id CurrentModuleID) *CurrentModule { } } -// Load a DaggerEngineCacheEntry from its ID. -func (r *Client) LoadDaggerEngineCacheEntryFromID(id DaggerEngineCacheEntryID) *DaggerEngineCacheEntry { - q := r.query.Select("loadDaggerEngineCacheEntryFromID") - q = q.Arg("id", id) - - return &DaggerEngineCacheEntry{ - query: q, - } -} - -// Load a DaggerEngineCacheEntrySet from its ID. -func (r *Client) LoadDaggerEngineCacheEntrySetFromID(id DaggerEngineCacheEntrySetID) *DaggerEngineCacheEntrySet { - q := r.query.Select("loadDaggerEngineCacheEntrySetFromID") - q = q.Arg("id", id) - - return &DaggerEngineCacheEntrySet{ - query: q, - } -} - -// Load a DaggerEngineCache from its ID. -func (r *Client) LoadDaggerEngineCacheFromID(id DaggerEngineCacheID) *DaggerEngineCache { - q := r.query.Select("loadDaggerEngineCacheFromID") - q = q.Arg("id", id) - - return &DaggerEngineCache{ - query: q, - } -} - // Load a Directory from its ID. func (r *Client) LoadDirectoryFromID(id DirectoryID) *Directory { q := r.query.Select("loadDirectoryFromID") @@ -7031,6 +6943,16 @@ func (r *Client) LoadSocketFromID(id SocketID) *Socket { } } +// Load a SourceMap from its ID. +func (r *Client) LoadSourceMapFromID(id SourceMapID) *SourceMap { + q := r.query.Select("loadSourceMapFromID") + q = q.Arg("id", id) + + return &SourceMap{ + query: q, + } +} + // Load a Terminal from its ID. func (r *Client) LoadTerminalFromID(id TerminalID) *Terminal { q := r.query.Select("loadTerminalFromID") @@ -7085,6 +7007,8 @@ func (r *Client) ModuleDependency(source *ModuleSource, opts ...ModuleDependency // ModuleSourceOpts contains options for Client.ModuleSource type ModuleSourceOpts struct { + // The pinned version of the module source + RefPin string // If true, enforce that the source is a stable version for source kinds that support versioning. Stable bool // The relative path to the module root from the host directory @@ -7095,6 +7019,10 @@ type ModuleSourceOpts struct { func (r *Client) ModuleSource(refString string, opts ...ModuleSourceOpts) *ModuleSource { q := r.query.Select("moduleSource") for i := len(opts) - 1; i >= 0; i-- { + // `refPin` optional argument + if !querybuilder.IsZeroValue(opts[i].RefPin) { + q = q.Arg("refPin", opts[i].RefPin) + } // `stable` optional argument if !querybuilder.IsZeroValue(opts[i].Stable) { q = q.Arg("stable", opts[i].Stable) @@ -7111,37 +7039,6 @@ func (r *Client) ModuleSource(refString string, opts ...ModuleSourceOpts) *Modul } } -// PipelineOpts contains options for Client.Pipeline -type PipelineOpts struct { - // Description of the sub-pipeline. - Description string - // Labels to apply to the sub-pipeline. - Labels []PipelineLabel -} - -// Creates a named sub-pipeline. -// -// Deprecated: Explicit pipeline creation is now a no-op -func (r *Client) Pipeline(name string, opts ...PipelineOpts) *Client { - q := r.query.Select("pipeline") - for i := len(opts) - 1; i >= 0; i-- { - // `description` optional argument - if !querybuilder.IsZeroValue(opts[i].Description) { - q = q.Arg("description", opts[i].Description) - } - // `labels` optional argument - if !querybuilder.IsZeroValue(opts[i].Labels) { - q = q.Arg("labels", opts[i].Labels) - } - } - q = q.Arg("name", name) - - return &Client{ - query: q, - client: r.client, - } -} - // SecretOpts contains options for Client.Secret type SecretOpts struct { Accessor string @@ -7176,6 +7073,18 @@ func (r *Client) SetSecret(name string, plaintext string) *Secret { } } +// Creates source map metadata. +func (r *Client) SourceMap(filename string, line int, column int) *SourceMap { + q := r.query.Select("sourceMap") + q = q.Arg("filename", filename) + q = q.Arg("line", line) + q = q.Arg("column", column) + + return &SourceMap{ + query: q, + } +} + // Create a new TypeDef. func (r *Client) TypeDef() *TypeDef { q := r.query.Select("typeDef") @@ -7400,6 +7309,14 @@ type Service struct { stop *ServiceID up *Void } +type WithServiceFunc func(r *Service) *Service + +// With calls the provided function with current Service. +// +// This is useful for reusability and readability by not breaking the calling chain. +func (r *Service) With(f WithServiceFunc) *Service { + return f(r) +} func (r *Service) WithGraphQLQuery(q *querybuilder.Selection) *Service { return &Service{ @@ -7607,6 +7524,16 @@ func (r *Service) Up(ctx context.Context, opts ...ServiceUpOpts) error { return q.Execute(ctx) } +// Configures a hostname which can be used by clients within the session to reach this container. +func (r *Service) WithHostname(hostname string) *Service { + q := r.query.Select("withHostname") + q = q.Arg("hostname", hostname) + + return &Service{ + query: q, + } +} + // A Unix or TCP/IP socket that can be mounted into a container. type Socket struct { query *querybuilder.Selection @@ -7669,6 +7596,124 @@ func (r *Socket) UnmarshalJSON(bs []byte) error { return nil } +// Source location information. +type SourceMap struct { + query *querybuilder.Selection + + column *int + filename *string + id *SourceMapID + line *int + module *string +} + +func (r *SourceMap) WithGraphQLQuery(q *querybuilder.Selection) *SourceMap { + return &SourceMap{ + query: q, + } +} + +// The column number within the line. +func (r *SourceMap) Column(ctx context.Context) (int, error) { + if r.column != nil { + return *r.column, nil + } + q := r.query.Select("column") + + var response int + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + +// The filename from the module source. +func (r *SourceMap) Filename(ctx context.Context) (string, error) { + if r.filename != nil { + return *r.filename, nil + } + q := r.query.Select("filename") + + var response string + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + +// A unique identifier for this SourceMap. +func (r *SourceMap) ID(ctx context.Context) (SourceMapID, error) { + if r.id != nil { + return *r.id, nil + } + q := r.query.Select("id") + + var response SourceMapID + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + +// XXX_GraphQLType is an internal function. It returns the native GraphQL type name +func (r *SourceMap) XXX_GraphQLType() string { + return "SourceMap" +} + +// XXX_GraphQLIDType is an internal function. It returns the native GraphQL type name for the ID of this object +func (r *SourceMap) XXX_GraphQLIDType() string { + return "SourceMapID" +} + +// XXX_GraphQLID is an internal function. It returns the underlying type ID +func (r *SourceMap) XXX_GraphQLID(ctx context.Context) (string, error) { + id, err := r.ID(ctx) + if err != nil { + return "", err + } + return string(id), nil +} + +func (r *SourceMap) MarshalJSON() ([]byte, error) { + id, err := r.ID(marshalCtx) + if err != nil { + return nil, err + } + return json.Marshal(id) +} +func (r *SourceMap) UnmarshalJSON(bs []byte) error { + var id string + err := json.Unmarshal(bs, &id) + if err != nil { + return err + } + *r = *dag.LoadSourceMapFromID(SourceMapID(id)) + return nil +} + +// The line number within the filename. +func (r *SourceMap) Line(ctx context.Context) (int, error) { + if r.line != nil { + return *r.line, nil + } + q := r.query.Select("line") + + var response int + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + +// The module dependency this was declared in. +func (r *SourceMap) Module(ctx context.Context) (string, error) { + if r.module != nil { + return *r.module, nil + } + q := r.query.Select("module") + + var response string + + q = q.Bind(&response) + return response, q.Execute(ctx) +} + // An interactive terminal that clients can connect to. type Terminal struct { query *querybuilder.Selection @@ -7914,6 +7959,8 @@ func (r *TypeDef) WithConstructor(function *Function) *TypeDef { type TypeDefWithEnumOpts struct { // A doc string for the enum, if any Description string + // The source map for the enum definition. + SourceMap *SourceMap } // Returns a TypeDef of kind Enum with the provided name. @@ -7926,6 +7973,10 @@ func (r *TypeDef) WithEnum(name string, opts ...TypeDefWithEnumOpts) *TypeDef { if !querybuilder.IsZeroValue(opts[i].Description) { q = q.Arg("description", opts[i].Description) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("name", name) @@ -7938,6 +7989,8 @@ func (r *TypeDef) WithEnum(name string, opts ...TypeDefWithEnumOpts) *TypeDef { type TypeDefWithEnumValueOpts struct { // A doc string for the value, if any Description string + // The source map for the enum value definition. + SourceMap *SourceMap } // Adds a static value for an Enum TypeDef, failing if the type is not an enum. @@ -7948,6 +8001,10 @@ func (r *TypeDef) WithEnumValue(value string, opts ...TypeDefWithEnumValueOpts) if !querybuilder.IsZeroValue(opts[i].Description) { q = q.Arg("description", opts[i].Description) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("value", value) @@ -7960,6 +8017,8 @@ func (r *TypeDef) WithEnumValue(value string, opts ...TypeDefWithEnumValueOpts) type TypeDefWithFieldOpts struct { // A doc string for the field, if any Description string + // The source map for the field definition. + SourceMap *SourceMap } // Adds a static field for an Object TypeDef, failing if the type is not an object. @@ -7971,6 +8030,10 @@ func (r *TypeDef) WithField(name string, typeDef *TypeDef, opts ...TypeDefWithFi if !querybuilder.IsZeroValue(opts[i].Description) { q = q.Arg("description", opts[i].Description) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("name", name) q = q.Arg("typeDef", typeDef) @@ -7994,6 +8057,8 @@ func (r *TypeDef) WithFunction(function *Function) *TypeDef { // TypeDefWithInterfaceOpts contains options for TypeDef.WithInterface type TypeDefWithInterfaceOpts struct { Description string + + SourceMap *SourceMap } // Returns a TypeDef of kind Interface with the provided name. @@ -8004,6 +8069,10 @@ func (r *TypeDef) WithInterface(name string, opts ...TypeDefWithInterfaceOpts) * if !querybuilder.IsZeroValue(opts[i].Description) { q = q.Arg("description", opts[i].Description) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("name", name) @@ -8036,6 +8105,8 @@ func (r *TypeDef) WithListOf(elementType *TypeDef) *TypeDef { // TypeDefWithObjectOpts contains options for TypeDef.WithObject type TypeDefWithObjectOpts struct { Description string + + SourceMap *SourceMap } // Returns a TypeDef of kind Object with the provided name. @@ -8048,6 +8119,10 @@ func (r *TypeDef) WithObject(name string, opts ...TypeDefWithObjectOpts) *TypeDe if !querybuilder.IsZeroValue(opts[i].Description) { q = q.Arg("description", opts[i].Description) } + // `sourceMap` optional argument + if !querybuilder.IsZeroValue(opts[i].SourceMap) { + q = q.Arg("sourceMap", opts[i].SourceMap) + } } q = q.Arg("name", name) @@ -8087,109 +8162,235 @@ func (r *TypeDef) WithScalar(name string, opts ...TypeDefWithScalarOpts) *TypeDe } } +// Sharing mode of the cache volume. type CacheSharingMode string func (CacheSharingMode) IsEnum() {} const ( // Shares the cache volume amongst many build pipelines, but will serialize the writes - Locked CacheSharingMode = "LOCKED" + CacheSharingModeLocked CacheSharingMode = "LOCKED" + + // Shares the cache volume amongst many build pipelines, but will serialize the writes + // Deprecated: use CacheSharingModeLocked instead + Locked CacheSharingMode = CacheSharingModeLocked + + // Keeps a cache volume for a single build pipeline + CacheSharingModePrivate CacheSharingMode = "PRIVATE" // Keeps a cache volume for a single build pipeline - Private CacheSharingMode = "PRIVATE" + // Deprecated: use CacheSharingModePrivate instead + Private CacheSharingMode = CacheSharingModePrivate // Shares the cache volume amongst many build pipelines - Shared CacheSharingMode = "SHARED" + CacheSharingModeShared CacheSharingMode = "SHARED" + + // Shares the cache volume amongst many build pipelines + // Deprecated: use CacheSharingModeShared instead + Shared CacheSharingMode = CacheSharingModeShared ) +// Compression algorithm to use for image layers. type ImageLayerCompression string func (ImageLayerCompression) IsEnum() {} const ( - Estargz ImageLayerCompression = "EStarGZ" + ImageLayerCompressionEstarGz ImageLayerCompression = "EStarGZ" + + // Deprecated: use ImageLayerCompressionEstarGz instead + Estargz ImageLayerCompression = ImageLayerCompressionEstarGz + + ImageLayerCompressionGzip ImageLayerCompression = "Gzip" - Gzip ImageLayerCompression = "Gzip" + // Deprecated: use ImageLayerCompressionGzip instead + Gzip ImageLayerCompression = ImageLayerCompressionGzip - Uncompressed ImageLayerCompression = "Uncompressed" + ImageLayerCompressionUncompressed ImageLayerCompression = "Uncompressed" - Zstd ImageLayerCompression = "Zstd" + // Deprecated: use ImageLayerCompressionUncompressed instead + Uncompressed ImageLayerCompression = ImageLayerCompressionUncompressed + + ImageLayerCompressionZstd ImageLayerCompression = "Zstd" + + // Deprecated: use ImageLayerCompressionZstd instead + Zstd ImageLayerCompression = ImageLayerCompressionZstd ) +// Mediatypes to use in published or exported image metadata. type ImageMediaTypes string func (ImageMediaTypes) IsEnum() {} const ( - Dockermediatypes ImageMediaTypes = "DockerMediaTypes" + ImageMediaTypesDockerMediaTypes ImageMediaTypes = "DockerMediaTypes" + + // Deprecated: use ImageMediaTypesDockerMediaTypes instead + Dockermediatypes ImageMediaTypes = ImageMediaTypesDockerMediaTypes + + ImageMediaTypesOcimediaTypes ImageMediaTypes = "OCIMediaTypes" - Ocimediatypes ImageMediaTypes = "OCIMediaTypes" + // Deprecated: use ImageMediaTypesOcimediaTypes instead + Ocimediatypes ImageMediaTypes = ImageMediaTypesOcimediaTypes ) +// The kind of module source. type ModuleSourceKind string func (ModuleSourceKind) IsEnum() {} const ( - GitSource ModuleSourceKind = "GIT_SOURCE" + ModuleSourceKindGitSource ModuleSourceKind = "GIT_SOURCE" - LocalSource ModuleSourceKind = "LOCAL_SOURCE" + // Deprecated: use ModuleSourceKindGitSource instead + GitSource ModuleSourceKind = ModuleSourceKindGitSource + + ModuleSourceKindLocalSource ModuleSourceKind = "LOCAL_SOURCE" + + // Deprecated: use ModuleSourceKindLocalSource instead + LocalSource ModuleSourceKind = ModuleSourceKindLocalSource ) +// Transport layer network protocol associated to a port. type NetworkProtocol string func (NetworkProtocol) IsEnum() {} const ( - Tcp NetworkProtocol = "TCP" + NetworkProtocolTcp NetworkProtocol = "TCP" + + // Deprecated: use NetworkProtocolTcp instead + Tcp NetworkProtocol = NetworkProtocolTcp + + NetworkProtocolUdp NetworkProtocol = "UDP" + + // Deprecated: use NetworkProtocolUdp instead + Udp NetworkProtocol = NetworkProtocolUdp +) + +// Expected return type of an execution +type ReturnType string + +func (ReturnType) IsEnum() {} + +const ( + // Any execution (exit codes 0-127) + ReturnTypeAny ReturnType = "ANY" + + // Any execution (exit codes 0-127) + // Deprecated: use ReturnTypeAny instead + Any ReturnType = ReturnTypeAny + + // A failed execution (exit codes 1-127) + ReturnTypeFailure ReturnType = "FAILURE" - Udp NetworkProtocol = "UDP" + // A failed execution (exit codes 1-127) + // Deprecated: use ReturnTypeFailure instead + Failure ReturnType = ReturnTypeFailure + + // A successful execution (exit code 0) + ReturnTypeSuccess ReturnType = "SUCCESS" + + // A successful execution (exit code 0) + // Deprecated: use ReturnTypeSuccess instead + Success ReturnType = ReturnTypeSuccess ) +// Distinguishes the different kinds of TypeDefs. type TypeDefKind string func (TypeDefKind) IsEnum() {} const ( // A boolean value. - BooleanKind TypeDefKind = "BOOLEAN_KIND" + TypeDefKindBooleanKind TypeDefKind = "BOOLEAN_KIND" + + // A boolean value. + // Deprecated: use TypeDefKindBooleanKind instead + BooleanKind TypeDefKind = TypeDefKindBooleanKind + + // A GraphQL enum type and its values + // + // Always paired with an EnumTypeDef. + TypeDefKindEnumKind TypeDefKind = "ENUM_KIND" // A GraphQL enum type and its values // // Always paired with an EnumTypeDef. - EnumKind TypeDefKind = "ENUM_KIND" + // Deprecated: use TypeDefKindEnumKind instead + EnumKind TypeDefKind = TypeDefKindEnumKind // A graphql input type, used only when representing the core API via TypeDefs. - InputKind TypeDefKind = "INPUT_KIND" + TypeDefKindInputKind TypeDefKind = "INPUT_KIND" + + // A graphql input type, used only when representing the core API via TypeDefs. + // Deprecated: use TypeDefKindInputKind instead + InputKind TypeDefKind = TypeDefKindInputKind + + // An integer value. + TypeDefKindIntegerKind TypeDefKind = "INTEGER_KIND" // An integer value. - IntegerKind TypeDefKind = "INTEGER_KIND" + // Deprecated: use TypeDefKindIntegerKind instead + IntegerKind TypeDefKind = TypeDefKindIntegerKind + + // A named type of functions that can be matched+implemented by other objects+interfaces. + // + // Always paired with an InterfaceTypeDef. + TypeDefKindInterfaceKind TypeDefKind = "INTERFACE_KIND" // A named type of functions that can be matched+implemented by other objects+interfaces. // // Always paired with an InterfaceTypeDef. - InterfaceKind TypeDefKind = "INTERFACE_KIND" + // Deprecated: use TypeDefKindInterfaceKind instead + InterfaceKind TypeDefKind = TypeDefKindInterfaceKind // A list of values all having the same type. // // Always paired with a ListTypeDef. - ListKind TypeDefKind = "LIST_KIND" + TypeDefKindListKind TypeDefKind = "LIST_KIND" + + // A list of values all having the same type. + // + // Always paired with a ListTypeDef. + // Deprecated: use TypeDefKindListKind instead + ListKind TypeDefKind = TypeDefKindListKind + + // A named type defined in the GraphQL schema, with fields and functions. + // + // Always paired with an ObjectTypeDef. + TypeDefKindObjectKind TypeDefKind = "OBJECT_KIND" // A named type defined in the GraphQL schema, with fields and functions. // // Always paired with an ObjectTypeDef. - ObjectKind TypeDefKind = "OBJECT_KIND" + // Deprecated: use TypeDefKindObjectKind instead + ObjectKind TypeDefKind = TypeDefKindObjectKind // A scalar value of any basic kind. - ScalarKind TypeDefKind = "SCALAR_KIND" + TypeDefKindScalarKind TypeDefKind = "SCALAR_KIND" + + // A scalar value of any basic kind. + // Deprecated: use TypeDefKindScalarKind instead + ScalarKind TypeDefKind = TypeDefKindScalarKind + + // A string value. + TypeDefKindStringKind TypeDefKind = "STRING_KIND" // A string value. - StringKind TypeDefKind = "STRING_KIND" + // Deprecated: use TypeDefKindStringKind instead + StringKind TypeDefKind = TypeDefKindStringKind + + // A special kind used to signify that no value is returned. + // + // This is used for functions that have no return value. The outer TypeDef specifying this Kind is always Optional, as the Void is never actually represented. + TypeDefKindVoidKind TypeDefKind = "VOID_KIND" // A special kind used to signify that no value is returned. // // This is used for functions that have no return value. The outer TypeDef specifying this Kind is always Optional, as the Void is never actually represented. - VoidKind TypeDefKind = "VOID_KIND" + // Deprecated: use TypeDefKindVoidKind instead + VoidKind TypeDefKind = TypeDefKindVoidKind ) type Client struct { diff --git a/dagger/internal/telemetry/attrs.go b/dagger/internal/telemetry/attrs.go index f830f3fc7..7e48793dd 100644 --- a/dagger/internal/telemetry/attrs.go +++ b/dagger/internal/telemetry/attrs.go @@ -83,4 +83,10 @@ const ( // Indicates whether the log should be shown globally. LogsGlobalAttr = "dagger.io/logs.global" + + // OTel metric attribute so we can correlate metrics with spans + MetricsSpanIDAttr = "dagger.io/metrics.span" + + // OTel metric attribute so we can correlate metrics with traces + MetricsTraceIDAttr = "dagger.io/metrics.trace" ) diff --git a/dagger/internal/telemetry/init.go b/dagger/internal/telemetry/init.go index 74f3bb632..8d5a265d2 100644 --- a/dagger/internal/telemetry/init.go +++ b/dagger/internal/telemetry/init.go @@ -14,38 +14,31 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/propagation" sdklog "go.opentelemetry.io/otel/sdk/log" + 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.24.0" "google.golang.org/grpc" ) -func OTelConfigured() bool { - for _, env := range os.Environ() { - if strings.HasPrefix(env, "OTEL_") { - return true - } - } - return false -} - -var configuredSpanExporter sdktrace.SpanExporter -var configuredSpanExporterOnce sync.Once +var ( + configuredSpanExporter sdktrace.SpanExporter + configuredSpanExporterOnce sync.Once +) func ConfiguredSpanExporter(ctx context.Context) (sdktrace.SpanExporter, bool) { ctx = context.WithoutCancel(ctx) configuredSpanExporterOnce.Do(func() { - if !OTelConfigured() { - return - } - var err error + // handle protocol first so we can guess the full uri from a top-level OTLP endpoint var proto string if v := os.Getenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"); v != "" { proto = v @@ -71,6 +64,11 @@ func ConfiguredSpanExporter(ctx context.Context) (sdktrace.SpanExporter, bool) { } } + if endpoint == "" { + return + } + + //nolint:dupl switch proto { case "http/protobuf", "http": headers := map[string]string{} @@ -87,7 +85,7 @@ func ConfiguredSpanExporter(ctx context.Context) (sdktrace.SpanExporter, bool) { var u *url.URL u, err = url.Parse(endpoint) if err != nil { - slog.Warn("bad OTLP logs endpoint %q: %w", endpoint, err) + slog.Warn("bad OTLP span endpoint %q: %w", endpoint, err) return } opts := []otlptracegrpc.Option{ @@ -188,9 +186,84 @@ func ConfiguredLogExporter(ctx context.Context) (sdklog.Exporter, bool) { return configuredLogExporter, configuredLogExporter != nil } -// FallbackResource is the fallback resource definition. A more specific +var configuredMetricExporter sdkmetric.Exporter +var configuredMetricExporterOnce sync.Once + +func ConfiguredMetricExporter(ctx context.Context) (sdkmetric.Exporter, bool) { + ctx = context.WithoutCancel(ctx) + + configuredMetricExporterOnce.Do(func() { + var err error + + var endpoint string + if v := os.Getenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"); v != "" { + endpoint = v + } else if v := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"); v != "" { + // we can't assume all OTLP endpoints support metrics. better to be explicit + // than have noisy otel errors. + return + } + if endpoint == "" { + return + } + + var proto string + if v := os.Getenv("OTEL_EXPORTER_OTLP_METRICS_PROTOCOL"); v != "" { + proto = v + } else if v := os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL"); v != "" { + proto = v + } else { + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md#specify-protocol + proto = "http/protobuf" + } + + //nolint:dupl + switch proto { + case "http/protobuf", "http": + headers := map[string]string{} + if hs := os.Getenv("OTEL_EXPORTER_OTLP_HEADERS"); hs != "" { + for _, header := range strings.Split(hs, ",") { + name, value, _ := strings.Cut(header, "=") + headers[name] = value + } + } + configuredMetricExporter, err = otlpmetrichttp.New(ctx, + otlpmetrichttp.WithEndpointURL(endpoint), + otlpmetrichttp.WithHeaders(headers)) + + case "grpc": + var u *url.URL + u, err = url.Parse(endpoint) + if err != nil { + slog.Warn("bad OTLP metrics endpoint %q: %w", endpoint, err) + return + } + opts := []otlpmetricgrpc.Option{ + otlpmetricgrpc.WithEndpointURL(endpoint), + } + if u.Scheme == "unix" { + dialer := func(ctx context.Context, addr string) (net.Conn, error) { + return net.Dial(u.Scheme, u.Path) + } + opts = append(opts, + otlpmetricgrpc.WithDialOption(grpc.WithContextDialer(dialer)), + otlpmetricgrpc.WithInsecure()) + } + configuredMetricExporter, err = otlpmetricgrpc.New(ctx, opts...) + + default: + err = fmt.Errorf("unknown OTLP protocol: %s", proto) + } + if err != nil { + slog.Warn("failed to configure metrics", "error", err) + } + }) + return configuredMetricExporter, configuredMetricExporter != nil +} + +// fallbackResource is the fallback resource definition. A more specific // resource should be set in Init. -func FallbackResource() *resource.Resource { +func fallbackResource() *resource.Resource { return resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("dagger"), @@ -224,6 +297,9 @@ type Config struct { // LiveLogExporters are exporters that receive logs in batches of ~100ms. LiveLogExporters []sdklog.Exporter + // LiveMetricExporters are exporters that receive metrics in batches of ~1s. + LiveMetricExporters []sdkmetric.Exporter + // Resource is the resource describing this component and runtime // environment. Resource *resource.Resource @@ -237,8 +313,10 @@ const NearlyImmediate = 100 * time.Millisecond // sent live span telemetry. var LiveTracesEnabled = os.Getenv("OTEL_EXPORTER_OTLP_TRACES_LIVE") != "" +var Resource *resource.Resource var SpanProcessors = []sdktrace.SpanProcessor{} var LogProcessors = []sdklog.Processor{} +var MetricExporters = []sdkmetric.Exporter{} func InitEmbedded(ctx context.Context, res *resource.Resource) context.Context { traceCfg := Config{ @@ -251,6 +329,9 @@ func InitEmbedded(ctx context.Context, res *resource.Resource) context.Context { if exp, ok := ConfiguredLogExporter(ctx); ok { traceCfg.LiveLogExporters = append(traceCfg.LiveLogExporters, exp) } + if exp, ok := ConfiguredMetricExporter(ctx); ok { + traceCfg.LiveMetricExporters = append(traceCfg.LiveMetricExporters, exp) + } return Init(ctx, traceCfg) } @@ -284,9 +365,13 @@ func Init(ctx context.Context, cfg Config) context.Context { })) if cfg.Resource == nil { - cfg.Resource = FallbackResource() + cfg.Resource = fallbackResource() } + // Set up the global resource so we can pass it into dynamically allocated + // log/trace providers at runtime. + Resource = cfg.Resource + if cfg.Detect { if exp, ok := ConfiguredSpanExporter(ctx); ok { if LiveTracesEnabled { @@ -305,6 +390,9 @@ func Init(ctx context.Context, cfg Config) context.Context { if exp, ok := ConfiguredLogExporter(ctx); ok { cfg.LiveLogExporters = append(cfg.LiveLogExporters, exp) } + if exp, ok := ConfiguredMetricExporter(ctx); ok { + cfg.LiveMetricExporters = append(cfg.LiveMetricExporters, exp) + } } traceOpts := []sdktrace.TracerProviderOption{ @@ -336,7 +424,9 @@ func Init(ctx context.Context, cfg Config) context.Context { // Set up a log provider if configured. if len(cfg.LiveLogExporters) > 0 { - logOpts := []sdklog.LoggerProviderOption{} + logOpts := []sdklog.LoggerProviderOption{ + sdklog.WithResource(cfg.Resource), + } for _, exp := range cfg.LiveLogExporters { processor := sdklog.NewBatchProcessor(exp, sdklog.WithExportInterval(NearlyImmediate)) @@ -346,6 +436,24 @@ func Init(ctx context.Context, cfg Config) context.Context { ctx = WithLoggerProvider(ctx, sdklog.NewLoggerProvider(logOpts...)) } + // Set up a metric provider if configured. + if len(cfg.LiveMetricExporters) > 0 { + meterOpts := []sdkmetric.Option{ + sdkmetric.WithResource(cfg.Resource), + } + const metricsExportInterval = 1 * time.Second + const metricsExportTimeout = 1 * time.Second + for _, exp := range cfg.LiveMetricExporters { + MetricExporters = append(MetricExporters, exp) + reader := sdkmetric.NewPeriodicReader(exp, + sdkmetric.WithInterval(metricsExportInterval), + sdkmetric.WithTimeout(metricsExportTimeout), + ) + meterOpts = append(meterOpts, sdkmetric.WithReader(reader)) + } + ctx = WithMeterProvider(ctx, sdkmetric.NewMeterProvider(meterOpts...)) + } + closeCtx = ctx return ctx diff --git a/dagger/internal/telemetry/logging.go b/dagger/internal/telemetry/logging.go index ed1d38834..a152a042f 100644 --- a/dagger/internal/telemetry/logging.go +++ b/dagger/internal/telemetry/logging.go @@ -40,7 +40,7 @@ func Logger(ctx context.Context, name string) log.Logger { // stdout/stderr and terminates them with an EOF, to confirm that all data has // been received. It should not be used for general-purpose logging. // -// Both streamsm must be closed to ensure that draining completes. +// Both streams must be closed to ensure that draining completes. func SpanStdio(ctx context.Context, name string, attrs ...log.KeyValue) SpanStreams { logger := Logger(ctx, name) return SpanStreams{ diff --git a/dagger/internal/telemetry/metrics.go b/dagger/internal/telemetry/metrics.go new file mode 100644 index 000000000..93186e9f1 --- /dev/null +++ b/dagger/internal/telemetry/metrics.go @@ -0,0 +1,61 @@ +package telemetry + +import ( + "context" + + "go.opentelemetry.io/otel/metric" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" +) + +const ( + // OTel metric for number of bytes read from disk by a container, as parsed from its cgroup + IOStatDiskReadBytes = "dagger.io/metrics.iostat.disk.readbytes" + + // OTel metric for number of bytes written to disk by a container, as parsed from its cgroup + IOStatDiskWriteBytes = "dagger.io/metrics.iostat.disk.writebytes" + + // OTel metric for number of microseconds SOME tasks in a cgroup were stalled on IO due to resource contention + IOStatPressureSomeTotal = "dagger.io/metrics.iostat.pressure.some.total" + + // OTel metric for number of microseconds of all CPU usage of a container, as parsed from its cgroup + CPUStatUsage = "dagger.io/metrics.cpustat.usage" + + // OTel metric for number of microseconds of CPU time spent in user mode by a container, as parsed from its cgroup + CPUStatUser = "dagger.io/metrics.cpustat.user" + + // OTel metric for number of microseconds of CPU time spent in system mode by a container, as parsed from its cgroup + CPUStatSystem = "dagger.io/metrics.cpustat.system" + + // OTel metric for number of microseconds SOME tasks in a cgroup were stalled on CPU due to resource contention + CPUStatPressureSomeTotal = "dagger.io/metrics.cpustat.pressure.some.total" + + // OTel metric for number of microseconds ALL tasks in a cgroup were stalled on CPU due to resource contention + CPUStatPressureFullTotal = "dagger.io/metrics.cpustat.pressure.full.total" + + // OTel metric units should be in UCUM format + // https://unitsofmeasure.org/ucum + + // Bytes unit for OTel metrics + ByteUnitName = "byte" + + // Microseconds unit for OTel metrics + MicrosecondUnitName = "us" +) + +type meterProviderKey struct{} + +func WithMeterProvider(ctx context.Context, provider *sdkmetric.MeterProvider) context.Context { + return context.WithValue(ctx, meterProviderKey{}, provider) +} + +func MeterProvider(ctx context.Context) *sdkmetric.MeterProvider { + meterProvider := sdkmetric.NewMeterProvider() + if val := ctx.Value(meterProviderKey{}); val != nil { + meterProvider = val.(*sdkmetric.MeterProvider) + } + return meterProvider +} + +func Meter(ctx context.Context, name string) metric.Meter { + return MeterProvider(ctx).Meter(name) +} diff --git a/dagger/internal/telemetry/transform.go b/dagger/internal/telemetry/transform.go index 8090d4c01..8147969df 100644 --- a/dagger/internal/telemetry/transform.go +++ b/dagger/internal/telemetry/transform.go @@ -1,6 +1,7 @@ package telemetry import ( + "errors" "fmt" "log/slog" "time" @@ -10,11 +11,13 @@ import ( "go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/sdk/instrumentation" sdklog "go.opentelemetry.io/otel/sdk/log" + "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" otlpcommonv1 "go.opentelemetry.io/proto/otlp/common/v1" otlplogsv1 "go.opentelemetry.io/proto/otlp/logs/v1" + otlpmetricsv1 "go.opentelemetry.io/proto/otlp/metrics/v1" otlpresourcev1 "go.opentelemetry.io/proto/otlp/resource/v1" otlptracev1 "go.opentelemetry.io/proto/otlp/trace/v1" ) @@ -48,7 +51,7 @@ func LogsToPB(sdl []sdklog.Record) []*otlplogsv1.ResourceLogs { if !iOk { // Either the resource or instrumentation scope were unknown. scopeLog = &otlplogsv1.ScopeLogs{ - Scope: InstrumentationScope(sd.InstrumentationScope()), + Scope: InstrumentationScopeToPB(sd.InstrumentationScope()), LogRecords: []*otlplogsv1.LogRecord{}, SchemaUrl: sd.InstrumentationScope().SchemaURL, } @@ -61,7 +64,7 @@ func LogsToPB(sdl []sdklog.Record) []*otlplogsv1.ResourceLogs { resources++ // The resource was unknown. rs = &otlplogsv1.ResourceLogs{ - Resource: Resource(res), + Resource: ResourceToPB(res), ScopeLogs: []*otlplogsv1.ScopeLogs{scopeLog}, SchemaUrl: res.SchemaURL(), } @@ -87,7 +90,7 @@ func LogsToPB(sdl []sdklog.Record) []*otlplogsv1.ResourceLogs { return rss } -func InstrumentationScope(il instrumentation.Scope) *otlpcommonv1.InstrumentationScope { +func InstrumentationScopeToPB(il instrumentation.Scope) *otlpcommonv1.InstrumentationScope { if il == (instrumentation.Scope{}) { return nil } @@ -124,13 +127,22 @@ func logRecord(l sdklog.Record) *otlplogsv1.LogRecord { return s } -// Resource transforms a Resource into an OTLP Resource. -func Resource(r resource.Resource) *otlpresourcev1.Resource { +// ResourceToPB transforms a Resource into an OTLP Resource. +func ResourceToPB(r resource.Resource) *otlpresourcev1.Resource { return &otlpresourcev1.Resource{Attributes: resourceAttributes(r)} } -// Resource transforms a Resource into an OTLP Resource. -func ResourcePtr(r *resource.Resource) *otlpresourcev1.Resource { +// ResourceFromPB creates a *resource.Resource from a schema URL and +// protobuf encoded attributes. +func ResourceFromPB(schemaURL string, pb *otlpresourcev1.Resource) *resource.Resource { + if schemaURL == "" { + return resource.NewSchemaless(AttributesFromProto(pb.Attributes)...) + } + return resource.NewWithAttributes(schemaURL, AttributesFromProto(pb.Attributes)...) +} + +// ResourcePtrToPB transforms a *Resource into an OTLP Resource. +func ResourcePtrToPB(r *resource.Resource) *otlpresourcev1.Resource { if r == nil { return nil } @@ -325,7 +337,7 @@ func SpansToPB(sdl []sdktrace.ReadOnlySpan) []*otlptracev1.ResourceSpans { if !iOk { // Either the resource or instrumentation scope were unknown. scopeSpan = &otlptracev1.ScopeSpans{ - Scope: InstrumentationScope(sd.InstrumentationScope()), + Scope: InstrumentationScopeToPB(sd.InstrumentationScope()), Spans: []*otlptracev1.Span{}, SchemaUrl: sd.InstrumentationScope().SchemaURL, } @@ -338,7 +350,7 @@ func SpansToPB(sdl []sdktrace.ReadOnlySpan) []*otlptracev1.ResourceSpans { resources++ // The resource was unknown. rs = &otlptracev1.ResourceSpans{ - Resource: ResourcePtr(sd.Resource()), + Resource: ResourcePtrToPB(sd.Resource()), ScopeSpans: []*otlptracev1.ScopeSpans{scopeSpan}, SchemaUrl: sd.Resource().SchemaURL(), } @@ -588,13 +600,7 @@ func (s *readOnlySpan) InstrumentationLibrary() instrumentation.Library { // Resource returns information about the entity that produced the span. func (s *readOnlySpan) Resource() *resource.Resource { - if s.resource == nil { - return nil - } - if s.schemaURL != "" { - return resource.NewWithAttributes(s.schemaURL, AttributesFromProto(s.resource.Attributes)...) - } - return resource.NewSchemaless(AttributesFromProto(s.resource.Attributes)...) + return ResourceFromPB(s.schemaURL, s.resource) } // DroppedAttributes returns the number of attributes dropped by the span @@ -956,3 +962,492 @@ func LogValueToPB(v log.Value) *otlpcommonv1.AnyValue { } return av } + +func ResourceMetricsFromPB(pbResourceMetrics *otlpmetricsv1.ResourceMetrics) (*metricdata.ResourceMetrics, error) { + resourceMetrics := &metricdata.ResourceMetrics{ + Resource: ResourceFromPB(pbResourceMetrics.GetSchemaUrl(), pbResourceMetrics.GetResource()), + } + var err error + resourceMetrics.ScopeMetrics, err = ScopeMetricsFromPB(pbResourceMetrics.GetScopeMetrics()) + if err != nil { + return nil, err + } + return resourceMetrics, nil +} + +// 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 ResourceMetricsToPB(rm *metricdata.ResourceMetrics) (*otlpmetricsv1.ResourceMetrics, error) { + sms, err := ScopeMetricsToPB(rm.ScopeMetrics) + return &otlpmetricsv1.ResourceMetrics{ + Resource: &otlpresourcev1.Resource{ + Attributes: iterator(rm.Resource.Iter()), + }, + ScopeMetrics: sms, + SchemaUrl: rm.Resource.SchemaURL(), + }, err +} + +func ScopeMetricsFromPB(pbScopeMetrics []*otlpmetricsv1.ScopeMetrics) ([]metricdata.ScopeMetrics, error) { + var errs error + scopeMetrics := make([]metricdata.ScopeMetrics, 0, len(pbScopeMetrics)) + for _, pbScopeMetric := range pbScopeMetrics { + scopeMetric := metricdata.ScopeMetrics{ + Scope: InstrumentationScopeFromPB(pbScopeMetric.GetScope()), + } + var err error + scopeMetric.Metrics, err = MetricsFromPB(pbScopeMetric.GetMetrics()) + if err != nil { + errs = errors.Join(errs, err) + continue + } + scopeMetrics = append(scopeMetrics, scopeMetric) + } + return scopeMetrics, errs +} + +// 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 ScopeMetricsToPB(sms []metricdata.ScopeMetrics) ([]*otlpmetricsv1.ScopeMetrics, error) { + var errs error + out := make([]*otlpmetricsv1.ScopeMetrics, 0, len(sms)) + for _, sm := range sms { + ms, err := MetricsToPB(sm.Metrics) + if err != nil { + errs = errors.Join(errs, err) + continue + } + + out = append(out, &otlpmetricsv1.ScopeMetrics{ + Scope: &otlpcommonv1.InstrumentationScope{ + Name: sm.Scope.Name, + Version: sm.Scope.Version, + }, + Metrics: ms, + SchemaUrl: sm.Scope.SchemaURL, + }) + } + return out, errs +} + +func MetricsFromPB(pbMetrics []*otlpmetricsv1.Metric) ([]metricdata.Metrics, error) { + var errs error + out := make([]metricdata.Metrics, 0, len(pbMetrics)) + for _, pbMetric := range pbMetrics { + metric, err := metricFromPB(pbMetric) + if err != nil { + errs = errors.Join(errs, err) + continue + } + out = append(out, metric) + } + return out, errs +} + +// 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 MetricsToPB(ms []metricdata.Metrics) ([]*otlpmetricsv1.Metric, error) { + var errs error + out := make([]*otlpmetricsv1.Metric, 0, len(ms)) + for _, m := range ms { + o, err := metricToPB(m) + if err != nil { + // Do not include invalid data. Drop the metric, report the error. + errs = errors.Join(errs, err) + continue + } + out = append(out, o) + } + return out, errs +} + +func metricFromPB(pbMetric *otlpmetricsv1.Metric) (metricdata.Metrics, error) { + m := metricdata.Metrics{ + Name: pbMetric.Name, + Description: pbMetric.Description, + Unit: pbMetric.Unit, + } + switch a := pbMetric.Data.(type) { + // TODO: rest of cases once needed (hand-writing this rather than copy-pasting from internal otlp package) + case *otlpmetricsv1.Metric_Gauge: + res := gaugeFromPB(a.Gauge) + // NOTE: setting m.Data to non-pointer value is important, metrics exporters will fail if it's a pointer + switch { + case res.AsInt != nil: + m.Data = *res.AsInt + case res.AsDouble != nil: + m.Data = *res.AsDouble + } + default: + return m, fmt.Errorf("unknown aggregation from pb: %T", a) + } + return m, nil +} + +func metricToPB(m metricdata.Metrics) (*otlpmetricsv1.Metric, error) { + var err error + out := &otlpmetricsv1.Metric{ + Name: m.Name, + Description: m.Description, + Unit: m.Unit, + } + switch a := m.Data.(type) { + case metricdata.Gauge[int64]: + out.Data = GaugeToPB(a) + case metricdata.Gauge[float64]: + out.Data = GaugeToPB(a) + case metricdata.Sum[int64]: + out.Data, err = SumToPB(a) + case metricdata.Sum[float64]: + out.Data, err = SumToPB(a) + case metricdata.Histogram[int64]: + out.Data, err = HistogramToPB(a) + case metricdata.Histogram[float64]: + out.Data, err = HistogramToPB(a) + case metricdata.ExponentialHistogram[int64]: + out.Data, err = ExponentialHistogramToPB(a) + case metricdata.ExponentialHistogram[float64]: + out.Data, err = ExponentialHistogramToPB(a) + case metricdata.Summary: + out.Data = SummaryToPB(a) + default: + return out, fmt.Errorf("unknown aggregation to pb: %T", a) + } + return out, err +} + +type gaugeFromPBResult struct { + // only one of these will be set, depending on whether the ungeneric input + // resolves to in the returned generic type + AsInt *metricdata.Gauge[int64] + AsDouble *metricdata.Gauge[float64] +} + +func gaugeFromPB(g *otlpmetricsv1.Gauge) gaugeFromPBResult { + dataPointsRes := dataPointsFromPB(g.DataPoints) + res := gaugeFromPBResult{} + switch { + case len(dataPointsRes.AsInt) > 0: + res = gaugeFromPBResult{ + AsInt: &metricdata.Gauge[int64]{ + DataPoints: dataPointsRes.AsInt, + }, + } + case len(dataPointsRes.AsDouble) > 0: + res = gaugeFromPBResult{ + AsDouble: &metricdata.Gauge[float64]{ + DataPoints: dataPointsRes.AsDouble, + }, + } + } + return res +} + +// GaugeToPB returns an OTLP Metric_Gauge generated from g. +func GaugeToPB[N int64 | float64](g metricdata.Gauge[N]) *otlpmetricsv1.Metric_Gauge { + return &otlpmetricsv1.Metric_Gauge{ + Gauge: &otlpmetricsv1.Gauge{ + DataPoints: DataPointsToPB(g.DataPoints), + }, + } +} + +// SumToPB returns an OTLP Metric_Sum generated from s. An error is returned +// if the temporality of s is unknown. +func SumToPB[N int64 | float64](s metricdata.Sum[N]) (*otlpmetricsv1.Metric_Sum, error) { + t, err := TemporalityToPB(s.Temporality) + if err != nil { + return nil, err + } + return &otlpmetricsv1.Metric_Sum{ + Sum: &otlpmetricsv1.Sum{ + AggregationTemporality: t, + IsMonotonic: s.IsMonotonic, + DataPoints: DataPointsToPB(s.DataPoints), + }, + }, nil +} + +type dataPointsFromPBResult struct { + // only one of these will be set, depending on whether the ungeneric input + // resolves to in the returned generic type + AsInt []metricdata.DataPoint[int64] + AsDouble []metricdata.DataPoint[float64] +} + +func dataPointsFromPB(dPts []*otlpmetricsv1.NumberDataPoint) dataPointsFromPBResult { + res := dataPointsFromPBResult{} + for _, dPt := range dPts { + switch pbV := dPt.Value.(type) { + case *otlpmetricsv1.NumberDataPoint_AsInt: + res.AsInt = append(res.AsInt, metricdata.DataPoint[int64]{ + Attributes: attribute.NewSet(AttributesFromProto(dPt.Attributes)...), + StartTime: time.Unix(0, int64(dPt.StartTimeUnixNano)), + Time: time.Unix(0, int64(dPt.TimeUnixNano)), + Value: pbV.AsInt, + Exemplars: exemplarsFromPB(dPt.Exemplars).AsInt, + }) + case *otlpmetricsv1.NumberDataPoint_AsDouble: + res.AsDouble = append(res.AsDouble, metricdata.DataPoint[float64]{ + Attributes: attribute.NewSet(AttributesFromProto(dPt.Attributes)...), + StartTime: time.Unix(0, int64(dPt.StartTimeUnixNano)), + Time: time.Unix(0, int64(dPt.TimeUnixNano)), + Value: pbV.AsDouble, + Exemplars: exemplarsFromPB(dPt.Exemplars).AsDouble, + }) + } + } + return res +} + +// DataPointsToPB returns a slice of OTLP NumberDataPoint generated from dPts. +func DataPointsToPB[N int64 | float64](dPts []metricdata.DataPoint[N]) []*otlpmetricsv1.NumberDataPoint { + out := make([]*otlpmetricsv1.NumberDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + ndp := &otlpmetricsv1.NumberDataPoint{ + Attributes: iterator(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Exemplars: ExemplarsToPB(dPt.Exemplars), + } + switch v := any(dPt.Value).(type) { + case int64: + ndp.Value = &otlpmetricsv1.NumberDataPoint_AsInt{ + AsInt: v, + } + case float64: + ndp.Value = &otlpmetricsv1.NumberDataPoint_AsDouble{ + AsDouble: v, + } + } + out = append(out, ndp) + } + return out +} + +// HistogramToPB returns an OTLP Metric_Histogram generated from h. An error is +// returned if the temporality of h is unknown. +func HistogramToPB[N int64 | float64](h metricdata.Histogram[N]) (*otlpmetricsv1.Metric_Histogram, error) { + t, err := TemporalityToPB(h.Temporality) + if err != nil { + return nil, err + } + return &otlpmetricsv1.Metric_Histogram{ + Histogram: &otlpmetricsv1.Histogram{ + AggregationTemporality: t, + DataPoints: HistogramDataPointsToPB(h.DataPoints), + }, + }, nil +} + +// HistogramDataPointsToPB returns a slice of OTLP HistogramDataPoint generated +// from dPts. +func HistogramDataPointsToPB[N int64 | float64](dPts []metricdata.HistogramDataPoint[N]) []*otlpmetricsv1.HistogramDataPoint { + out := make([]*otlpmetricsv1.HistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + hdp := &otlpmetricsv1.HistogramDataPoint{ + Attributes: iterator(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + BucketCounts: dPt.BucketCounts, + ExplicitBounds: dPt.Bounds, + Exemplars: ExemplarsToPB(dPt.Exemplars), + } + 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 +} + +// ExponentialHistogramToPB returns an OTLP Metric_ExponentialHistogram generated from h. An error is +// returned if the temporality of h is unknown. +func ExponentialHistogramToPB[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*otlpmetricsv1.Metric_ExponentialHistogram, error) { + t, err := TemporalityToPB(h.Temporality) + if err != nil { + return nil, err + } + return &otlpmetricsv1.Metric_ExponentialHistogram{ + ExponentialHistogram: &otlpmetricsv1.ExponentialHistogram{ + AggregationTemporality: t, + DataPoints: ExponentialHistogramDataPointsToPB(h.DataPoints), + }, + }, nil +} + +// ExponentialHistogramDataPointsToPB returns a slice of OTLP ExponentialHistogramDataPoint generated +// from dPts. +func ExponentialHistogramDataPointsToPB[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*otlpmetricsv1.ExponentialHistogramDataPoint { + out := make([]*otlpmetricsv1.ExponentialHistogramDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sum := float64(dPt.Sum) + ehdp := &otlpmetricsv1.ExponentialHistogramDataPoint{ + Attributes: iterator(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: &sum, + Scale: dPt.Scale, + ZeroCount: dPt.ZeroCount, + Exemplars: ExemplarsToPB(dPt.Exemplars), + + Positive: ExponentialHistogramDataPointBucketsToPB(dPt.PositiveBucket), + Negative: ExponentialHistogramDataPointBucketsToPB(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 +} + +// ExponentialHistogramDataPointBucketsToPB returns an OTLP ExponentialHistogramDataPoint_Buckets generated +// from bucket. +func ExponentialHistogramDataPointBucketsToPB(bucket metricdata.ExponentialBucket) *otlpmetricsv1.ExponentialHistogramDataPoint_Buckets { + return &otlpmetricsv1.ExponentialHistogramDataPoint_Buckets{ + Offset: bucket.Offset, + BucketCounts: bucket.Counts, + } +} + +// TemporalityToPB returns an OTLP AggregationTemporality generated from t. If t +// is unknown, an error is returned along with the invalid +// AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED. +func TemporalityToPB(t metricdata.Temporality) (otlpmetricsv1.AggregationTemporality, error) { + switch t { + case metricdata.DeltaTemporality: + return otlpmetricsv1.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, nil + case metricdata.CumulativeTemporality: + return otlpmetricsv1.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE, nil + default: + err := fmt.Errorf("unknown temporality: %s", t) + return otlpmetricsv1.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 { + return uint64(max(0, t.UnixNano())) +} + +type exemplarFromPBResult struct { + // only one of these will be set, depending on whether the ungeneric input + // resolves to in the returned generic type + AsInt []metricdata.Exemplar[int64] + AsDouble []metricdata.Exemplar[float64] +} + +func exemplarsFromPB(exemplars []*otlpmetricsv1.Exemplar) exemplarFromPBResult { + res := exemplarFromPBResult{} + for _, pbExemplar := range exemplars { + switch pbV := pbExemplar.Value.(type) { + case *otlpmetricsv1.Exemplar_AsInt: + res.AsInt = append(res.AsInt, metricdata.Exemplar[int64]{ + FilteredAttributes: AttributesFromProto(pbExemplar.FilteredAttributes), + Time: time.Unix(0, int64(pbExemplar.TimeUnixNano)), + Value: pbV.AsInt, + SpanID: pbExemplar.SpanId, + TraceID: pbExemplar.TraceId, + }) + case *otlpmetricsv1.Exemplar_AsDouble: + res.AsDouble = append(res.AsDouble, metricdata.Exemplar[float64]{ + FilteredAttributes: AttributesFromProto(pbExemplar.FilteredAttributes), + Time: time.Unix(0, int64(pbExemplar.TimeUnixNano)), + Value: pbV.AsDouble, + SpanID: pbExemplar.SpanId, + TraceID: pbExemplar.TraceId, + }) + } + } + return res +} + +// ExemplarsToPB returns a slice of OTLP ExemplarsToPB generated from exemplars. +func ExemplarsToPB[N int64 | float64](exemplars []metricdata.Exemplar[N]) []*otlpmetricsv1.Exemplar { + out := make([]*otlpmetricsv1.Exemplar, 0, len(exemplars)) + for _, exemplar := range exemplars { + e := &otlpmetricsv1.Exemplar{ + FilteredAttributes: KeyValues(exemplar.FilteredAttributes), + TimeUnixNano: timeUnixNano(exemplar.Time), + SpanId: exemplar.SpanID, + TraceId: exemplar.TraceID, + } + switch v := any(exemplar.Value).(type) { + case int64: + e.Value = &otlpmetricsv1.Exemplar_AsInt{ + AsInt: v, + } + case float64: + e.Value = &otlpmetricsv1.Exemplar_AsDouble{ + AsDouble: v, + } + } + out = append(out, e) + } + return out +} + +// SummaryToPB returns an OTLP Metric_Summary generated from s. +func SummaryToPB(s metricdata.Summary) *otlpmetricsv1.Metric_Summary { + return &otlpmetricsv1.Metric_Summary{ + Summary: &otlpmetricsv1.Summary{ + DataPoints: SummaryDataPointsToPB(s.DataPoints), + }, + } +} + +// SummaryDataPointsToPB returns a slice of OTLP SummaryDataPoint generated from +// dPts. +func SummaryDataPointsToPB(dPts []metricdata.SummaryDataPoint) []*otlpmetricsv1.SummaryDataPoint { + out := make([]*otlpmetricsv1.SummaryDataPoint, 0, len(dPts)) + for _, dPt := range dPts { + sdp := &otlpmetricsv1.SummaryDataPoint{ + Attributes: iterator(dPt.Attributes.Iter()), + StartTimeUnixNano: timeUnixNano(dPt.StartTime), + TimeUnixNano: timeUnixNano(dPt.Time), + Count: dPt.Count, + Sum: dPt.Sum, + QuantileValues: QuantileValuesToPB(dPt.QuantileValues), + } + out = append(out, sdp) + } + return out +} + +// QuantileValuesToPB returns a slice of OTLP SummaryDataPoint_ValueAtQuantile +// generated from quantiles. +func QuantileValuesToPB(quantiles []metricdata.QuantileValue) []*otlpmetricsv1.SummaryDataPoint_ValueAtQuantile { + out := make([]*otlpmetricsv1.SummaryDataPoint_ValueAtQuantile, 0, len(quantiles)) + for _, q := range quantiles { + quantile := &otlpmetricsv1.SummaryDataPoint_ValueAtQuantile{ + Quantile: q.Quantile, + Value: q.Value, + } + out = append(out, quantile) + } + return out +} diff --git a/go.work.sum b/go.work.sum index 724460a97..c33c55ffb 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,5 +1,6 @@ cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= @@ -28,8 +29,10 @@ github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= @@ -45,13 +48,13 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -94,6 +97,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= @@ -130,8 +134,10 @@ golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -146,6 +152,7 @@ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=