diff --git a/added-cow-option-to-bind.patch b/added-cow-option-to-bind.patch deleted file mode 100644 index 7217317..0000000 --- a/added-cow-option-to-bind.patch +++ /dev/null @@ -1,254 +0,0 @@ -diff --git a/internal/app/wwctl/container/exec/child/main.go b/internal/app/wwctl/container/exec/child/main.go -index 253a6ad2..0785ba74 100644 ---- a/internal/app/wwctl/container/exec/child/main.go -+++ b/internal/app/wwctl/container/exec/child/main.go -@@ -92,7 +92,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { - wwlog.Debug("overlay options: %s", options) - err = syscall.Mount("overlay", containerPath, "overlay", 0, options) - if err != nil { -- wwlog.Warn(fmt.Sprintf("Couldn't create overlay for ephermal mount points: %s", err)) -+ wwlog.Warn("Couldn't create overlay for ephermal mount points: %s", err) - } - } else if nodename != "" { - nodeDB, err := node.New() -@@ -142,6 +142,10 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { - } - - for _, mntPnt := range mountPts { -+ if mntPnt.Copy { -+ continue -+ } -+ wwlog.Debug("bind mounting: %s -> %s", mntPnt.Source, path.Join(containerPath, mntPnt.Dest)) - err = syscall.Mount(mntPnt.Source, path.Join(containerPath, mntPnt.Dest), "", syscall.MS_BIND, "") - if err != nil { - wwlog.Warn("Couldn't mount %s to %s: %s", mntPnt.Source, mntPnt.Dest, err) -@@ -195,6 +199,9 @@ the invalid mount points. Directories always have '/' as suffix - func checkMountPoints(containerName string, binds []*warewulfconf.MountEntry) (overlayObjects []string) { - overlayObjects = []string{} - for _, b := range binds { -+ if b.Copy { -+ continue -+ } - _, err := os.Stat(b.Source) - if err != nil { - wwlog.Debug("Couldn't stat %s create no mount point in container", b.Source) -diff --git a/internal/app/wwctl/container/exec/main.go b/internal/app/wwctl/container/exec/main.go -index 60cf9d48..336218a9 100644 ---- a/internal/app/wwctl/container/exec/main.go -+++ b/internal/app/wwctl/container/exec/main.go -@@ -54,7 +54,6 @@ func runContainedCmd(cmd *cobra.Command, containerName string, args []string) (e - }() - - logStr := fmt.Sprint(wwlog.GetLogLevel()) -- - childArgs := []string{"--warewulfconf", conf.GetWarewulfConf(), "--loglevel", logStr, "container", "exec", "__child"} - childArgs = append(childArgs, containerName) - for _, b := range binds { -@@ -64,8 +63,32 @@ func runContainedCmd(cmd *cobra.Command, containerName string, args []string) (e - childArgs = append(childArgs, "--node", nodeName) - } - childArgs = append(childArgs, args...) -+ // copy the files into the container at this stage, es in __child the -+ // command syscall.Exec which replaces the __child process with the -+ // exec command in the container. All the mounts, have to be done in -+ // __child so that the used mounts don't propagate outside on the host -+ // (see the CLONE attributes), but as for the copy option we need -+ // to see if a file was modified after it was copied into the container -+ // so do this here. -+ // At first read out conf, the parse commandline, as copy files has the -+ // same synatx as mount points -+ mountPts := append(container.InitMountPnts(binds), conf.MountsContainer...) -+ filesToCpy := getCopyFiles(mountPts) -+ for _, cpyFile := range filesToCpy { -+ if err := (cpyFile).copyToContainer(containerName); err != nil { -+ wwlog.Warn("couldn't copy file: %s", err) -+ } -+ } - wwlog.Verbose("Running contained command: %s", childArgs) -- return childCommandFunc(cmd, childArgs) -+ retVal := childCommandFunc(cmd, childArgs) -+ for _, cpyFile := range filesToCpy { -+ if cpyFile.shouldRemoveFromContainer(containerName) { -+ if err := cpyFile.removeFromContainer(containerName); err != nil { -+ wwlog.Warn("couldn't remove file: %s", err) -+ } -+ } -+ } -+ return retVal - } - - func CobraRunE(cmd *cobra.Command, args []string) error { -@@ -154,3 +177,68 @@ func SetBinds(myBinds []string) { - func SetNode(myNode string) { - nodeName = myNode - } -+ -+// file name and last modification time so we can remove the file if it wasn't modified -+type copyFile struct { -+ fileName string -+ src string -+ modTime time.Time -+} -+ -+func (this *copyFile) containerDest(containerName string) string { -+ return path.Join(container.RootFsDir(containerName), this.fileName) -+} -+ -+func (this *copyFile) copyToContainer(containerName string) error { -+ containerDest := this.containerDest(containerName) -+ if _, err := os.Stat(path.Dir(containerDest)); err != nil { -+ return err -+ } else if _, err := os.Stat(containerDest); err == nil { -+ return err -+ } else if _, err := os.Stat(this.src); err != nil { -+ return err -+ } else if err := util.CopyFile(this.src, containerDest); err != nil { -+ return err -+ } else if stat, err := os.Stat(containerDest); err != nil { -+ return err -+ } else { -+ this.modTime = stat.ModTime() -+ return nil -+ } -+} -+ -+func (this *copyFile) shouldRemoveFromContainer(containerName string) bool { -+ containerDest := this.containerDest(containerName) -+ if this.modTime.IsZero() { -+ wwlog.Debug("file was not previously copied: %s", this.fileName) -+ return false -+ } else if destStat, err := os.Stat(containerDest); err != nil { -+ wwlog.Verbose("file is no longer present: %s (%s)", this.fileName, err) -+ return false -+ } else if destStat.ModTime() == this.modTime { -+ wwlog.Verbose("don't remove modified file:", this.fileName) -+ return false -+ } else { -+ return true -+ } -+} -+ -+func (this *copyFile) removeFromContainer(containerName string) error { -+ containerDest := this.containerDest(containerName) -+ return os.Remove(containerDest) -+} -+ -+/* -+Check the objects we want to copy in, instead of mounting -+*/ -+func getCopyFiles(binds []*warewulfconf.MountEntry) (copyObjects []*copyFile) { -+ for _, bind := range binds { -+ if bind.Copy { -+ copyObjects = append(copyObjects, ©File{ -+ fileName: bind.Dest, -+ src: bind.Source, -+ }) -+ } -+ } -+ return -+} -diff --git a/internal/app/wwctl/container/exec/root.go b/internal/app/wwctl/container/exec/root.go -index 4b74c941..1152fd8e 100644 ---- a/internal/app/wwctl/container/exec/root.go -+++ b/internal/app/wwctl/container/exec/root.go -@@ -32,7 +32,10 @@ var ( - - func init() { - baseCmd.AddCommand(child.GetCommand()) -- baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, "Bind a local path into the container (must exist)") -+ baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, `source[:destination[:{ro|copy}]] -+Bind a local path which must exist into the container. If destination is not -+set, uses the same path as source. "ro" binds read-only. "copy" temporarily -+copies the file into the container.`) - baseCmd.PersistentFlags().BoolVar(&SyncUser, "syncuser", false, "Synchronize UIDs/GIDs from host to container") - baseCmd.PersistentFlags().StringVarP(&nodeName, "node", "n", "", "Create a read only view of the container for the given node") - } -diff --git a/internal/app/wwctl/container/shell/root.go b/internal/app/wwctl/container/shell/root.go -index cceb7512..e1ae01d3 100644 ---- a/internal/app/wwctl/container/shell/root.go -+++ b/internal/app/wwctl/container/shell/root.go -@@ -28,7 +28,10 @@ var ( - ) - - func init() { -- baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, "Bind a local path into the container (must exist)") -+ baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, `source[:destination[:{ro|copy}]] -+Bind a local path which must exist into the container. If destination is not -+set, uses the same path as source. "ro" binds read-only. "copy" temporarily -+copies the file into the container.`) - baseCmd.PersistentFlags().StringVarP(&nodeName, "node", "n", "", "Create a read only view of the container for the given node") - } - -diff --git a/internal/pkg/config/mounts.go b/internal/pkg/config/mounts.go -index 2eb5060b..305fbad4 100644 ---- a/internal/pkg/config/mounts.go -+++ b/internal/pkg/config/mounts.go -@@ -7,4 +7,5 @@ type MountEntry struct { - Dest string `yaml:"dest,omitempty"` - ReadOnly bool `yaml:"readonly,omitempty"` - Options string `yaml:"options,omitempty"` // ignored at the moment -+ Copy bool `yaml:"copy,omitempty"` // temporarily copy the file into the container - } -diff --git a/internal/pkg/container/mountpoints.go b/internal/pkg/container/mountpoints.go -index 5de00c75..961513fb 100644 ---- a/internal/pkg/container/mountpoints.go -+++ b/internal/pkg/container/mountpoints.go -@@ -21,13 +21,19 @@ func InitMountPnts(binds []string) (mounts []*warewulfconf.MountEntry) { - dest = bind[1] - } - readonly := false -- if len(bind) >= 3 && bind[2] == "ro" { -- readonly = true -+ copy_ := false -+ if len(bind) >= 3 { -+ if bind[2] == "ro" { -+ readonly = true -+ } else if bind[2] == "copy" { -+ copy_ = true -+ } - } - mntPnt := warewulfconf.MountEntry{ - Source: bind[0], - Dest: dest, - ReadOnly: readonly, -+ Copy: copy_, - } - mounts = append(mounts, &mntPnt) - } -diff --git a/internal/pkg/warewulfd/copyshim.go b/internal/pkg/warewulfd/copyshim.go -index 4f085017..13a32d64 100644 ---- a/internal/pkg/warewulfd/copyshim.go -+++ b/internal/pkg/warewulfd/copyshim.go -@@ -16,7 +16,6 @@ import ( - Copies the default shim, which is the shim located on host - to the tftp directory - */ -- - func CopyShimGrub() (err error) { - conf := warewulfconf.Get() - wwlog.Debug("copy shim and grub binaries from host") -diff --git a/userdocs/contents/containers.rst b/userdocs/contents/containers.rst -index 2e84921f..2ee7a236 100644 ---- a/userdocs/contents/containers.rst -+++ b/userdocs/contents/containers.rst -@@ -213,6 +213,20 @@ when using the exec command. This works as follows: - location, as it is almost always present and empty in every Linux - distribution (as prescribed by the LSB file hierarchy standard). - -+Files which should always be present in a container image like ``resolv.conf`` -+can be specified in ``warewulf.conf``: -+ -+.. code-block:: yaml -+ container mounts: -+ - source: /etc/resolv.conf -+ dest: /etc/resolv.conf -+ readonly: true -+ -+.. note:: -+ Instead of ``readonly: true`` you can set ``copy: true``. This causes the -+ source file to be copied to the container and removed if it was not -+ modified. This can be useful for files used for registrations. -+ - When the command completes, if anything within the container changed, - the container will be rebuilt into a bootable static object - automatically.