github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/daemon/commit.go (about) 1 package daemon 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "runtime" 8 "strings" 9 "time" 10 11 "golang.org/x/net/context" 12 13 "github.com/docker/docker/api/types" 14 // "github.com/docker/docker/utils" 15 // "github.com/docker/docker/pkg/term" 16 // "github.com/docker/docker/api/types/strslice" 17 // "github.com/docker/docker/daemon/exec" 18 // "github.com/docker/docker/pkg/pools" 19 // "github.com/docker/docker/pkg/signal" 20 21 22 // "github.com/Sirupsen/logrus" 23 // "github.com/docker/docker/api/errors" 24 // "github.com/docker/docker/libcontainerd" 25 26 27 "github.com/docker/docker/api/types/backend" 28 containertypes "github.com/docker/docker/api/types/container" 29 "github.com/docker/docker/builder/dockerfile" 30 "github.com/docker/docker/container" 31 "github.com/docker/docker/dockerversion" 32 "github.com/docker/docker/image" 33 "github.com/docker/docker/layer" 34 "github.com/docker/docker/pkg/ioutils" 35 "github.com/docker/docker/reference" 36 ) 37 38 39 // merge merges two Config, the image container configuration (defaults values), 40 // and the user container configuration, either passed by the API or generated 41 // by the cli. 42 // It will mutate the specified user configuration (userConf) with the image 43 // configuration where the user configuration is incomplete. 44 func merge(userConf, imageConf *containertypes.Config) error { 45 if userConf.User == "" { 46 userConf.User = imageConf.User 47 } 48 if len(userConf.ExposedPorts) == 0 { 49 userConf.ExposedPorts = imageConf.ExposedPorts 50 } else if imageConf.ExposedPorts != nil { 51 for port := range imageConf.ExposedPorts { 52 if _, exists := userConf.ExposedPorts[port]; !exists { 53 userConf.ExposedPorts[port] = struct{}{} 54 } 55 } 56 } 57 58 if len(userConf.Env) == 0 { 59 userConf.Env = imageConf.Env 60 } else { 61 for _, imageEnv := range imageConf.Env { 62 found := false 63 imageEnvKey := strings.Split(imageEnv, "=")[0] 64 for _, userEnv := range userConf.Env { 65 userEnvKey := strings.Split(userEnv, "=")[0] 66 if runtime.GOOS == "windows" { 67 // Case insensitive environment variables on Windows 68 imageEnvKey = strings.ToUpper(imageEnvKey) 69 userEnvKey = strings.ToUpper(userEnvKey) 70 } 71 if imageEnvKey == userEnvKey { 72 found = true 73 break 74 } 75 } 76 if !found { 77 userConf.Env = append(userConf.Env, imageEnv) 78 } 79 } 80 } 81 82 if userConf.Labels == nil { 83 userConf.Labels = map[string]string{} 84 } 85 if imageConf.Labels != nil { 86 for l := range userConf.Labels { 87 imageConf.Labels[l] = userConf.Labels[l] 88 } 89 userConf.Labels = imageConf.Labels 90 } 91 92 if len(userConf.Entrypoint) == 0 { 93 if len(userConf.Cmd) == 0 { 94 userConf.Cmd = imageConf.Cmd 95 userConf.ArgsEscaped = imageConf.ArgsEscaped 96 } 97 98 if userConf.Entrypoint == nil { 99 userConf.Entrypoint = imageConf.Entrypoint 100 } 101 } 102 if imageConf.Healthcheck != nil { 103 if userConf.Healthcheck == nil { 104 userConf.Healthcheck = imageConf.Healthcheck 105 } else { 106 if len(userConf.Healthcheck.Test) == 0 { 107 userConf.Healthcheck.Test = imageConf.Healthcheck.Test 108 } 109 if userConf.Healthcheck.Interval == 0 { 110 userConf.Healthcheck.Interval = imageConf.Healthcheck.Interval 111 } 112 if userConf.Healthcheck.Timeout == 0 { 113 userConf.Healthcheck.Timeout = imageConf.Healthcheck.Timeout 114 } 115 if userConf.Healthcheck.Retries == 0 { 116 userConf.Healthcheck.Retries = imageConf.Healthcheck.Retries 117 } 118 } 119 } 120 121 if userConf.WorkingDir == "" { 122 userConf.WorkingDir = imageConf.WorkingDir 123 } 124 if len(userConf.Volumes) == 0 { 125 userConf.Volumes = imageConf.Volumes 126 } else { 127 for k, v := range imageConf.Volumes { 128 userConf.Volumes[k] = v 129 } 130 } 131 132 if userConf.StopSignal == "" { 133 userConf.StopSignal = imageConf.StopSignal 134 } 135 return nil 136 } 137 138 // Commit creates a new filesystem image from the current state of a container. 139 // The image can optionally be tagged into a repository. 140 func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (string, error) { 141 start := time.Now() 142 143 fmt.Println("daemon/commit.go Commit()") 144 145 container, err := daemon.GetContainer(name) 146 if err != nil { 147 return "", err 148 } 149 fmt.Println("daemon/commit.go Commit() container.ImageID : ", container.ImageID) 150 fmt.Println("daemon/commit.go Commit() name : ", name) 151 152 // It is not possible to commit a running container on Windows and on Solaris. 153 if (runtime.GOOS == "windows" || runtime.GOOS == "solaris") && container.IsRunning() { 154 return "", fmt.Errorf("%+v does not support commit of a running container", runtime.GOOS) 155 } 156 157 158 tmpConfig := container.Config 159 fmt.Println("daemon/commit.go judge the status c.Pause container container.IsPause()",c.Pause , container.IsPaused()) 160 fmt.Println("daemon/commit.go container Config ", tmpConfig) 161 162 /* if c.Pause && !container.IsPaused() { 163 daemon.containerPause(container) 164 defer daemon.containerUnpause(container) 165 } 166 */ 167 fmt.Println("daemon/commit.go not Paused!!!!!!!!!!!!!!") 168 169 170 newConfig, err := dockerfile.BuildFromConfig(c.Config, c.Changes) 171 if err != nil { 172 return "", err 173 } 174 175 176 fmt.Println("daemon/commit.go merge config") 177 if c.MergeConfigs { 178 if err := merge(newConfig, container.Config); err != nil { 179 return "", err 180 } 181 } 182 183 fmt.Println("daemon/commit.go before exportContainerRw container : ", container) 184 rwTar, err := daemon.exportContainerRw(container) 185 if err != nil { 186 fmt.Println("daemon/commit.go exportContainerRw is err!!!") 187 return "", err 188 } 189 defer func() { 190 if rwTar != nil { 191 rwTar.Close() 192 } 193 }() 194 195 var history []image.History 196 rootFS := image.NewRootFS() 197 osVersion := "" 198 var osFeatures []string 199 200 if container.ImageID != "" { 201 fmt.Println("daemon/commit.go container.ImageID : ", container.ImageID) 202 img, err := daemon.imageStore.Get(container.ImageID) 203 if err != nil { 204 return "", err 205 } 206 history = img.History 207 rootFS = img.RootFS 208 osVersion = img.OSVersion 209 osFeatures = img.OSFeatures 210 } 211 212 fmt.Println("daemon/commit.go before register()") 213 l, err := daemon.layerStore.Register(rwTar, rootFS.ChainID()) 214 if err != nil { 215 return "", err 216 } 217 fmt.Println("daemon/commit.go after register()") 218 defer layer.ReleaseAndLog(daemon.layerStore, l) 219 220 h := image.History{ 221 Author: c.Author, 222 Created: time.Now().UTC(), 223 CreatedBy: strings.Join(container.Config.Cmd, " "), 224 Comment: c.Comment, 225 EmptyLayer: true, 226 } 227 228 fmt.Println("daemon/commit.go before diff()") 229 if diffID := l.DiffID(); layer.DigestSHA256EmptyTar != diffID { 230 h.EmptyLayer = false 231 rootFS.Append(diffID) 232 } 233 234 history = append(history, h) 235 236 config, err := json.Marshal(&image.Image{ 237 V1Image: image.V1Image{ 238 DockerVersion: dockerversion.Version, 239 Config: newConfig, 240 Architecture: runtime.GOARCH, 241 OS: runtime.GOOS, 242 Container: container.ID, 243 ContainerConfig: *container.Config, 244 Author: c.Author, 245 Created: h.Created, 246 }, 247 RootFS: rootFS, 248 History: history, 249 OSFeatures: osFeatures, 250 OSVersion: osVersion, 251 }) 252 253 if err != nil { 254 return "", err 255 } 256 257 fmt.Println("daemon/commit.go before create()") 258 id, err := daemon.imageStore.Create(config) 259 fmt.Println("daemon/commit.go Commit finish creat image") 260 261 if err != nil { 262 return "", err 263 } 264 265 if container.ImageID != "" { 266 if err := daemon.imageStore.SetParent(id, container.ImageID); err != nil { 267 return "", err 268 } 269 } 270 271 imageRef := "" 272 if c.Repo != "" { 273 newTag, err := reference.WithName(c.Repo) // todo: should move this to API layer 274 if err != nil { 275 return "", err 276 } 277 if c.Tag != "" { 278 if newTag, err = reference.WithTag(newTag, c.Tag); err != nil { 279 return "", err 280 } 281 } 282 if err := daemon.TagImageWithReference(id, newTag); err != nil { 283 return "", err 284 } 285 imageRef = newTag.String() 286 } 287 288 attributes := map[string]string{ 289 "comment": c.Comment, 290 "imageID": id.String(), 291 "imageRef": imageRef, 292 } 293 daemon.LogContainerEventWithAttributes(container, "commit", attributes) 294 containerActions.WithValues("commit").UpdateSince(start) 295 return id.String(), nil 296 } 297 298 299 func (daemon *Daemon) GetFirstContainerStatus(id string) error { 300 container, err := daemon.GetContainer(id) 301 if err != nil { 302 return err 303 } 304 fmt.Println("daemon/commit.go GetFirstContainerStatus() isRunning ", container.IsRunning()) 305 return nil 306 } 307 308 /* 309 //func (daemon *Daemon) GetFirstContainer(id string) (*container.Container, error) { 310 container, err := daemon.GetContainer(id) 311 if err != nil { 312 return "", err 313 } 314 fmt.Println("daemon/commit.go GetFirstContainer() return first container") 315 316 return container, err 317 } 318 */ 319 /* 320 //func (daemon *Daemon) GetFirstContainerBuildingStatus(id string) error { 321 container, err := daemon.GetContainer(id) 322 if err != nil { 323 return err 324 } 325 fmt.Println("daemon/commit.go GetFirstContainerBuildingStatus() isBuilding : ", container.GetBuildingStatus()) 326 327 return nil 328 } 329 */ 330 331 func (daemon *Daemon) SetFirstContainerBuildingStatus(cId string, status bool) error { 332 container, err := daemon.GetContainer(cId) 333 if err != nil { 334 return err 335 } 336 337 fmt.Println("daemon/commit.go SetFirstContainerBuildingStatus() isBuilding before : ", container.GetBuildingStatus()) 338 container.SetBuildingStatus(status) 339 fmt.Println("daemon/commit.go SetFirstContainerBuildingStatus() isBuilding after : ", container.GetBuildingStatus()) 340 341 return nil 342 } 343 344 345 // ContainerExecCreate sets up an exec in a running container. 346 func (d *Daemon) FirstContainerExecCreate(name string, config *types.ExecConfig) (string, error) { 347 348 fmt.Println("daemon/commit.go FirstContainerExecCreate()") 349 350 id, err := d.ContainerExecCreate(name, config) 351 if err != nil { 352 fmt.Println("daemon/commit.go ContainerExecCreate() is err!!!") 353 return "", err 354 } 355 356 fmt.Println("daemon/commit.go FirstContainerExecCreate() end") 357 return id, err 358 359 360 /* container, err := d.getActiveContainer(name) 361 if err != nil { 362 return "", err 363 } 364 365 cmd := strslice.StrSlice(config.Cmd) 366 entrypoint, args := d.getEntrypointAndArgs(strslice.StrSlice{}, cmd) 367 368 keys := []byte{} 369 if config.DetachKeys != "" { 370 keys, err = term.ToBytes(config.DetachKeys) 371 if err != nil { 372 err = fmt.Errorf("Invalid escape keys (%s) provided", config.DetachKeys) 373 return "", err 374 } 375 } 376 377 execConfig := exec.NewConfig() 378 execConfig.OpenStdin = config.AttachStdin 379 execConfig.OpenStdout = config.AttachStdout 380 execConfig.OpenStderr = config.AttachStderr 381 execConfig.ContainerID = container.ID 382 execConfig.DetachKeys = keys 383 execConfig.Entrypoint = entrypoint 384 execConfig.Args = args 385 execConfig.Tty = config.Tty 386 execConfig.Privileged = config.Privileged 387 execConfig.User = config.User 388 389 linkedEnv, err := d.setupLinkedContainers(container) 390 if err != nil { 391 return "", err 392 } 393 execConfig.Env = utils.ReplaceOrAppendEnvValues(container.CreateDaemonEnvironment(config.Tty, linkedEnv), config.Env) 394 if len(execConfig.User) == 0 { 395 execConfig.User = container.Config.User 396 } 397 398 d.registerExecCommand(container, execConfig) 399 400 d.LogContainerEvent(container, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")) 401 402 return execConfig.ID, nil 403 */ 404 } 405 406 407 408 // ContainerExecStart starts a previously set up exec instance. The 409 // std streams are set up. 410 // If ctx is cancelled, the process is terminated. 411 func (d *Daemon) FirstContainerExecStart(ctx context.Context, name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) (err error) { 412 413 fmt.Println("daemon/commit.go FirstContainerExecStart()") 414 415 if err := d.ContainerExecStart(ctx, name, stdin, stdout, stderr); err != nil { 416 fmt.Println("daemon/commit.go FirstContainerExecStart() is err : ", err) 417 } 418 419 /* 420 var ( 421 cStdin io.ReadCloser 422 cStdout, cStderr io.Writer 423 ) 424 425 ec, err := d.getExecConfig(name) 426 if err != nil { 427 return errExecNotFound(name) 428 } 429 fmt.Println("daemon/commit.go FirstContainerExecStart() execConfig : ", ec) 430 431 ec.Lock() 432 if ec.ExitCode != nil { 433 ec.Unlock() 434 err := fmt.Errorf("Error: Exec command %s has already run", ec.ID) 435 return errors.NewRequestConflictError(err) 436 } 437 438 if ec.Running { 439 ec.Unlock() 440 return fmt.Errorf("Error: Exec command %s is already running", ec.ID) 441 } 442 ec.Running = true 443 defer func() { 444 if err != nil { 445 ec.Running = false 446 exitCode := 126 447 ec.ExitCode = &exitCode 448 } 449 }() 450 ec.Unlock() 451 452 c := d.containers.Get(ec.ContainerID) 453 fmt.Println("daemon/commit.go FirstContainerExecStart starting exec command : ", ec.ID) 454 fmt.Println("daemon/commit.go FirstContainerExecStart in container : ", c.ID) 455 456 d.LogContainerEvent(c, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " ")) 457 458 if ec.OpenStdin && stdin != nil { 459 r, w := io.Pipe() 460 go func() { 461 defer w.Close() 462 defer logrus.Debug("Closing buffered stdin pipe") 463 pools.Copy(w, stdin) 464 }() 465 cStdin = r 466 } 467 if ec.OpenStdout { 468 cStdout = stdout 469 } 470 if ec.OpenStderr { 471 cStderr = stderr 472 } 473 474 if ec.OpenStdin { 475 ec.StreamConfig.NewInputPipes() 476 } else { 477 ec.StreamConfig.NewNopInputPipe() 478 } 479 480 p := libcontainerd.Process{ 481 Args: append([]string{ec.Entrypoint}, ec.Args...), 482 Env: ec.Env, 483 Terminal: ec.Tty, 484 } 485 486 if err := execSetPlatformOpt(c, ec, &p); err != nil { 487 return err 488 } 489 490 attachErr := container.AttachStreams(ctx, ec.StreamConfig, ec.OpenStdin, true, ec.Tty, cStdin, cStdout, cStderr, ec.DetachKeys) 491 492 fmt.Println("daemon/commit.go FirstContainerExecStart() AddProcess()") 493 systemPid, err := d.containerd.AddProcess(ctx, c.ID, name, p, ec.InitializeStdio) 494 if err != nil { 495 fmt.Println("daemon/commit.go FirstContainerExecStart() AddProcess() err!!!") 496 return err 497 } 498 fmt.Println("daemon/commit.go FirstContainerExecStart() AddProcess systemPid : ", systemPid) 499 500 ec.Lock() 501 ec.Pid = systemPid 502 ec.Unlock() 503 504 select { 505 case <-ctx.Done(): 506 logrus.Debugf("Sending TERM signal to process %v in container %v", name, c.ID) 507 fmt.Println("daemon/commit.go FirstContainerExecStart() sendingterm signal") 508 d.containerd.SignalProcess(c.ID, name, int(signal.SignalMap["TERM"])) 509 select { 510 case <-time.After(termProcessTimeout * time.Second): 511 logrus.Infof("Container %v, process %v failed to exit within %d seconds of signal TERM - using the force", c.ID, name, termProcessTimeout) 512 fmt.Println("daemon/commit.go FirstContainerExecStart() failed to exit termProcessTimeout ", termProcessTimeout) 513 d.containerd.SignalProcess(c.ID, name, int(signal.SignalMap["KILL"])) 514 case <-attachErr: 515 // TERM signal worked 516 fmt.Println("daemon/commit.go FirstExecContainer() TERM signal worked") 517 } 518 return fmt.Errorf("context cancelled") 519 case err := <-attachErr: 520 fmt.Println("daemon/commit.go FirstContainerExecStart() attachErr") 521 if err != nil { 522 if _, ok := err.(container.DetachError); !ok { 523 return fmt.Errorf("exec attach failed with error: %v", err) 524 } 525 d.LogContainerEvent(c, "exec_detach") 526 } 527 } 528 */ 529 fmt.Println("daemon/commit.go FirstContainerExecStart() end") 530 return nil 531 } 532 533 534 535 // It will also return the error produced by `getConfig` 536 func (d *Daemon) FirstContainerExecExists(name string) (bool, error) { 537 if _, err := d.getExecConfig(name); err != nil { 538 return false, err 539 } 540 return true, nil 541 } 542 543 544 545 546 func (daemon *Daemon) exportContainerRw(container *container.Container) (io.ReadCloser, error) { 547 fmt.Println("daemon/commit.go exportContainerRw") 548 549 if err := daemon.Mount(container); err != nil { 550 return nil, err 551 } 552 553 archive, err := container.RWLayer.TarStream() 554 if err != nil { 555 daemon.Unmount(container) // logging is already handled in the `Unmount` function 556 return nil, err 557 } 558 return ioutils.NewReadCloserWrapper(archive, func() error { 559 archive.Close() 560 return container.RWLayer.Unmount() 561 }), 562 nil 563 }