...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/docker/client.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients/docker

     1  // Copyright 2021 Chaos Mesh Authors.
     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  
    16  package docker
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"net/http"
    22  
    23  	"github.com/docker/docker/api/types"
    24  	"github.com/docker/docker/api/types/filters"
    25  	dockerclient "github.com/docker/docker/client"
    26  	"github.com/pkg/errors"
    27  
    28  	"github.com/chaos-mesh/chaos-mesh/pkg/mock"
    29  )
    30  
    31  const (
    32  	dockerProtocolPrefix = "docker://"
    33  
    34  	// containerKindLabel is a label key intending to filter sandbox container
    35  	// ref: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_service.go#L67-L75
    36  	containerKindLabel     = "io.kubernetes.docker.type"
    37  	containerKindContainer = "container"
    38  )
    39  
    40  // DockerClientInterface represents the DockerClient, it's used to simply unit test
    41  type DockerClientInterface interface {
    42  	ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error)
    43  	ContainerKill(ctx context.Context, containerID, signal string) error
    44  	ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error)
    45  }
    46  
    47  // DockerClient can get information from docker
    48  type DockerClient struct {
    49  	client DockerClientInterface
    50  }
    51  
    52  // FormatContainerID strips protocol prefix from the container ID
    53  func (c DockerClient) FormatContainerID(ctx context.Context, containerID string) (string, error) {
    54  	if len(containerID) < len(dockerProtocolPrefix) {
    55  		return "", errors.Errorf("container id %s is not a docker container id", containerID)
    56  	}
    57  	if containerID[0:len(dockerProtocolPrefix)] != dockerProtocolPrefix {
    58  		return "", errors.Errorf("expected %s but got %s", dockerProtocolPrefix, containerID[0:len(dockerProtocolPrefix)])
    59  	}
    60  	return containerID[len(dockerProtocolPrefix):], nil
    61  }
    62  
    63  // GetPidFromContainerID fetches PID according to container id
    64  func (c DockerClient) GetPidFromContainerID(ctx context.Context, containerID string) (uint32, error) {
    65  	id, err := c.FormatContainerID(ctx, containerID)
    66  	if err != nil {
    67  		return 0, err
    68  	}
    69  	container, err := c.client.ContainerInspect(ctx, id)
    70  	if err != nil {
    71  		return 0, err
    72  	}
    73  
    74  	if container.State.Pid == 0 {
    75  		return 0, errors.Errorf("container is not running, status: %s", container.State.Status)
    76  	}
    77  
    78  	return uint32(container.State.Pid), nil
    79  }
    80  
    81  // ContainerKillByContainerID kills container according to container id
    82  func (c DockerClient) ContainerKillByContainerID(ctx context.Context, containerID string) error {
    83  	id, err := c.FormatContainerID(ctx, containerID)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	err = c.client.ContainerKill(ctx, id, "SIGKILL")
    88  
    89  	return err
    90  }
    91  
    92  // ListContainerIDs lists all container IDs
    93  func (c DockerClient) ListContainerIDs(ctx context.Context) ([]string, error) {
    94  	// filter sandbox containers
    95  	filterArg := filters.Arg("label", fmt.Sprintf("%s=%s", containerKindLabel, containerKindContainer))
    96  	containers, err := c.client.ContainerList(ctx, types.ContainerListOptions{
    97  		Filters: filters.NewArgs(filterArg),
    98  	})
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	var ids []string
   104  	for _, container := range containers {
   105  		id := fmt.Sprintf("%s%s", dockerProtocolPrefix, container.ID)
   106  		ids = append(ids, id)
   107  	}
   108  	return ids, nil
   109  }
   110  
   111  // GetLabelsFromContainerID returns the labels according to container ID
   112  func (c DockerClient) GetLabelsFromContainerID(ctx context.Context, containerID string) (map[string]string, error) {
   113  	id, err := c.FormatContainerID(ctx, containerID)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	container, err := c.client.ContainerInspect(ctx, id)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	return container.Config.Labels, nil
   123  }
   124  
   125  func New(host string, version string, client *http.Client, httpHeaders map[string]string) (*DockerClient, error) {
   126  	// Mock point to return error or mock client in unit test
   127  	if err := mock.On("NewDockerClientError"); err != nil {
   128  		return nil, err.(error)
   129  	}
   130  	if client := mock.On("MockDockerClient"); client != nil {
   131  		return &DockerClient{
   132  			client: client.(DockerClientInterface),
   133  		}, nil
   134  	}
   135  
   136  	c, err := dockerclient.NewClientWithOpts(
   137  		dockerclient.FromEnv,
   138  		dockerclient.WithHost(host),
   139  		dockerclient.WithVersion(version),
   140  		dockerclient.WithHTTPClient(client),
   141  		dockerclient.WithHTTPHeaders(httpHeaders))
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	// The real logic
   146  	return &DockerClient{
   147  		client: c,
   148  	}, nil
   149  }
   150