github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/helper/containercenter/cri_runtime_api_interface.go (about)

     1  // Copyright 2025 iLogtail 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  package containercenter
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/alibaba/ilogtail/pkg/logger"
    23  
    24  	"google.golang.org/grpc"
    25  )
    26  
    27  type CriContainerState int32
    28  
    29  const (
    30  	ContainerStateContainerCreated CriContainerState = 0
    31  	ContainerStateContainerRunning CriContainerState = 1
    32  	ContainerStateContainerExited  CriContainerState = 2
    33  	ContainerStateContainerUnknown CriContainerState = 3
    34  )
    35  
    36  type CriMountPropagation int32
    37  
    38  const (
    39  	MountPropagationPropagationPrivate         CriMountPropagation = 0
    40  	MountPropagationPropagationHostToContainer CriMountPropagation = 1
    41  	MountPropagationPropagationBidirectional   CriMountPropagation = 2
    42  )
    43  
    44  type CriVersionInfo struct {
    45  	Version           string
    46  	RuntimeName       string
    47  	RuntimeVersion    string
    48  	RuntimeAPIVersion string
    49  }
    50  
    51  type CriVersionResponse struct {
    52  	Version           string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
    53  	RuntimeName       string `protobuf:"bytes,2,opt,name=runtime_name,proto3" json:"runtime_name,omitempty"`
    54  	RuntimeVersion    string `protobuf:"bytes,3,opt,name=runtime_version,proto3" json:"runtime_version,omitempty"`
    55  	RuntimeAPIVersion string `protobuf:"bytes,4,opt,name=runtime_api_version,proto3" json:"runtime_api_version,omitempty"`
    56  }
    57  
    58  type CriContainerMetadata struct {
    59  	Name    string
    60  	Attempt uint32
    61  }
    62  
    63  type CriImageSpec struct {
    64  	Image       string
    65  	Annotations map[string]string
    66  }
    67  
    68  type CriContainer struct {
    69  	ID           string
    70  	PodSandboxID string
    71  	Metadata     *CriContainerMetadata
    72  	Image        *CriImageSpec
    73  	ImageRef     string
    74  	State        CriContainerState
    75  	CreatedAt    int64
    76  	Labels       map[string]string
    77  	Annotations  map[string]string
    78  }
    79  
    80  type CriListContainersResponse struct {
    81  	Containers []*CriContainer
    82  }
    83  
    84  type CriMount struct {
    85  	ContainerPath  string
    86  	HostPath       string
    87  	Readonly       bool
    88  	SelinuxRelabel bool
    89  	Propagation    CriMountPropagation
    90  }
    91  
    92  type CriContainerStatus struct {
    93  	ID          string
    94  	Metadata    *CriContainerMetadata
    95  	State       CriContainerState
    96  	CreatedAt   int64
    97  	StartedAt   int64
    98  	FinishedAt  int64
    99  	ExitCode    int32
   100  	Image       *CriImageSpec
   101  	ImageRef    string
   102  	Reason      string
   103  	Message     string
   104  	Labels      map[string]string
   105  	Annotations map[string]string
   106  	Mounts      []*CriMount
   107  	LogPath     string
   108  }
   109  
   110  type CriContainerStatusResponse struct {
   111  	Status *CriContainerStatus
   112  	Info   map[string]string
   113  }
   114  
   115  type CriPodSandboxMetadata struct {
   116  	Name      string
   117  	UID       string
   118  	Namespace string
   119  	Attempt   uint32
   120  }
   121  
   122  type CriPodSandbox struct {
   123  	ID             string
   124  	Metadata       *CriPodSandboxMetadata
   125  	State          CriContainerState
   126  	CreatedAt      int64
   127  	Labels         map[string]string
   128  	Annotations    map[string]string
   129  	RuntimeHandler string
   130  }
   131  
   132  type CriListPodSandboxResponse struct {
   133  	Items []*CriPodSandbox
   134  }
   135  
   136  type CriPodSandboxStatus struct {
   137  	ID             string
   138  	Metadata       *CriPodSandboxMetadata
   139  	State          CriContainerState
   140  	CreatedAt      int64
   141  	Labels         map[string]string
   142  	Annotations    map[string]string
   143  	RuntimeHandler string
   144  }
   145  
   146  type CriPodSandboxStatusResponse struct {
   147  	Status *CriPodSandboxStatus
   148  	Info   map[string]string
   149  }
   150  
   151  type RuntimeService interface {
   152  	Version(ctx context.Context) (*CriVersionResponse, error)
   153  	ListContainers(ctx context.Context) (*CriListContainersResponse, error)
   154  	ContainerStatus(ctx context.Context, containerID string, verbose bool) (*CriContainerStatusResponse, error)
   155  	ListPodSandbox(ctx context.Context) (*CriListPodSandboxResponse, error)
   156  	PodSandboxStatus(ctx context.Context, sandboxID string, verbose bool) (*CriPodSandboxStatusResponse, error)
   157  }
   158  
   159  type RuntimeServiceClient struct {
   160  	service RuntimeService
   161  	info    CriVersionInfo
   162  	conn    *grpc.ClientConn
   163  }
   164  
   165  var ( // for mock
   166  	getAddressAndDialer = GetAddressAndDialer
   167  	grpcDialContext     = grpc.DialContext
   168  )
   169  
   170  func NewRuntimeServiceClient(contextTimeout time.Duration, grpcMaxCallRecvMsgSize int) (*RuntimeServiceClient, error) {
   171  	addr, dailer, err := getAddressAndDialer(containerdUnixSocket)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  	ctx, cancel := getContextWithTimeout(contextTimeout)
   176  	defer cancel()
   177  
   178  	conn, err := grpcDialContext(ctx, addr, grpc.WithInsecure(), grpc.WithDialer(dailer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(grpcMaxCallRecvMsgSize)))
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	client := &RuntimeServiceClient{
   184  		conn: conn,
   185  	}
   186  	// Try v1 first
   187  	client.service = newCRIRuntimeServiceV1Adapter(conn)
   188  	if client.getVersion(ctx) == nil {
   189  		logger.Info(ctx, "Init cri client v1 success, cri info", client.info)
   190  		return client, nil
   191  	}
   192  
   193  	// Fallback to v1alpha2
   194  	client.service = newCRIRuntimeServiceV1Alpha2Adapter(conn)
   195  	if client.getVersion(ctx) == nil {
   196  		logger.Info(ctx, "Init cri client v1alpha2 success, cri info", client.info)
   197  		return client, nil
   198  	}
   199  
   200  	// if create client failed, close the connection
   201  	_ = conn.Close()
   202  	return nil, fmt.Errorf("failed to initialize RuntimeServiceClient")
   203  }
   204  
   205  func (c *RuntimeServiceClient) Version(ctx context.Context) (*CriVersionResponse, error) {
   206  	if c.service != nil {
   207  		return c.service.Version(ctx)
   208  	}
   209  	return &CriVersionResponse{}, fmt.Errorf("invalid RuntimeServiceClient")
   210  }
   211  
   212  func (c *RuntimeServiceClient) ListContainers(ctx context.Context) (*CriListContainersResponse, error) {
   213  	if c.service != nil {
   214  		return c.service.ListContainers(ctx)
   215  	}
   216  	return &CriListContainersResponse{}, fmt.Errorf("invalid RuntimeServiceClient")
   217  }
   218  
   219  func (c *RuntimeServiceClient) ContainerStatus(ctx context.Context, containerID string, verbose bool) (*CriContainerStatusResponse, error) {
   220  	if c.service != nil {
   221  		return c.service.ContainerStatus(ctx, containerID, verbose)
   222  	}
   223  	return &CriContainerStatusResponse{}, fmt.Errorf("invalid RuntimeServiceClient")
   224  }
   225  
   226  func (c *RuntimeServiceClient) ListPodSandbox(ctx context.Context) (*CriListPodSandboxResponse, error) {
   227  	if c.service != nil {
   228  		return c.service.ListPodSandbox(ctx)
   229  	}
   230  	return &CriListPodSandboxResponse{}, fmt.Errorf("invalid RuntimeServiceClient")
   231  }
   232  
   233  func (c *RuntimeServiceClient) PodSandboxStatus(ctx context.Context, sandboxID string, verbose bool) (*CriPodSandboxStatusResponse, error) {
   234  	if c.service != nil {
   235  		return c.service.PodSandboxStatus(ctx, sandboxID, verbose)
   236  	}
   237  	return &CriPodSandboxStatusResponse{}, fmt.Errorf("invalid RuntimeServiceClient")
   238  }
   239  
   240  func (c *RuntimeServiceClient) getVersion(ctx context.Context) error {
   241  	versionResp, err := c.service.Version(ctx)
   242  	if err == nil {
   243  		c.info = CriVersionInfo{
   244  			versionResp.Version,
   245  			versionResp.RuntimeName,
   246  			versionResp.RuntimeVersion,
   247  			versionResp.RuntimeAPIVersion,
   248  		}
   249  	}
   250  	return err
   251  }
   252  
   253  func (c *RuntimeServiceClient) Close() {
   254  	if c.conn != nil {
   255  		_ = c.conn.Close()
   256  	}
   257  }