rebase: update K8s packages to v0.32.1

Update K8s packages in go.mod to v0.32.1

Signed-off-by: Praveen M <m.praveen@ibm.com>
This commit is contained in:
Praveen M
2025-01-16 09:41:46 +05:30
committed by mergify[bot]
parent 5aef21ea4e
commit 7eb99fc6c9
2442 changed files with 273386 additions and 47788 deletions

View File

@ -0,0 +1,162 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package containerd
import (
"context"
"errors"
"fmt"
"net"
"sync"
"time"
containersapi "github.com/containerd/containerd/api/services/containers/v1"
tasksapi "github.com/containerd/containerd/api/services/tasks/v1"
versionapi "github.com/containerd/containerd/api/services/version/v1"
tasktypes "github.com/containerd/containerd/api/types/task"
"github.com/containerd/errdefs"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
"google.golang.org/grpc/credentials/insecure"
emptypb "google.golang.org/protobuf/types/known/emptypb"
"github.com/google/cadvisor/container/containerd/containers"
"github.com/google/cadvisor/container/containerd/pkg/dialer"
)
type client struct {
containerService containersapi.ContainersClient
taskService tasksapi.TasksClient
versionService versionapi.VersionClient
}
type ContainerdClient interface {
LoadContainer(ctx context.Context, id string) (*containers.Container, error)
TaskPid(ctx context.Context, id string) (uint32, error)
Version(ctx context.Context) (string, error)
}
var (
ErrTaskIsInUnknownState = errors.New("containerd task is in unknown state") // used when process reported in containerd task is in Unknown State
)
var once sync.Once
var ctrdClient ContainerdClient = nil
const (
maxBackoffDelay = 3 * time.Second
baseBackoffDelay = 100 * time.Millisecond
connectionTimeout = 2 * time.Second
maxMsgSize = 16 * 1024 * 1024 // 16MB
)
// Client creates a containerd client
func Client(address, namespace string) (ContainerdClient, error) {
var retErr error
once.Do(func() {
tryConn, err := net.DialTimeout("unix", address, connectionTimeout)
if err != nil {
retErr = fmt.Errorf("containerd: cannot unix dial containerd api service: %v", err)
return
}
tryConn.Close()
connParams := grpc.ConnectParams{
Backoff: backoff.DefaultConfig,
}
connParams.Backoff.BaseDelay = baseBackoffDelay
connParams.Backoff.MaxDelay = maxBackoffDelay
//nolint:staticcheck // SA1019
gopts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(dialer.ContextDialer),
grpc.WithBlock(),
grpc.WithConnectParams(connParams),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)),
}
unary, stream := newNSInterceptors(namespace)
gopts = append(gopts,
grpc.WithUnaryInterceptor(unary),
grpc.WithStreamInterceptor(stream),
)
ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout)
defer cancel()
//nolint:staticcheck // SA1019
conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
if err != nil {
retErr = err
return
}
ctrdClient = &client{
containerService: containersapi.NewContainersClient(conn),
taskService: tasksapi.NewTasksClient(conn),
versionService: versionapi.NewVersionClient(conn),
}
})
return ctrdClient, retErr
}
func (c *client) LoadContainer(ctx context.Context, id string) (*containers.Container, error) {
r, err := c.containerService.Get(ctx, &containersapi.GetContainerRequest{
ID: id,
})
if err != nil {
return nil, errdefs.FromGRPC(err)
}
return containerFromProto(r.Container), nil
}
func (c *client) TaskPid(ctx context.Context, id string) (uint32, error) {
response, err := c.taskService.Get(ctx, &tasksapi.GetRequest{
ContainerID: id,
})
if err != nil {
return 0, errdefs.FromGRPC(err)
}
if response.Process.Status == tasktypes.Status_UNKNOWN {
return 0, ErrTaskIsInUnknownState
}
return response.Process.Pid, nil
}
func (c *client) Version(ctx context.Context) (string, error) {
response, err := c.versionService.Version(ctx, &emptypb.Empty{})
if err != nil {
return "", errdefs.FromGRPC(err)
}
return response.Version, nil
}
func containerFromProto(containerpb *containersapi.Container) *containers.Container {
var runtime containers.RuntimeInfo
// TODO: is nil check required for containerpb
if containerpb.Runtime != nil {
runtime = containers.RuntimeInfo{
Name: containerpb.Runtime.Name,
Options: containerpb.Runtime.Options,
}
}
return &containers.Container{
ID: containerpb.ID,
Labels: containerpb.Labels,
Image: containerpb.Image,
Runtime: runtime,
Spec: containerpb.Spec,
Snapshotter: containerpb.Snapshotter,
SnapshotKey: containerpb.SnapshotKey,
Extensions: containerpb.Extensions,
}
}

View File

@ -0,0 +1,125 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containers
import (
"context"
"time"
"google.golang.org/protobuf/types/known/anypb"
)
// Container represents the set of data pinned by a container. Unless otherwise
// noted, the resources here are considered in use by the container.
//
// The resources specified in this object are used to create tasks from the container.
type Container struct {
// ID uniquely identifies the container in a namespace.
//
// This property is required and cannot be changed after creation.
ID string
// Labels provide metadata extension for a container.
//
// These are optional and fully mutable.
Labels map[string]string
// Image specifies the image reference used for a container.
//
// This property is optional and mutable.
Image string
// Runtime specifies which runtime should be used when launching container
// tasks.
//
// This property is required and immutable.
Runtime RuntimeInfo
// Spec should carry the runtime specification used to implement the
// container.
//
// This field is required but mutable.
Spec *anypb.Any
// SnapshotKey specifies the snapshot key to use for the container's root
// filesystem. When starting a task from this container, a caller should
// look up the mounts from the snapshot service and include those on the
// task create request.
//
// This field is not required but mutable.
SnapshotKey string
// Snapshotter specifies the snapshotter name used for rootfs
//
// This field is not required but immutable.
Snapshotter string
// CreatedAt is the time at which the container was created.
CreatedAt time.Time
// UpdatedAt is the time at which the container was updated.
UpdatedAt time.Time
// Extensions stores client-specified metadata
Extensions map[string]*anypb.Any
}
// RuntimeInfo holds runtime specific information
type RuntimeInfo struct {
Name string
Options *anypb.Any
}
// Store interacts with the underlying container storage
type Store interface {
// Get a container using the id.
//
// Container object is returned on success. If the id is not known to the
// store, an error will be returned.
Get(ctx context.Context, id string) (Container, error)
// List returns containers that match one or more of the provided filters.
List(ctx context.Context, filters ...string) ([]Container, error)
// Create a container in the store from the provided container.
Create(ctx context.Context, container Container) (Container, error)
// Update the container with the provided container object. ID must be set.
//
// If one or more fieldpaths are provided, only the field corresponding to
// the fieldpaths will be mutated.
Update(ctx context.Context, container Container, fieldpaths ...string) (Container, error)
// Delete a container using the id.
//
// nil will be returned on success. If the container is not known to the
// store, ErrNotFound will be returned.
Delete(ctx context.Context, id string) error
}

View File

@ -0,0 +1,157 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package containerd
import (
"flag"
"fmt"
"path"
"regexp"
"strings"
"golang.org/x/net/context"
"k8s.io/klog/v2"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/libcontainer"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/watcher"
)
var ArgContainerdEndpoint = flag.String("containerd", "/run/containerd/containerd.sock", "containerd endpoint")
var ArgContainerdNamespace = flag.String("containerd-namespace", "k8s.io", "containerd namespace")
var containerdEnvMetadataWhiteList = flag.String("containerd_env_metadata_whitelist", "", "DEPRECATED: this flag will be removed, please use `env_metadata_whitelist`. A comma-separated list of environment variable keys matched with specified prefix that needs to be collected for containerd containers")
// The namespace under which containerd aliases are unique.
const k8sContainerdNamespace = "containerd"
// Regexp that identifies containerd cgroups, containers started with
// --cgroup-parent have another prefix than 'containerd'
var containerdCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`)
type containerdFactory struct {
machineInfoFactory info.MachineInfoFactory
client ContainerdClient
version string
// Information about the mounted cgroup subsystems.
cgroupSubsystems map[string]string
// Information about mounted filesystems.
fsInfo fs.FsInfo
includedMetrics container.MetricSet
}
func (f *containerdFactory) String() string {
return k8sContainerdNamespace
}
func (f *containerdFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) {
client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace)
if err != nil {
return
}
containerdMetadataEnvAllowList := strings.Split(*containerdEnvMetadataWhiteList, ",")
// prefer using the unified metadataEnvAllowList
if len(metadataEnvAllowList) != 0 {
containerdMetadataEnvAllowList = metadataEnvAllowList
}
return newContainerdContainerHandler(
client,
name,
f.machineInfoFactory,
f.fsInfo,
f.cgroupSubsystems,
inHostNamespace,
containerdMetadataEnvAllowList,
f.includedMetrics,
)
}
// Returns the containerd ID from the full container name.
func ContainerNameToContainerdID(name string) string {
id := path.Base(name)
if matches := containerdCgroupRegexp.FindStringSubmatch(id); matches != nil {
return matches[1]
}
return id
}
// isContainerName returns true if the cgroup with associated name
// corresponds to a containerd container.
func isContainerName(name string) bool {
// TODO: May be check with HasPrefix ContainerdNamespace
if strings.HasSuffix(name, ".mount") {
return false
}
return containerdCgroupRegexp.MatchString(path.Base(name))
}
// Containerd can handle and accept all containerd created containers
func (f *containerdFactory) CanHandleAndAccept(name string) (bool, bool, error) {
// if the container is not associated with containerd, we can't handle it or accept it.
if !isContainerName(name) {
return false, false, nil
}
// Check if the container is known to containerd and it is running.
id := ContainerNameToContainerdID(name)
// If container and task lookup in containerd fails then we assume
// that the container state is not known to containerd
ctx := context.Background()
_, err := f.client.LoadContainer(ctx, id)
if err != nil {
return false, false, fmt.Errorf("failed to load container: %v", err)
}
return true, true, nil
}
func (f *containerdFactory) DebugInfo() map[string][]string {
return map[string][]string{}
}
// Register root container before running this function!
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
client, err := Client(*ArgContainerdEndpoint, *ArgContainerdNamespace)
if err != nil {
return fmt.Errorf("unable to create containerd client: %v", err)
}
containerdVersion, err := client.Version(context.Background())
if err != nil {
return fmt.Errorf("failed to fetch containerd client version: %v", err)
}
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
}
klog.V(1).Infof("Registering containerd factory")
f := &containerdFactory{
cgroupSubsystems: cgroupSubsystems,
client: client,
fsInfo: fsInfo,
machineInfoFactory: factory,
version: containerdVersion,
includedMetrics: includedMetrics,
}
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
return nil
}

View File

@ -0,0 +1,49 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This code has been taken from containerd repo to avoid large library import
package containerd
import (
"github.com/google/cadvisor/container/containerd/namespaces"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
type namespaceInterceptor struct {
namespace string
}
func (ni namespaceInterceptor) unary(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
_, ok := namespaces.Namespace(ctx)
if !ok {
ctx = namespaces.WithNamespace(ctx, ni.namespace)
}
return invoker(ctx, method, req, reply, cc, opts...)
}
func (ni namespaceInterceptor) stream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
_, ok := namespaces.Namespace(ctx)
if !ok {
ctx = namespaces.WithNamespace(ctx, ni.namespace)
}
return streamer(ctx, desc, cc, method, opts...)
}
func newNSInterceptors(ns string) (grpc.UnaryClientInterceptor, grpc.StreamClientInterceptor) {
ni := namespaceInterceptor{
namespace: ns,
}
return grpc.UnaryClientInterceptor(ni.unary), grpc.StreamClientInterceptor(ni.stream)
}

View File

@ -0,0 +1,250 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Handler for containerd containers.
package containerd
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/containerd/errdefs"
"github.com/opencontainers/runc/libcontainer/cgroups"
specs "github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/net/context"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/common"
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
)
type containerdContainerHandler struct {
machineInfoFactory info.MachineInfoFactory
// Absolute path to the cgroup hierarchies of this container.
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
cgroupPaths map[string]string
fsInfo fs.FsInfo
// Metadata associated with the container.
reference info.ContainerReference
envs map[string]string
labels map[string]string
// Image name used for this container.
image string
// Filesystem handler.
includedMetrics container.MetricSet
libcontainerHandler *containerlibcontainer.Handler
}
var _ container.ContainerHandler = &containerdContainerHandler{}
// newContainerdContainerHandler returns a new container.ContainerHandler
func newContainerdContainerHandler(
client ContainerdClient,
name string,
machineInfoFactory info.MachineInfoFactory,
fsInfo fs.FsInfo,
cgroupSubsystems map[string]string,
inHostNamespace bool,
metadataEnvAllowList []string,
includedMetrics container.MetricSet,
) (container.ContainerHandler, error) {
// Create the cgroup paths.
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name)
// Generate the equivalent cgroup manager for this container.
cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths)
if err != nil {
return nil, err
}
id := ContainerNameToContainerdID(name)
// We assume that if load fails then the container is not known to containerd.
ctx := context.Background()
cntr, err := client.LoadContainer(ctx, id)
if err != nil {
return nil, err
}
var spec specs.Spec
if err := json.Unmarshal(cntr.Spec.Value, &spec); err != nil {
return nil, err
}
// Cgroup is created during task creation. When cadvisor sees the cgroup,
// task may not be fully created yet. Use a retry+backoff to tolerant the
// race condition.
// TODO(random-liu): Use cri-containerd client to talk with cri-containerd
// instead. cri-containerd has some internal synchronization to make sure
// `ContainerStatus` only returns result after `StartContainer` finishes.
var taskPid uint32
backoff := 100 * time.Millisecond
retry := 5
for {
taskPid, err = client.TaskPid(ctx, id)
if err == nil {
break
}
// Retry when task is not created yet or task is in unknown state (likely in process of initializing)
isRetriableError := errdefs.IsNotFound(err) || errors.Is(err, ErrTaskIsInUnknownState)
if !isRetriableError || retry == 0 {
return nil, err
}
retry--
time.Sleep(backoff)
backoff *= 2
}
rootfs := "/"
if !inHostNamespace {
rootfs = "/rootfs"
}
containerReference := info.ContainerReference{
Id: id,
Name: name,
Namespace: k8sContainerdNamespace,
Aliases: []string{id, name},
}
// Containers that don't have their own network -- this includes
// containers running in Kubernetes pods that use the network of the
// infrastructure container -- does not need their stats to be
// reported. This stops metrics being reported multiple times for each
// container in a pod.
metrics := common.RemoveNetMetrics(includedMetrics, cntr.Labels["io.cri-containerd.kind"] != "sandbox")
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootfs, int(taskPid), metrics)
handler := &containerdContainerHandler{
machineInfoFactory: machineInfoFactory,
cgroupPaths: cgroupPaths,
fsInfo: fsInfo,
envs: make(map[string]string),
labels: cntr.Labels,
includedMetrics: metrics,
reference: containerReference,
libcontainerHandler: libcontainerHandler,
}
// Add the name and bare ID as aliases of the container.
handler.image = cntr.Image
for _, exposedEnv := range metadataEnvAllowList {
if exposedEnv == "" {
// if no containerdEnvWhitelist provided, len(metadataEnvAllowList) == 1, metadataEnvAllowList[0] == ""
continue
}
for _, envVar := range spec.Process.Env {
if envVar != "" {
splits := strings.SplitN(envVar, "=", 2)
if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) {
handler.envs[splits[0]] = splits[1]
}
}
}
}
return handler, nil
}
func (h *containerdContainerHandler) ContainerReference() (info.ContainerReference, error) {
return h.reference, nil
}
func (h *containerdContainerHandler) GetSpec() (info.ContainerSpec, error) {
// TODO: Since we dont collect disk usage stats for containerd, we set hasFilesystem
// to false. Revisit when we support disk usage stats for containerd
hasFilesystem := false
hasNet := h.includedMetrics.Has(container.NetworkUsageMetrics)
spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, hasNet, hasFilesystem)
spec.Labels = h.labels
spec.Envs = h.envs
spec.Image = h.image
return spec, err
}
func (h *containerdContainerHandler) getFsStats(stats *info.ContainerStats) error {
mi, err := h.machineInfoFactory.GetMachineInfo()
if err != nil {
return err
}
if h.includedMetrics.Has(container.DiskIOMetrics) {
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
}
return nil
}
func (h *containerdContainerHandler) GetStats() (*info.ContainerStats, error) {
stats, err := h.libcontainerHandler.GetStats()
if err != nil {
return stats, err
}
// Get filesystem stats.
err = h.getFsStats(stats)
return stats, err
}
func (h *containerdContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
return []info.ContainerReference{}, nil
}
func (h *containerdContainerHandler) GetCgroupPath(resource string) (string, error) {
var res string
if !cgroups.IsCgroup2UnifiedMode() {
res = resource
}
path, ok := h.cgroupPaths[res]
if !ok {
return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name)
}
return path, nil
}
func (h *containerdContainerHandler) GetContainerLabels() map[string]string {
return h.labels
}
func (h *containerdContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
return h.libcontainerHandler.GetProcesses()
}
func (h *containerdContainerHandler) Exists() bool {
return common.CgroupExists(h.cgroupPaths)
}
func (h *containerdContainerHandler) Type() container.ContainerType {
return container.ContainerTypeContainerd
}
func (h *containerdContainerHandler) Start() {
}
func (h *containerdContainerHandler) Cleanup() {
}
func (h *containerdContainerHandler) GetContainerIPAddress() string {
// containerd doesnt take care of networking.So it doesnt maintain networking states
return ""
}

View File

@ -0,0 +1,86 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package identifiers provides common validation for identifiers and keys
// across containerd.
//
// Identifiers in containerd must be a alphanumeric, allowing limited
// underscores, dashes and dots.
//
// While the character set may be expanded in the future, identifiers
// are guaranteed to be safely used as filesystem path components.
package identifiers
import (
"regexp"
"github.com/containerd/errdefs"
"github.com/pkg/errors"
)
const (
maxLength = 76
alphanum = `[A-Za-z0-9]+`
separators = `[._-]`
)
var (
// identifierRe defines the pattern for valid identifiers.
identifierRe = regexp.MustCompile(reAnchor(alphanum + reGroup(separators+reGroup(alphanum)) + "*"))
)
// Validate returns nil if the string s is a valid identifier.
//
// identifiers are similar to the domain name rules according to RFC 1035, section 2.3.1. However
// rules in this package are relaxed to allow numerals to follow period (".") and mixed case is
// allowed.
//
// In general identifiers that pass this validation should be safe for use as filesystem path components.
func Validate(s string) error {
if len(s) == 0 {
return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier must not be empty")
}
if len(s) > maxLength {
return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q greater than maximum length (%d characters)", s, maxLength)
}
if !identifierRe.MatchString(s) {
return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q must match %v", s, identifierRe)
}
return nil
}
func reGroup(s string) string {
return `(?:` + s + `)`
}
func reAnchor(s string) string {
return `^` + s + `$`
}

View File

@ -0,0 +1,30 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The install package registers containerd.NewPlugin() as the "containerd" container provider when imported
package install
import (
"k8s.io/klog/v2"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/containerd"
)
func init() {
err := container.RegisterPlugin("containerd", containerd.NewPlugin())
if err != nil {
klog.Fatalf("Failed to register containerd plugin: %v", err)
}
}

View File

@ -0,0 +1,92 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package namespaces
import (
"context"
"os"
"github.com/containerd/errdefs"
"github.com/pkg/errors"
"github.com/google/cadvisor/container/containerd/identifiers"
)
const (
// NamespaceEnvVar is the environment variable key name
NamespaceEnvVar = "CONTAINERD_NAMESPACE"
// Default is the name of the default namespace
Default = "default"
)
type namespaceKey struct{}
// WithNamespace sets a given namespace on the context
func WithNamespace(ctx context.Context, namespace string) context.Context {
ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace
// also store on the grpc and ttrpc headers so it gets picked up by any clients that
// are using this.
return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace)
}
// NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or
// default
func NamespaceFromEnv(ctx context.Context) context.Context {
namespace := os.Getenv(NamespaceEnvVar)
if namespace == "" {
namespace = Default
}
return WithNamespace(ctx, namespace)
}
// Namespace returns the namespace from the context.
//
// The namespace is not guaranteed to be valid.
func Namespace(ctx context.Context) (string, bool) {
namespace, ok := ctx.Value(namespaceKey{}).(string)
if !ok {
if namespace, ok = fromGRPCHeader(ctx); !ok {
return fromTTRPCHeader(ctx)
}
}
return namespace, ok
}
// NamespaceRequired returns the valid namespace from the context or an error.
func NamespaceRequired(ctx context.Context) (string, error) {
namespace, ok := Namespace(ctx)
if !ok || namespace == "" {
return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required")
}
if err := identifiers.Validate(namespace); err != nil {
return "", errors.Wrap(err, "namespace validation")
}
return namespace, nil
}

View File

@ -0,0 +1,74 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package namespaces
import (
"context"
"google.golang.org/grpc/metadata"
)
const (
// GRPCHeader defines the header name for specifying a containerd namespace.
GRPCHeader = "containerd-namespace"
)
// NOTE(stevvooe): We can stub this file out if we don't want a grpc dependency here.
func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
// also store on the grpc headers so it gets picked up by any clients that
// are using this.
nsheader := metadata.Pairs(GRPCHeader, namespace)
md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
if !ok {
md = nsheader
} else {
// order ensures the latest is first in this list.
md = metadata.Join(nsheader, md)
}
return metadata.NewOutgoingContext(ctx, md)
}
func fromGRPCHeader(ctx context.Context) (string, bool) {
// try to extract for use in grpc servers.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
// TODO(stevvooe): Check outgoing context?
return "", false
}
values := md[GRPCHeader]
if len(values) == 0 {
return "", false
}
return values[0], true
}

View File

@ -0,0 +1,57 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package namespaces
import "context"
// Store provides introspection about namespaces.
//
// Note that these are slightly different than other objects, which are record
// oriented. A namespace is really just a name and a set of labels. Objects
// that belong to a namespace are returned when the namespace is assigned to a
// given context.
type Store interface {
Create(ctx context.Context, namespace string, labels map[string]string) error
Labels(ctx context.Context, namespace string) (map[string]string, error)
SetLabel(ctx context.Context, namespace, key, value string) error
List(ctx context.Context) ([]string, error)
// Delete removes the namespace. The namespace must be empty to be deleted.
Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error
}
// DeleteInfo specifies information for the deletion of a namespace
type DeleteInfo struct {
// Name of the namespace
Name string
}
// DeleteOpts allows the caller to set options for namespace deletion
type DeleteOpts func(context.Context, *DeleteInfo) error

View File

@ -0,0 +1,64 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package namespaces
import (
"context"
"github.com/containerd/ttrpc"
)
const (
// TTRPCHeader defines the header name for specifying a containerd namespace
TTRPCHeader = "containerd-namespace-ttrpc"
)
func copyMetadata(src ttrpc.MD) ttrpc.MD {
md := ttrpc.MD{}
for k, v := range src {
md[k] = append(md[k], v...)
}
return md
}
func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
md, ok := ttrpc.GetMetadata(ctx)
if !ok {
md = ttrpc.MD{}
} else {
md = copyMetadata(md)
}
md.Set(TTRPCHeader, namespace)
return ttrpc.WithMetadata(ctx, md)
}
func fromTTRPCHeader(ctx context.Context) (string, bool) {
return ttrpc.GetMetadataValue(ctx, TTRPCHeader)
}

View File

@ -0,0 +1,92 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dialer
import (
"context"
"net"
"time"
"github.com/pkg/errors"
)
type dialResult struct {
c net.Conn
err error
}
// ContextDialer returns a GRPC net.Conn connected to the provided address
func ContextDialer(ctx context.Context, address string) (net.Conn, error) {
if deadline, ok := ctx.Deadline(); ok {
return timeoutDialer(address, time.Until(deadline))
}
return timeoutDialer(address, 0)
}
// Dialer returns a GRPC net.Conn connected to the provided address
// Deprecated: use ContextDialer and grpc.WithContextDialer.
var Dialer = timeoutDialer
func timeoutDialer(address string, timeout time.Duration) (net.Conn, error) {
var (
stopC = make(chan struct{})
synC = make(chan *dialResult)
)
go func() {
defer close(synC)
for {
select {
case <-stopC:
return
default:
c, err := dialer(address, timeout)
if isNoent(err) {
<-time.After(10 * time.Millisecond)
continue
}
synC <- &dialResult{c, err}
return
}
}
}()
select {
case dr := <-synC:
return dr.c, dr.err
case <-time.After(timeout):
close(stopC)
go func() {
dr := <-synC
if dr != nil && dr.c != nil {
dr.c.Close()
}
}()
return nil, errors.Errorf("dial %s: timeout", address)
}
}

View File

@ -0,0 +1,66 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !windows
// +build !windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dialer
import (
"fmt"
"net"
"os"
"strings"
"syscall"
"time"
)
// DialAddress returns the address with unix:// prepended to the
// provided address
func DialAddress(address string) string {
return fmt.Sprintf("unix://%s", address)
}
func isNoent(err error) bool {
if err != nil {
if nerr, ok := err.(*net.OpError); ok {
if serr, ok := nerr.Err.(*os.SyscallError); ok {
if serr.Err == syscall.ENOENT {
return true
}
}
}
}
return false
}
func dialer(address string, timeout time.Duration) (net.Conn, error) {
address = strings.TrimPrefix(address, "unix://")
return net.DialTimeout("unix", address, timeout)
}

View File

@ -0,0 +1,51 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dialer
import (
"net"
"os"
"time"
winio "github.com/Microsoft/go-winio"
)
func isNoent(err error) bool {
return os.IsNotExist(err)
}
func dialer(address string, timeout time.Duration) (net.Conn, error) {
return winio.DialPipe(address, &timeout)
}
// DialAddress returns the dial address
func DialAddress(address string) string {
return address
}

View File

@ -0,0 +1,38 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package containerd
import (
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/watcher"
)
// NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin()
func NewPlugin() container.Plugin {
return &plugin{}
}
type plugin struct{}
func (p *plugin) InitializeFSContext(context *fs.Context) error {
return nil
}
func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) {
err := Register(factory, fsInfo, includedMetrics)
return nil, err
}