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 }