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  }