github.com/google/cadvisor@v0.49.1/container/containerd/client.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package containerd
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"net"
    22  	"sync"
    23  	"time"
    24  
    25  	ptypes "github.com/gogo/protobuf/types"
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/backoff"
    28  	"google.golang.org/grpc/credentials/insecure"
    29  
    30  	"github.com/google/cadvisor/container/containerd/containers"
    31  	"github.com/google/cadvisor/container/containerd/errdefs"
    32  	"github.com/google/cadvisor/container/containerd/pkg/dialer"
    33  	containersapi "github.com/google/cadvisor/third_party/containerd/api/services/containers/v1"
    34  	tasksapi "github.com/google/cadvisor/third_party/containerd/api/services/tasks/v1"
    35  	versionapi "github.com/google/cadvisor/third_party/containerd/api/services/version/v1"
    36  	tasktypes "github.com/google/cadvisor/third_party/containerd/api/types/task"
    37  )
    38  
    39  type client struct {
    40  	containerService containersapi.ContainersClient
    41  	taskService      tasksapi.TasksClient
    42  	versionService   versionapi.VersionClient
    43  }
    44  
    45  type ContainerdClient interface {
    46  	LoadContainer(ctx context.Context, id string) (*containers.Container, error)
    47  	TaskPid(ctx context.Context, id string) (uint32, error)
    48  	Version(ctx context.Context) (string, error)
    49  }
    50  
    51  var (
    52  	ErrTaskIsInUnknownState = errors.New("containerd task is in unknown state") // used when process reported in containerd task is in Unknown State
    53  )
    54  
    55  var once sync.Once
    56  var ctrdClient ContainerdClient = nil
    57  
    58  const (
    59  	maxBackoffDelay   = 3 * time.Second
    60  	baseBackoffDelay  = 100 * time.Millisecond
    61  	connectionTimeout = 2 * time.Second
    62  	maxMsgSize        = 16 * 1024 * 1024 // 16MB
    63  )
    64  
    65  // Client creates a containerd client
    66  func Client(address, namespace string) (ContainerdClient, error) {
    67  	var retErr error
    68  	once.Do(func() {
    69  		tryConn, err := net.DialTimeout("unix", address, connectionTimeout)
    70  		if err != nil {
    71  			retErr = fmt.Errorf("containerd: cannot unix dial containerd api service: %v", err)
    72  			return
    73  		}
    74  		tryConn.Close()
    75  
    76  		connParams := grpc.ConnectParams{
    77  			Backoff: backoff.DefaultConfig,
    78  		}
    79  		connParams.Backoff.BaseDelay = baseBackoffDelay
    80  		connParams.Backoff.MaxDelay = maxBackoffDelay
    81  		gopts := []grpc.DialOption{
    82  			grpc.WithTransportCredentials(insecure.NewCredentials()),
    83  			grpc.WithContextDialer(dialer.ContextDialer),
    84  			grpc.WithBlock(),
    85  			grpc.WithConnectParams(connParams),
    86  			grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)),
    87  		}
    88  		unary, stream := newNSInterceptors(namespace)
    89  		gopts = append(gopts,
    90  			grpc.WithUnaryInterceptor(unary),
    91  			grpc.WithStreamInterceptor(stream),
    92  		)
    93  
    94  		ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout)
    95  		defer cancel()
    96  		conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...)
    97  		if err != nil {
    98  			retErr = err
    99  			return
   100  		}
   101  		ctrdClient = &client{
   102  			containerService: containersapi.NewContainersClient(conn),
   103  			taskService:      tasksapi.NewTasksClient(conn),
   104  			versionService:   versionapi.NewVersionClient(conn),
   105  		}
   106  	})
   107  	return ctrdClient, retErr
   108  }
   109  
   110  func (c *client) LoadContainer(ctx context.Context, id string) (*containers.Container, error) {
   111  	r, err := c.containerService.Get(ctx, &containersapi.GetContainerRequest{
   112  		ID: id,
   113  	})
   114  	if err != nil {
   115  		return nil, errdefs.FromGRPC(err)
   116  	}
   117  	return containerFromProto(r.Container), nil
   118  }
   119  
   120  func (c *client) TaskPid(ctx context.Context, id string) (uint32, error) {
   121  	response, err := c.taskService.Get(ctx, &tasksapi.GetRequest{
   122  		ContainerID: id,
   123  	})
   124  	if err != nil {
   125  		return 0, errdefs.FromGRPC(err)
   126  	}
   127  	if response.Process.Status == tasktypes.StatusUnknown {
   128  		return 0, ErrTaskIsInUnknownState
   129  	}
   130  	return response.Process.Pid, nil
   131  }
   132  
   133  func (c *client) Version(ctx context.Context) (string, error) {
   134  	response, err := c.versionService.Version(ctx, &ptypes.Empty{})
   135  	if err != nil {
   136  		return "", errdefs.FromGRPC(err)
   137  	}
   138  	return response.Version, nil
   139  }
   140  
   141  func containerFromProto(containerpb containersapi.Container) *containers.Container {
   142  	var runtime containers.RuntimeInfo
   143  	if containerpb.Runtime != nil {
   144  		runtime = containers.RuntimeInfo{
   145  			Name:    containerpb.Runtime.Name,
   146  			Options: containerpb.Runtime.Options,
   147  		}
   148  	}
   149  	return &containers.Container{
   150  		ID:          containerpb.ID,
   151  		Labels:      containerpb.Labels,
   152  		Image:       containerpb.Image,
   153  		Runtime:     runtime,
   154  		Spec:        containerpb.Spec,
   155  		Snapshotter: containerpb.Snapshotter,
   156  		SnapshotKey: containerpb.SnapshotKey,
   157  		Extensions:  containerpb.Extensions,
   158  	}
   159  }