github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/api/handlers/types.go (about)

     1  package handlers
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/containers/image/v5/manifest"
    12  	"github.com/containers/libpod/libpod"
    13  	"github.com/containers/libpod/libpod/define"
    14  	"github.com/containers/libpod/libpod/events"
    15  	libpodImage "github.com/containers/libpod/libpod/image"
    16  	"github.com/containers/libpod/pkg/domain/entities"
    17  	docker "github.com/docker/docker/api/types"
    18  	dockerContainer "github.com/docker/docker/api/types/container"
    19  	dockerEvents "github.com/docker/docker/api/types/events"
    20  	dockerNetwork "github.com/docker/docker/api/types/network"
    21  	"github.com/docker/go-connections/nat"
    22  	"github.com/pkg/errors"
    23  )
    24  
    25  type AuthConfig struct {
    26  	docker.AuthConfig
    27  }
    28  
    29  type ImageInspect struct {
    30  	docker.ImageInspect
    31  }
    32  
    33  type ContainerConfig struct {
    34  	dockerContainer.Config
    35  }
    36  
    37  type LibpodImagesLoadReport struct {
    38  	ID string `json:"id"`
    39  }
    40  
    41  type LibpodImagesPullReport struct {
    42  	ID string `json:"id"`
    43  }
    44  
    45  type ContainersPruneReport struct {
    46  	docker.ContainersPruneReport
    47  }
    48  
    49  type LibpodContainersPruneReport struct {
    50  	ID             string `json:"id"`
    51  	SpaceReclaimed int64  `json:"space"`
    52  	PruneError     string `json:"error"`
    53  }
    54  
    55  type Info struct {
    56  	docker.Info
    57  	BuildahVersion     string
    58  	CPURealtimePeriod  bool
    59  	CPURealtimeRuntime bool
    60  	CgroupVersion      string
    61  	Rootless           bool
    62  	SwapFree           int64
    63  	SwapTotal          int64
    64  	Uptime             string
    65  }
    66  
    67  type Container struct {
    68  	docker.Container
    69  	docker.ContainerCreateConfig
    70  }
    71  
    72  type Version struct {
    73  	docker.Version
    74  }
    75  
    76  type DiskUsage struct {
    77  	docker.DiskUsage
    78  }
    79  
    80  type VolumesPruneReport struct {
    81  	docker.VolumesPruneReport
    82  }
    83  
    84  type ImagesPruneReport struct {
    85  	docker.ImagesPruneReport
    86  }
    87  
    88  type BuildCachePruneReport struct {
    89  	docker.BuildCachePruneReport
    90  }
    91  
    92  type NetworkPruneReport struct {
    93  	docker.NetworksPruneReport
    94  }
    95  
    96  type ConfigCreateResponse struct {
    97  	docker.ConfigCreateResponse
    98  }
    99  
   100  type PushResult struct {
   101  	docker.PushResult
   102  }
   103  
   104  type BuildResult struct {
   105  	docker.BuildResult
   106  }
   107  
   108  type ContainerWaitOKBody struct {
   109  	StatusCode int
   110  	Error      struct {
   111  		Message string
   112  	}
   113  }
   114  
   115  type CreateContainerConfig struct {
   116  	Name string
   117  	dockerContainer.Config
   118  	HostConfig       dockerContainer.HostConfig
   119  	NetworkingConfig dockerNetwork.NetworkingConfig
   120  }
   121  
   122  // swagger:model IDResponse
   123  type IDResponse struct {
   124  	// ID
   125  	ID string `json:"id"`
   126  }
   127  
   128  type ContainerTopOKBody struct {
   129  	dockerContainer.ContainerTopOKBody
   130  }
   131  
   132  type PodTopOKBody struct {
   133  	dockerContainer.ContainerTopOKBody
   134  }
   135  
   136  // swagger:model PodCreateConfig
   137  type PodCreateConfig struct {
   138  	Name         string   `json:"name"`
   139  	CGroupParent string   `json:"cgroup-parent"`
   140  	Hostname     string   `json:"hostname"`
   141  	Infra        bool     `json:"infra"`
   142  	InfraCommand string   `json:"infra-command"`
   143  	InfraImage   string   `json:"infra-image"`
   144  	Labels       []string `json:"labels"`
   145  	Publish      []string `json:"publish"`
   146  	Share        string   `json:"share"`
   147  }
   148  
   149  type ErrorModel struct {
   150  	Message string `json:"message"`
   151  }
   152  
   153  type Event struct {
   154  	dockerEvents.Message
   155  }
   156  
   157  type HistoryResponse struct {
   158  	ID        string   `json:"Id"`
   159  	Created   int64    `json:"Created"`
   160  	CreatedBy string   `json:"CreatedBy"`
   161  	Tags      []string `json:"Tags"`
   162  	Size      int64    `json:"Size"`
   163  	Comment   string   `json:"Comment"`
   164  }
   165  
   166  type ImageLayer struct{}
   167  
   168  type ImageTreeResponse struct {
   169  	ID     string       `json:"id"`
   170  	Tags   []string     `json:"tags"`
   171  	Size   string       `json:"size"`
   172  	Layers []ImageLayer `json:"layers"`
   173  }
   174  
   175  type ExecCreateConfig struct {
   176  	docker.ExecConfig
   177  }
   178  
   179  type ExecCreateResponse struct {
   180  	docker.IDResponse
   181  }
   182  
   183  func EventToApiEvent(e *events.Event) *Event {
   184  	return &Event{dockerEvents.Message{
   185  		Type:   e.Type.String(),
   186  		Action: e.Status.String(),
   187  		Actor: dockerEvents.Actor{
   188  			ID: e.ID,
   189  			Attributes: map[string]string{
   190  				"image":             e.Image,
   191  				"name":              e.Name,
   192  				"containerExitCode": strconv.Itoa(e.ContainerExitCode),
   193  			},
   194  		},
   195  		Scope:    "local",
   196  		Time:     e.Time.Unix(),
   197  		TimeNano: e.Time.UnixNano(),
   198  	}}
   199  }
   200  
   201  func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
   202  	containers, err := l.Containers()
   203  	if err != nil {
   204  		return nil, errors.Wrapf(err, "Failed to obtain Containers for image %s", l.ID())
   205  	}
   206  	containerCount := len(containers)
   207  
   208  	// FIXME: GetParent() panics
   209  	// parent, err := l.GetParent(context.TODO())
   210  	// if err != nil {
   211  	// 	return nil, errors.Wrapf(err, "Failed to obtain ParentID for image %s", l.ID())
   212  	// }
   213  
   214  	labels, err := l.Labels(context.TODO())
   215  	if err != nil {
   216  		return nil, errors.Wrapf(err, "Failed to obtain Labels for image %s", l.ID())
   217  	}
   218  
   219  	size, err := l.Size(context.TODO())
   220  	if err != nil {
   221  		return nil, errors.Wrapf(err, "Failed to obtain Size for image %s", l.ID())
   222  	}
   223  
   224  	repoTags, err := l.RepoTags()
   225  	if err != nil {
   226  		return nil, errors.Wrapf(err, "Failed to obtain RepoTags for image %s", l.ID())
   227  	}
   228  
   229  	history, err := l.History(context.TODO())
   230  	if err != nil {
   231  		return nil, errors.Wrapf(err, "Failed to obtain History for image %s", l.ID())
   232  	}
   233  	historyIds := make([]string, len(history))
   234  	for i, h := range history {
   235  		historyIds[i] = h.ID
   236  	}
   237  
   238  	digests := make([]string, len(l.Digests()))
   239  	for i, d := range l.Digests() {
   240  		digests[i] = string(d)
   241  	}
   242  
   243  	is := entities.ImageSummary{
   244  		ID:           l.ID(),
   245  		ParentId:     l.Parent,
   246  		RepoTags:     repoTags,
   247  		Created:      l.Created().Unix(),
   248  		Size:         int64(*size),
   249  		SharedSize:   0,
   250  		VirtualSize:  l.VirtualSize,
   251  		Labels:       labels,
   252  		Containers:   containerCount,
   253  		ReadOnly:     l.IsReadOnly(),
   254  		Dangling:     l.Dangling(),
   255  		Names:        l.Names(),
   256  		Digest:       string(l.Digest()),
   257  		Digests:      digests,
   258  		ConfigDigest: string(l.ConfigDigest),
   259  		History:      historyIds,
   260  	}
   261  	return &is, nil
   262  }
   263  
   264  func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageInspect, error) {
   265  	info, err := l.Inspect(context.Background())
   266  	if err != nil {
   267  		return nil, err
   268  	}
   269  	ports, err := portsToPortSet(info.Config.ExposedPorts)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	// TODO the rest of these still need wiring!
   274  	config := dockerContainer.Config{
   275  		//	Hostname:        "",
   276  		//	Domainname:      "",
   277  		User: info.User,
   278  		//	AttachStdin:     false,
   279  		//	AttachStdout:    false,
   280  		//	AttachStderr:    false,
   281  		ExposedPorts: ports,
   282  		//	Tty:             false,
   283  		//	OpenStdin:       false,
   284  		//	StdinOnce:       false,
   285  		Env: info.Config.Env,
   286  		Cmd: info.Config.Cmd,
   287  		//	Healthcheck:     nil,
   288  		//	ArgsEscaped:     false,
   289  		//	Image:           "",
   290  		//	Volumes:         nil,
   291  		//	WorkingDir:      "",
   292  		//	Entrypoint:      nil,
   293  		//	NetworkDisabled: false,
   294  		//	MacAddress:      "",
   295  		//	OnBuild:         nil,
   296  		//	Labels:          nil,
   297  		//	StopSignal:      "",
   298  		//	StopTimeout:     nil,
   299  		//	Shell:           nil,
   300  	}
   301  	ic, err := l.ToImageRef(ctx)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	dockerImageInspect := docker.ImageInspect{
   306  		Architecture:  l.Architecture,
   307  		Author:        l.Author,
   308  		Comment:       info.Comment,
   309  		Config:        &config,
   310  		Created:       l.Created().Format(time.RFC3339Nano),
   311  		DockerVersion: "",
   312  		GraphDriver:   docker.GraphDriverData{},
   313  		ID:            fmt.Sprintf("sha256:%s", l.ID()),
   314  		Metadata:      docker.ImageMetadata{},
   315  		Os:            l.Os,
   316  		OsVersion:     l.Version,
   317  		Parent:        l.Parent,
   318  		RepoDigests:   info.RepoDigests,
   319  		RepoTags:      info.RepoTags,
   320  		RootFS:        docker.RootFS{},
   321  		Size:          info.Size,
   322  		Variant:       "",
   323  		VirtualSize:   info.VirtualSize,
   324  	}
   325  	bi := ic.ConfigInfo()
   326  	// For docker images, we need to get the Container id and config
   327  	// and populate the image with it.
   328  	if bi.MediaType == manifest.DockerV2Schema2ConfigMediaType {
   329  		d := manifest.Schema2Image{}
   330  		b, err := ic.ConfigBlob(ctx)
   331  		if err != nil {
   332  			return nil, err
   333  		}
   334  		if err := json.Unmarshal(b, &d); err != nil {
   335  			return nil, err
   336  		}
   337  		// populate the Container id into the image
   338  		dockerImageInspect.Container = d.Container
   339  		containerConfig := dockerContainer.Config{}
   340  		configBytes, err := json.Marshal(d.ContainerConfig)
   341  		if err != nil {
   342  			return nil, err
   343  		}
   344  		if err := json.Unmarshal(configBytes, &containerConfig); err != nil {
   345  			return nil, err
   346  		}
   347  		// populate the Container config in the image
   348  		dockerImageInspect.ContainerConfig = &containerConfig
   349  		// populate parent
   350  		dockerImageInspect.Parent = d.Parent.String()
   351  	}
   352  	return &ImageInspect{dockerImageInspect}, nil
   353  
   354  }
   355  
   356  func LibpodToContainer(l *libpod.Container, sz bool) (*Container, error) {
   357  	imageId, imageName := l.Image()
   358  
   359  	var (
   360  		err        error
   361  		sizeRootFs int64
   362  		sizeRW     int64
   363  		state      define.ContainerStatus
   364  	)
   365  
   366  	if state, err = l.State(); err != nil {
   367  		return nil, err
   368  	}
   369  	stateStr := state.String()
   370  	if stateStr == "configured" {
   371  		stateStr = "created"
   372  	}
   373  
   374  	if sz {
   375  		if sizeRW, err = l.RWSize(); err != nil {
   376  			return nil, err
   377  		}
   378  		if sizeRootFs, err = l.RootFsSize(); err != nil {
   379  			return nil, err
   380  		}
   381  	}
   382  
   383  	return &Container{docker.Container{
   384  		ID:         l.ID(),
   385  		Names:      []string{fmt.Sprintf("/%s", l.Name())},
   386  		Image:      imageName,
   387  		ImageID:    imageId,
   388  		Command:    strings.Join(l.Command(), " "),
   389  		Created:    l.CreatedTime().Unix(),
   390  		Ports:      nil,
   391  		SizeRw:     sizeRW,
   392  		SizeRootFs: sizeRootFs,
   393  		Labels:     l.Labels(),
   394  		State:      stateStr,
   395  		Status:     "",
   396  		HostConfig: struct {
   397  			NetworkMode string `json:",omitempty"`
   398  		}{
   399  			"host"},
   400  		NetworkSettings: nil,
   401  		Mounts:          nil,
   402  	},
   403  		docker.ContainerCreateConfig{},
   404  	}, nil
   405  }
   406  
   407  func LibpodToContainerJSON(l *libpod.Container, sz bool) (*docker.ContainerJSON, error) {
   408  	_, imageName := l.Image()
   409  	inspect, err := l.Inspect(sz)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  	i, err := json.Marshal(inspect.State)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  	state := docker.ContainerState{}
   418  	if err := json.Unmarshal(i, &state); err != nil {
   419  		return nil, err
   420  	}
   421  
   422  	// docker considers paused to be running
   423  	if state.Paused {
   424  		state.Running = true
   425  	}
   426  
   427  	h, err := json.Marshal(inspect.HostConfig)
   428  	if err != nil {
   429  		return nil, err
   430  	}
   431  	hc := dockerContainer.HostConfig{}
   432  	if err := json.Unmarshal(h, &hc); err != nil {
   433  		return nil, err
   434  	}
   435  	g, err := json.Marshal(inspect.GraphDriver)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  	graphDriver := docker.GraphDriverData{}
   440  	if err := json.Unmarshal(g, &graphDriver); err != nil {
   441  		return nil, err
   442  	}
   443  
   444  	cb := docker.ContainerJSONBase{
   445  		ID:              l.ID(),
   446  		Created:         l.CreatedTime().String(),
   447  		Path:            "",
   448  		Args:            nil,
   449  		State:           &state,
   450  		Image:           imageName,
   451  		ResolvConfPath:  inspect.ResolvConfPath,
   452  		HostnamePath:    inspect.HostnamePath,
   453  		HostsPath:       inspect.HostsPath,
   454  		LogPath:         l.LogPath(),
   455  		Node:            nil,
   456  		Name:            fmt.Sprintf("/%s", l.Name()),
   457  		RestartCount:    0,
   458  		Driver:          inspect.Driver,
   459  		Platform:        "linux",
   460  		MountLabel:      inspect.MountLabel,
   461  		ProcessLabel:    inspect.ProcessLabel,
   462  		AppArmorProfile: inspect.AppArmorProfile,
   463  		ExecIDs:         inspect.ExecIDs,
   464  		HostConfig:      &hc,
   465  		GraphDriver:     graphDriver,
   466  		SizeRw:          inspect.SizeRw,
   467  		SizeRootFs:      &inspect.SizeRootFs,
   468  	}
   469  
   470  	stopTimeout := int(l.StopTimeout())
   471  
   472  	ports := make(nat.PortSet)
   473  	for p := range inspect.HostConfig.PortBindings {
   474  		splitp := strings.Split(p, "/")
   475  		port, err := nat.NewPort(splitp[0], splitp[1])
   476  		if err != nil {
   477  			return nil, err
   478  		}
   479  		ports[port] = struct{}{}
   480  	}
   481  
   482  	config := dockerContainer.Config{
   483  		Hostname:        l.Hostname(),
   484  		Domainname:      inspect.Config.DomainName,
   485  		User:            l.User(),
   486  		AttachStdin:     inspect.Config.AttachStdin,
   487  		AttachStdout:    inspect.Config.AttachStdout,
   488  		AttachStderr:    inspect.Config.AttachStderr,
   489  		ExposedPorts:    ports,
   490  		Tty:             inspect.Config.Tty,
   491  		OpenStdin:       inspect.Config.OpenStdin,
   492  		StdinOnce:       inspect.Config.StdinOnce,
   493  		Env:             inspect.Config.Env,
   494  		Cmd:             inspect.Config.Cmd,
   495  		Healthcheck:     nil,
   496  		ArgsEscaped:     false,
   497  		Image:           imageName,
   498  		Volumes:         nil,
   499  		WorkingDir:      l.WorkingDir(),
   500  		Entrypoint:      l.Entrypoint(),
   501  		NetworkDisabled: false,
   502  		MacAddress:      "",
   503  		OnBuild:         nil,
   504  		Labels:          l.Labels(),
   505  		StopSignal:      string(l.StopSignal()),
   506  		StopTimeout:     &stopTimeout,
   507  		Shell:           nil,
   508  	}
   509  
   510  	m, err := json.Marshal(inspect.Mounts)
   511  	if err != nil {
   512  		return nil, err
   513  	}
   514  	mounts := []docker.MountPoint{}
   515  	if err := json.Unmarshal(m, &mounts); err != nil {
   516  		return nil, err
   517  	}
   518  
   519  	networkSettingsDefault := docker.DefaultNetworkSettings{
   520  		EndpointID:          "",
   521  		Gateway:             "",
   522  		GlobalIPv6Address:   "",
   523  		GlobalIPv6PrefixLen: 0,
   524  		IPAddress:           "",
   525  		IPPrefixLen:         0,
   526  		IPv6Gateway:         "",
   527  		MacAddress:          l.Config().StaticMAC.String(),
   528  	}
   529  
   530  	networkSettings := docker.NetworkSettings{
   531  		NetworkSettingsBase:    docker.NetworkSettingsBase{},
   532  		DefaultNetworkSettings: networkSettingsDefault,
   533  		Networks:               nil,
   534  	}
   535  
   536  	c := docker.ContainerJSON{
   537  		ContainerJSONBase: &cb,
   538  		Mounts:            mounts,
   539  		Config:            &config,
   540  		NetworkSettings:   &networkSettings,
   541  	}
   542  	return &c, nil
   543  }
   544  
   545  // portsToPortSet converts libpods exposed ports to dockers structs
   546  func portsToPortSet(input map[string]struct{}) (nat.PortSet, error) {
   547  	ports := make(nat.PortSet)
   548  	for k := range input {
   549  		npTCP, err := nat.NewPort("tcp", k)
   550  		if err != nil {
   551  			return nil, errors.Wrapf(err, "unable to create tcp port from %s", k)
   552  		}
   553  		npUDP, err := nat.NewPort("udp", k)
   554  		if err != nil {
   555  			return nil, errors.Wrapf(err, "unable to create udp port from %s", k)
   556  		}
   557  		ports[npTCP] = struct{}{}
   558  		ports[npUDP] = struct{}{}
   559  	}
   560  	return ports, nil
   561  }