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 }