vendor: OTEL v1.19.0 / v0.45.0, containerd v1.7.11
- relates to https://github.com/containerd/containerd/pull/9281
- relates to https://github.com/moby/buildkit/pull/4318
- includes fix for https://github.com/open-telemetry/opentelemetry-go-contrib/security/advisories/GHSA-5r5m-65gx-7vrh
- [x] depends on https://github.com/moby/moby/pull/46914
- [x] depends on https://github.com/moby/buildkit/pull/4472
- [x] depends on https://github.com/containerd/containerd/pull/9480
---

### vendor: vendor: upgrade OpenTelemetry to v1.19.0 / v0.45.0

Upgrade to the latest OpenTelemetry libraries; this will unblock a lot of
downstream projects in the ecosystem to upgrade, as some of the parts here
were pre-1.0/unstable.

### vendor: github.com/containerd/containerd v1.7.9

full diff: https://github.com/containerd/containerd/compare/v1.7.8...v1.7.9

### vendor: github.com/containerd/containerd v1.7.10

full diff: https://github.com/containerd/containerd/compare/v1.7.9...v1.7.10

### vendor: github.com/containerd/containerd v1.7.11

full diff: https://github.com/containerd/containerd/compare/v1.7.10...v1.7.11

### vendor: github.com/moby/buildkit v0.12.5-0.20231208203051-3b6880d2a00f

full diff: https://github.com/moby/buildkit/compare/v0.12.4...3b6880d2a00fd6080019118ef40515be905e58db

### update to go.opentelemetry.io/otel/semconv/v1.21.0, remove "httpconv" uses

This commit switches our code to use semconv 1.21, which is the version matching
the OTEL modules, as well as the containerd code.

The BuildKit 0.12.x module currently uses an older version of the OTEL modules,
and uses the semconv 0.17 schema. Mixing schema-versions is problematic, but
we still want to consume BuildKit's "detect" package to wire-up other parts
of OTEL.

To align the versions in our code, this patch sets the BuildKit detect.Resource
with the correct semconv version.

It's worth noting that the BuildKit package has a custom "serviceNameDetector";
https://github.com/moby/buildkit/blob/v0.12.4/util/tracing/detect/detect.go#L153-L169

Whith is merged with OTEL's default resource:
https://github.com/moby/buildkit/blob/v0.12.4/util/tracing/detect/detect.go#L100-L107

There's no need to duplicate that code, as OTEL's `resource.Default()` already
provides this functionality:

- It uses fromEnv{} detector internally: https://github.com/open-telemetry/opentelemetry-go/blob/v1.19.0/sdk/resource/resource.go#L208
- fromEnv{} detector reads OTEL_SERVICE_NAME: https://github.com/open-telemetry/opentelemetry-go/blob/v1.19.0/sdk/resource/env.go#L53

This patch also removes uses of the httpconv package, which is no longer included
in semconv 1.21 and now an internal package. Removing the use of this package
means that hijacked connections will not have the HTTP attributes on the Moby
client span, which isn't ideal, but a limited loss that'd impact exec/attach.
The span itself will still exist, it just won't the additional attributes that
are added by that package.

Alternatively, the httpconv call COULD remain - it will not error and will send
syntactically valid spans but we would be mixing & matching semconv versions,
so won't be compliant.

Some parts of the httpconv package were preserved through a very minimal local
implementation; a variant of `httpconv.ClientStatus(resp.StatusCode))` is added
to set the span status (`span.SetStatus()`). The `httpconv` package has complex
logic for this, but mostly drills down to HTTP status range (1xx/2xx/3xx/4xx/5xx)
to determine if the status was successfull or non-successful (4xx/5xx).

The additional logic it provided was to validate actual status-codes, and to
convert "bogus" status codes in "success" ranges (1xx, 2xx) into an error. That
code seemed over-reaching (and not accounting for potential future _valid_
status codes). Let's assume we only get valid status codes.

- https://github.com/open-telemetry/opentelemetry-go/blob/v1.21.0/semconv/v1.17.0/httpconv/http.go#L85-L89
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.21.0/semconv/internal/v2/http.go#L322-L330
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.21.0/semconv/internal/v2/http.go#L356-L404

**- What I did**

**- How I did it**

**- How to verify it**

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


**- A picture of a cute animal (not mandatory but encouraged)**


testutil/helpers.go
package testutil // import "github.com/docker/docker/testutil"

import (
	"context"
	"io"
	"os"
	"strings"
	"sync"
	"testing"

	"github.com/containerd/log"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
	"gotest.tools/v3/icmd"
)

// DevZero acts like /dev/zero but in an OS-independent fashion.
var DevZero io.Reader = devZero{}

type devZero struct{}

func (d devZero) Read(p []byte) (n int, err error) {
	for i := range p {
		p[i] = 0
	}
	return len(p), nil
}

var tracingOnce sync.Once

// configureTracing sets up an OTLP tracing exporter for use in tests.
func ConfigureTracing() func(context.Context) {
	if os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") == "" {
		// No OTLP endpoint configured, so don't bother setting up tracing.
		// Since we are not using a batch exporter we don't want tracing to block up tests.
		return func(context.Context) {}
	}
	var tp *trace.TracerProvider
	tracingOnce.Do(func() {
		ctx := context.Background()
		exp := otlptracehttp.NewUnstarted()
		sp := trace.NewBatchSpanProcessor(exp)
		props := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
		otel.SetTextMapPropagator(props)

		tp = trace.NewTracerProvider(
			trace.WithSpanProcessor(sp),
			trace.WithSampler(trace.AlwaysSample()),
			trace.WithResource(resource.NewSchemaless(
				attribute.KeyValue{Key: semconv.ServiceNameKey, Value: attribute.StringValue("integration-test-client")},
			)),
		)
		otel.SetTracerProvider(tp)

		if err := exp.Start(ctx); err != nil {
			log.G(ctx).WithError(err).Warn("Failed to start tracing exporter")
		}
	})

	// if ConfigureTracing was called multiple times we'd have a nil `tp` here
	// Get the already configured tracer provider
	if tp == nil {
		tp = otel.GetTracerProvider().(*trace.TracerProvider)
	}
	return func(ctx context.Context) {
		if err := tp.Shutdown(ctx); err != nil {
			log.G(ctx).WithError(err).Warn("Failed to shutdown tracer")
		}
	}
}

// TestingT is an interface wrapper around *testing.T and *testing.B.
type TestingT interface {
	Name() string
	Cleanup(func())
	Log(...any)
	Failed() bool
}

// StartSpan starts a span for the given test.
func StartSpan(ctx context.Context, t TestingT) context.Context {
	ConfigureTracing()
	ctx, span := otel.Tracer("").Start(ctx, t.Name())
	t.Cleanup(func() {
		if t.Failed() {
			span.SetStatus(codes.Error, "test failed")
		}
		span.End()
	})
	return ctx
}

func RunCommand(ctx context.Context, cmd string, args ...string) *icmd.Result {
	_, span := otel.Tracer("").Start(ctx, "RunCommand "+cmd+" "+strings.Join(args, " "))
	res := icmd.RunCommand(cmd, args...)
	if res.Error != nil {
		span.SetStatus(codes.Error, res.Error.Error())
	}
	span.SetAttributes(attribute.String("cmd", cmd), attribute.String("args", strings.Join(args, " ")))
	span.SetAttributes(attribute.Int("exit", res.ExitCode))
	span.SetAttributes(attribute.String("stdout", res.Stdout()), attribute.String("stderr", res.Stderr()))
	span.End()
	return res
}

type testContextStore struct {
	mu  sync.Mutex
	idx map[TestingT]context.Context
}

var testContexts = &testContextStore{idx: make(map[TestingT]context.Context)}

func (s *testContextStore) Get(t TestingT) context.Context {
	s.mu.Lock()
	defer s.mu.Unlock()

	ctx, ok := s.idx[t]
	if ok {
		return ctx
	}
	ctx = context.Background()
	s.idx[t] = ctx
	return ctx
}

func (s *testContextStore) Set(ctx context.Context, t TestingT) {
	s.mu.Lock()
	if _, ok := s.idx[t]; ok {
		panic("test context already set")
	}
	s.idx[t] = ctx
	s.mu.Unlock()
}

func (s *testContextStore) Delete(t *testing.T) {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.idx, t)
}

func GetContext(t TestingT) context.Context {
	return testContexts.Get(t)
}

func SetContext(t TestingT, ctx context.Context) {
	testContexts.Set(ctx, t)
}

func CleanupContext(t *testing.T) {
	testContexts.Delete(t)
}

package testutil // import "github.com/docker/docker/testutil"

import (
	"context"
	"io"
	"os"
	"strings"
	"sync"
	"testing"

	"github.com/containerd/log"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
	"gotest.tools/v3/icmd"
)

// DevZero acts like /dev/zero but in an OS-independent fashion.
var DevZero io.Reader = devZero{}

type devZero struct{}

func (d devZero) Read(p []byte) (n int, err error) {
	for i := range p {
		p[i] = 0
	}
	return len(p), nil
}

var tracingOnce sync.Once

// ConfigureTracing sets up an OTLP tracing exporter for use in tests.
func ConfigureTracing() func(context.Context) {
	if os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT") == "" {
		// No OTLP endpoint configured, so don't bother setting up tracing.
		// Since we are not using a batch exporter we don't want tracing to block up tests.
		return func(context.Context) {}
	}
	var tp *trace.TracerProvider
	tracingOnce.Do(func() {
		ctx := context.Background()
		exp := otlptracehttp.NewUnstarted()
		sp := trace.NewBatchSpanProcessor(exp)
		props := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
		otel.SetTextMapPropagator(props)

		tp = trace.NewTracerProvider(
			trace.WithSpanProcessor(sp),
			trace.WithSampler(trace.AlwaysSample()),
			trace.WithResource(resource.NewSchemaless(semconv.ServiceName("integration-test-client"))),
		)
		otel.SetTracerProvider(tp)

		if err := exp.Start(ctx); err != nil {
			log.G(ctx).WithError(err).Warn("Failed to start tracing exporter")
		}
	})

	// if ConfigureTracing was called multiple times we'd have a nil `tp` here
	// Get the already configured tracer provider
	if tp == nil {
		tp = otel.GetTracerProvider().(*trace.TracerProvider)
	}
	return func(ctx context.Context) {
		if err := tp.Shutdown(ctx); err != nil {
			log.G(ctx).WithError(err).Warn("Failed to shutdown tracer")
		}
	}
}

// TestingT is an interface wrapper around *testing.T and *testing.B.
type TestingT interface {
	Name() string
	Cleanup(func())
	Log(...any)
	Failed() bool
}

// StartSpan starts a span for the given test.
func StartSpan(ctx context.Context, t TestingT) context.Context {
	ConfigureTracing()
	ctx, span := otel.Tracer("").Start(ctx, t.Name())
	t.Cleanup(func() {
		if t.Failed() {
			span.SetStatus(codes.Error, "test failed")
		}
		span.End()
	})
	return ctx
}

func RunCommand(ctx context.Context, cmd string, args ...string) *icmd.Result {
	_, span := otel.Tracer("").Start(ctx, "RunCommand "+cmd+" "+strings.Join(args, " "))
	res := icmd.RunCommand(cmd, args...)
	if res.Error != nil {
		span.SetStatus(codes.Error, res.Error.Error())
	}
	span.SetAttributes(attribute.String("cmd", cmd), attribute.String("args", strings.Join(args, " ")))
	span.SetAttributes(attribute.Int("exit", res.ExitCode))
	span.SetAttributes(attribute.String("stdout", res.Stdout()), attribute.String("stderr", res.Stderr()))
	span.End()
	return res
}

type testContextStore struct {
	mu  sync.Mutex
	idx map[TestingT]context.Context
}

var testContexts = &testContextStore{idx: make(map[TestingT]context.Context)}

func (s *testContextStore) Get(t TestingT) context.Context {
	s.mu.Lock()
	defer s.mu.Unlock()

	ctx, ok := s.idx[t]
	if ok {
		return ctx
	}
	ctx = context.Background()
	s.idx[t] = ctx
	return ctx
}

func (s *testContextStore) Set(ctx context.Context, t TestingT) {
	s.mu.Lock()
	if _, ok := s.idx[t]; ok {
		panic("test context already set")
	}
	s.idx[t] = ctx
	s.mu.Unlock()
}

func (s *testContextStore) Delete(t *testing.T) {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.idx, t)
}

func GetContext(t TestingT) context.Context {
	return testContexts.Get(t)
}

func SetContext(t TestingT, ctx context.Context) {
	testContexts.Set(ctx, t)
}

func CleanupContext(t *testing.T) {
	testContexts.Delete(t)
}

This change is not strictly needed, but while working on this code, I found the `semconv.ServiceName` utility, and thought it was slightly cleaner than to manually construct the `attribute.KeyValue`