From 99fdce7258368459cb3671531d869599da7b9a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20=C5=A0=C5=A5astn=C3=BD?= Date: Mon, 26 Jan 2026 15:40:07 +0100 Subject: [PATCH 1/4] Add check for docker environment, refactor --- cmd/bap-builder/AppMode.go | 2 +- cmd/bap-builder/PackageMode.go | 83 ++++++++++++++++++++-- cmd/bap-builder/SysrootMode.go | 2 +- internal/bacpack_package/PlatformString.go | 21 +----- internal/build/Build.go | 39 +++------- internal/constants/Constants.go | 2 + internal/docker/DockerRun.go | 22 ++++++ internal/sysroot/Sysroot.go | 73 ++++++++++++++----- internal/sysroot/default_test.go | 37 +++++++--- 9 files changed, 198 insertions(+), 83 deletions(-) diff --git a/cmd/bap-builder/AppMode.go b/cmd/bap-builder/AppMode.go index ad1c5e5..655bc7e 100644 --- a/cmd/bap-builder/AppMode.go +++ b/cmd/bap-builder/AppMode.go @@ -16,7 +16,7 @@ import ( // BuildApp func BuildApp(cmdLine *BuildAppCmdLineArgs, contextPath string) error { - platformString, err := determinePlatformString(*cmdLine.DockerImageName, uint16(*cmdLine.Port)) + platformString, err := checkDockerEnvironmentAndDeterminePlatformString(*cmdLine.DockerImageName, uint16(*cmdLine.Port)) if err != nil { return err } diff --git a/cmd/bap-builder/PackageMode.go b/cmd/bap-builder/PackageMode.go index 72ebef1..20fd4d5 100644 --- a/cmd/bap-builder/PackageMode.go +++ b/cmd/bap-builder/PackageMode.go @@ -17,6 +17,7 @@ import ( "fmt" "strconv" "slices" + "time" ) type buildDepList struct { @@ -122,7 +123,7 @@ func performPreBuildChecks( // BuildPackage // process Package mode of the program func BuildPackage(cmdLine *BuildPackageCmdLineArgs, contextPath string) error { - platformString, err := determinePlatformString(*cmdLine.DockerImageName, uint16(*cmdLine.Port)) + platformString, err := checkDockerEnvironmentAndDeterminePlatformString(*cmdLine.DockerImageName, uint16(*cmdLine.Port)) if err != nil { return err } @@ -401,14 +402,79 @@ func buildAndCopyPackage( return err } -// determinePlatformString -// Will construct platform string suitable for sysroot. -func determinePlatformString(dockerImageName string, dockerPort uint16) (*bacpack_package.PlatformString, error) { +// checkDockerEnvironment +// Checks if the Docker environment is valid. Checks for read/write permissions and volume read +// permissions. +func checkDockerEnvironment(credentials ssh.SSHCredentials) error { + testDir := "/packager-test-dir-" + strconv.Itoa(time.Now().Nanosecond()) + + logger := log.GetLogger() + + shellEvaluator := ssh.ShellEvaluator{ + Commands: []string{"mkdir " + testDir + " && test -r " + testDir + " && test -w " + testDir + " && rmdir " + testDir}, + } + + err := shellEvaluator.RunOverSSH(credentials) + if err != nil { + logger.ErrorIndent("Cannot create directories, or read or write to them inside Docker container") + return fmt.Errorf("invalid Docker environment") + } + + shellEvaluator.Commands = []string{"test -r " + constants.ContainerSysrootPath} + + err = shellEvaluator.RunOverSSH(credentials) + if err != nil { + logger.ErrorIndent("Cannot read volume directory inside Docker container") + return fmt.Errorf("invalid Docker environment") + } + + return nil +} + +// prepareDockerEnvironmentCheck +// Prepares Docker environment for check and returns Docker struct to be used for check. +func prepareDockerEnvironmentCheck(dockerImageName string, dockerPort uint16) (*docker.Docker, error) { defaultDocker, err := prerequisites.CreateAndInitialize[docker.Docker](dockerImageName, dockerPort) if err != nil { return nil, err } - defaultDocker.ImageName = dockerImageName + + err = sysroot.CreateBaseSysrootDir() + if err != nil { + return nil, err + } + + sysrootPath, err := sysroot.GetBaseSysrootPath() + if err != nil { + return nil, err + } + + err = defaultDocker.SetVolume(sysrootPath, constants.ContainerSysrootPath) + if err != nil { + return nil, err + } + + return defaultDocker, nil +} + +// checkDockerEnvironmentAndDeterminePlatformString +// Checks if the Docker environment is valid and constructs platform string suitable for sysroot. +func checkDockerEnvironmentAndDeterminePlatformString(dockerImageName string, dockerPort uint16) (*bacpack_package.PlatformString, error) { + logger := log.GetLogger() + logger.Info("Checking Docker environment") + + defaultDocker, err := prepareDockerEnvironmentCheck(dockerImageName, dockerPort) + if err != nil { + return nil, err + } + + dockerRun := (*docker.DockerRun)(defaultDocker) + err = dockerRun.Run() + if err != nil { + return nil, err + } + removeHandler := dockerRun.GetUndoHandler() + defer removeHandler() sshCreds, err := prerequisites.CreateAndInitialize[ssh.SSHCredentials]() if err != nil { @@ -416,11 +482,16 @@ func determinePlatformString(dockerImageName string, dockerPort uint16) (*bacpac } sshCreds.Port = uint16(defaultDocker.Port) + err = checkDockerEnvironment(*sshCreds) + if err != nil { + return nil, err + } + platformString := bacpack_package.PlatformString{ Mode: bacpack_package.ModeAuto, } - err = prerequisites.Initialize[bacpack_package.PlatformString](&platformString, sshCreds, defaultDocker) + err = prerequisites.Initialize(&platformString, sshCreds, defaultDocker) return &platformString, err } diff --git a/cmd/bap-builder/SysrootMode.go b/cmd/bap-builder/SysrootMode.go index 451b088..019df84 100644 --- a/cmd/bap-builder/SysrootMode.go +++ b/cmd/bap-builder/SysrootMode.go @@ -39,7 +39,7 @@ func CreateSysroot(cmdLine *CreateSysrootCmdLineArgs, contextPath string) error if err != nil { return err } - platformString, err := determinePlatformString(*cmdLine.ImageName, uint16(*cmdLine.Port)) + platformString, err := checkDockerEnvironmentAndDeterminePlatformString(*cmdLine.ImageName, uint16(*cmdLine.Port)) if err != nil { return err } diff --git a/internal/bacpack_package/PlatformString.go b/internal/bacpack_package/PlatformString.go index eaa2afa..decd154 100644 --- a/internal/bacpack_package/PlatformString.go +++ b/internal/bacpack_package/PlatformString.go @@ -5,13 +5,11 @@ import ( "github.com/bacpack-system/packager/internal/docker" "github.com/bacpack-system/packager/internal/log" "github.com/bacpack-system/packager/internal/prerequisites" - "github.com/bacpack-system/packager/internal/process" "github.com/bacpack-system/packager/internal/ssh" "fmt" "os" "regexp" "strings" - "time" ) // PlatformStringMode is a fill-up mode of the platform-string. @@ -111,30 +109,13 @@ func (pstr *PlatformString) CheckPrerequisites(args *prerequisites.Args) error { } // determinePlatformString -// Computes platform string for ModeAuto. +// Gets PlatformString for ModeAuto from container using credentials The container must be already running. // If the PlatformString is in ModeExplicit the panic raise. func (pstr *PlatformString) determinePlatformString(credentials ssh.SSHCredentials, dock *docker.Docker) error { if pstr.Mode == ModeExplicit { panic(fmt.Errorf("cannot determine PlatformString for explicit mode")) } - dockerRun := (*docker.DockerRun)(dock) - removeHandler := process.SignalHandlerAddHandler(func() error { - dockerStop := (*docker.DockerStop)(dock) - dockerRm := (*docker.DockerRm)(dock) - // Waiting for docker run command to get container id - time.Sleep(200 * time.Millisecond) - dockerStop.Stop() - return dockerRm.RemoveContainer() - }) - defer removeHandler() - - err := dockerRun.Run() - if err != nil { - return err - } - credentials.Port = dock.Port - distroName, distroRelease := getDistroIdAndReleaseFromDockerContainer(dock) if distroName == "" || distroRelease == "" { return fmt.Errorf("can't get distro name and id from os-release file") diff --git a/internal/build/Build.go b/internal/build/Build.go index 2181373..00d9309 100644 --- a/internal/build/Build.go +++ b/internal/build/Build.go @@ -7,7 +7,6 @@ import ( "github.com/bacpack-system/packager/internal/log" "github.com/bacpack-system/packager/internal/bacpack_package" "github.com/bacpack-system/packager/internal/prerequisites" - "github.com/bacpack-system/packager/internal/process" "github.com/bacpack-system/packager/internal/ssh" "github.com/bacpack-system/packager/internal/sysroot" "bufio" @@ -16,7 +15,6 @@ import ( "os" "path/filepath" "regexp" - "time" "strconv" ) @@ -159,13 +157,19 @@ func (build *Build) prepareForBuild() error { build.BuildSystem.InstallPrefix = constants.DockerInstallDirConst if build.sysroot != nil { - build.sysroot.CreateSysrootDir() - sysPath := build.sysroot.GetSysrootPath() - err = build.Docker.SetVolume(sysPath, "/sysroot") + err := build.sysroot.CreateSysrootDir() if err != nil { return err } - build.BuildSystem.PrefixPath = "/sysroot" + sysPath, err := build.sysroot.GetSysrootPath() + if err != nil { + return err + } + err = build.Docker.SetVolume(sysPath, constants.ContainerSysrootPath) + if err != nil { + return err + } + build.BuildSystem.PrefixPath = constants.ContainerSysrootPath } return nil @@ -199,11 +203,7 @@ func (build *Build) RunBuild() (error, bool) { // Long function - it is hard to } dockerRun := (*docker.DockerRun)(build.Docker) - removeHandler := process.SignalHandlerAddHandler(func() error { - // Waiting for docker run command to get container id - time.Sleep(300 * time.Millisecond) - return build.stopAndRemoveContainer() - }) + removeHandler := dockerRun.GetUndoHandler() defer removeHandler() logger.InfoIndent("Starting docker container") @@ -286,23 +286,6 @@ func (build *Build) GetLocalInstallDirPath() string { return copyBaseDir } -func (build *Build) stopAndRemoveContainer() error { - var err error - - dockerStop := (*docker.DockerStop)(build.Docker) - dockerRm := (*docker.DockerRm)(build.Docker) - logger := log.GetLogger() - err = dockerStop.Stop() - if err != nil { - logger.Error("Can't stop container - %s", err) - } - err = dockerRm.RemoveContainer() - if err != nil { - logger.Error("Can't remove container - %s", err) - } - return nil -} - func (build *Build) CleanUp() error { var err error copyDir := build.GetLocalInstallDirPath() diff --git a/internal/constants/Constants.go b/internal/constants/Constants.go index 6ad6fb7..bc04d37 100644 --- a/internal/constants/Constants.go +++ b/internal/constants/Constants.go @@ -20,4 +20,6 @@ const ( EmptyGitCommitHash = "" // Absolute path of Package Repository inside docker container ContainerPackageRepoPath = "/lfsrepo" + // Absolute path of sysroot inside docker container + ContainerSysrootPath = "/sysroot" ) diff --git a/internal/docker/DockerRun.go b/internal/docker/DockerRun.go index e3a023e..a44fd52 100644 --- a/internal/docker/DockerRun.go +++ b/internal/docker/DockerRun.go @@ -2,6 +2,7 @@ package docker import ( "github.com/bacpack-system/packager/internal/process" + "github.com/bacpack-system/packager/internal/log" "bytes" "fmt" "regexp" @@ -37,6 +38,27 @@ func (args *DockerRun) Run() error { return nil } +func (args *DockerRun) GetUndoHandler() func() { + return process.SignalHandlerAddHandler(func() error { + if args.containerId == "" { + return nil + } + dockerStop := (*DockerStop)(args) + dockerRm := (*DockerRm)(args) + + logger := log.GetLogger() + err := dockerStop.Stop() + if err != nil { + logger.Error("Can't stop container - %s", err) + } + err = dockerRm.RemoveContainer() + if err != nil { + logger.Error("Can't remove container - %s", err) + } + return nil + }) +} + func (runArgs *DockerRun) GenerateCmdLine() ([]string, error) { cmdArgs := make([]string, 0) cmdArgs = append(cmdArgs, "run") diff --git a/internal/sysroot/Sysroot.go b/internal/sysroot/Sysroot.go index 4fef809..054e7a8 100644 --- a/internal/sysroot/Sysroot.go +++ b/internal/sysroot/Sysroot.go @@ -16,6 +16,7 @@ import ( const ( sysrootDirectoryName = "install_sysroot" + sysrootDirPermissions = 0777 // Constant for number of problematic files which will be printed when trying to overwrite files // in sysroot listFilesCount = 10 @@ -58,7 +59,11 @@ func (sysroot *Sysroot) CopyToSysroot(source string, pack BuiltPackage) error { PreserveOwner: true, PreserveTimes: true, } - err = copy.Copy(source, sysroot.GetSysrootPath(), copyOptions) + sysrootPath, err := sysroot.GetSysrootPath() + if err != nil { + return err + } + err = copy.Copy(source, sysrootPath, copyOptions) if err != nil { return err } @@ -83,7 +88,11 @@ func (sysroot *Sysroot) IsPackageInSysroot(pack BuiltPackage) bool { func (sysroot *Sysroot) checkForOverwritingFiles(dirPath string) error { filesToCopy := getExistingFilesInDir(dirPath) filesInSysrootMap := make(map[string]struct{}) - for _, file := range getExistingFilesInDir(sysroot.GetSysrootPath()) { + sysrootPath, err := sysroot.GetSysrootPath() + if err != nil { + return err + } + for _, file := range getExistingFilesInDir(sysrootPath) { filesInSysrootMap[file] = struct{}{} } var intersection []string @@ -124,37 +133,69 @@ func (sysroot *Sysroot) GetDirNameInSysroot() string { return dirInSysrootName } +// GetBaseSysrootPath +// Returns absolute path to the sysroot base directory. +func GetBaseSysrootPath() (string, error) { + workingDir, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("cannot get working directory - %w", err) + } + + return filepath.Join(workingDir, sysrootDirectoryName), nil +} + +// CreateBaseSysrootDir +// Creates a Sysroot base dir. If not succeed returns error. +func CreateBaseSysrootDir() error { + sysPath, err := GetBaseSysrootPath() + if err != nil { + return err + } + err = os.MkdirAll(sysPath, sysrootDirPermissions) + if err != nil { + return fmt.Errorf("cannot create sysroot dir: '%s' - %w", sysPath, err) + } + + return nil +} + // GetSysrootPath // Returns absolute path to the sysroot. -func (sysroot *Sysroot) GetSysrootPath() string { - workingDir, err := os.Getwd() +func (sysroot *Sysroot) GetSysrootPath() (string, error) { + baseSysrootPath, err := GetBaseSysrootPath() if err != nil { - panic(fmt.Errorf("cannot call Getwd - %w", err)) + return "", err } dirInSysrootName := sysroot.GetDirNameInSysroot() - sysrootDir := filepath.Join(workingDir, sysrootDirectoryName, dirInSysrootName) - return sysrootDir + return filepath.Join(baseSysrootPath, dirInSysrootName), nil } // CreateSysrootDir -// Creates a Sysroot dir. If not succeed the panic occurrs. -func (sysroot *Sysroot) CreateSysrootDir() { +// Creates a Sysroot dir. If not succeed returns error. +func (sysroot *Sysroot) CreateSysrootDir() error { var err error - sysPath := sysroot.GetSysrootPath() - if _, err = os.Stat(sysPath); os.IsNotExist(err) { - err = os.MkdirAll(sysPath, 0777) - if err != nil { - panic(fmt.Errorf("cannot create sysroot dir: '%s'", sysPath)) - } + sysPath, err := sysroot.GetSysrootPath() + if err != nil { + return err + } + err = os.MkdirAll(sysPath, sysrootDirPermissions) + if err != nil { + return fmt.Errorf("cannot create sysroot dir: '%s' - %w", sysPath, err) } + + return nil } // IsSysrootDirectoryEmpty // Returns true if specified dir do not exists or exists but is empty, otherwise returns false. func (sysroot *Sysroot) IsSysrootDirectoryEmpty() bool { - f, err := os.Open(sysroot.GetSysrootPath()) + sysrootPath, err := sysroot.GetSysrootPath() + if err != nil { + return true + } + f, err := os.Open(sysrootPath) if err != nil { // The directory do not exists return true } diff --git a/internal/sysroot/default_test.go b/internal/sysroot/default_test.go index 162d9f5..0e06b5e 100644 --- a/internal/sysroot/default_test.go +++ b/internal/sysroot/default_test.go @@ -12,9 +12,7 @@ import ( ) const ( - sysrootDir = "test_sysroot" gitUri = "git_uri" - gitCommitHash = "hash" sysrootDirName = "machine-distro-1.0" ) @@ -93,11 +91,14 @@ func TestInitialize(t *testing.T) { } func TestGetSysrootPath(t *testing.T) { - sysrootPath := defaultSysroot.GetSysrootPath() + sysrootPath, err := defaultSysroot.GetSysrootPath() + if err != nil { + t.Fatalf("GetSysrootPath failed - %s", err) + } workingDir, err := os.Getwd() if err != nil { - t.Fatalf("can't get workinǵ dir - %s", err) + t.Fatalf("can't get working dir - %s", err) } testPath := filepath.Join(workingDir, sysrootDirectoryName, defaultSysroot.PlatformString.Serialize()) @@ -107,9 +108,12 @@ func TestGetSysrootPath(t *testing.T) { } func TestCreateSysrootDir(t *testing.T) { - sysrootPath := defaultSysroot.GetSysrootPath() + sysrootPath, err := defaultSysroot.GetSysrootPath() + if err != nil { + t.Fatalf("GetSysrootPath failed - %s", err) + } - err := os.RemoveAll(sysrootPath) + err = os.RemoveAll(sysrootPath) if err != nil { t.Fatalf("can't remove sysroot dir - %s", err) } @@ -135,8 +139,12 @@ func TestCopyToSysrootOnePackage(t *testing.T) { if err != nil { t.Errorf("CopyToSysroot failed - %s", err) } + sysrootPath, err := defaultSysroot.GetSysrootPath() + if err != nil { + t.Fatalf("GetSysrootPath failed - %s", err) + } - pack1Path := filepath.Join(defaultSysroot.GetSysrootPath(), testtools.Pack1FileName) + pack1Path := filepath.Join(sysrootPath, testtools.Pack1FileName) _, err = os.ReadFile(pack1Path) if os.IsNotExist(err) { t.Fail() @@ -163,20 +171,24 @@ func TestCopyToSysrootMultiplePackages(t *testing.T) { if err != nil { t.Errorf("CopyToSysroot failed - %s", err) } + sysrootPath, err := defaultSysroot.GetSysrootPath() + if err != nil { + t.Fatalf("GetSysrootPath failed - %s", err) + } - pack1Path := filepath.Join(defaultSysroot.GetSysrootPath(), testtools.Pack1FileName) + pack1Path := filepath.Join(sysrootPath, testtools.Pack1FileName) _, err = os.ReadFile(pack1Path) if os.IsNotExist(err) { t.Fail() } - pack2Path := filepath.Join(defaultSysroot.GetSysrootPath(), testtools.Pack2FileName) + pack2Path := filepath.Join(sysrootPath, testtools.Pack2FileName) _, err = os.ReadFile(pack2Path) if os.IsNotExist(err) { t.Fail() } - pack3Path := filepath.Join(defaultSysroot.GetSysrootPath(), testtools.Pack3FileName) + pack3Path := filepath.Join(sysrootPath, testtools.Pack3FileName) _, err = os.ReadFile(pack3Path) if os.IsNotExist(err) { t.Fail() @@ -268,6 +280,9 @@ func TestIsPackageInSysrootDifferentHash(t *testing.T) { } func clearSysroot() error { - sysrootPath := defaultSysroot.GetSysrootPath() + sysrootPath, err := defaultSysroot.GetSysrootPath() + if err != nil { + return err + } return os.RemoveAll(filepath.Dir(sysrootPath)) } From ee61069bfbe18f44fe2159e054da6b351652e78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20=C5=A0=C5=A5astn=C3=BD?= Date: Fri, 30 Jan 2026 12:52:00 +0100 Subject: [PATCH 2/4] Fix docker volumes for SELinux systems --- internal/docker/DockerRun.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/docker/DockerRun.go b/internal/docker/DockerRun.go index a44fd52..0379eab 100644 --- a/internal/docker/DockerRun.go +++ b/internal/docker/DockerRun.go @@ -69,7 +69,7 @@ func (runArgs *DockerRun) GenerateCmdLine() ([]string, error) { cmdArgs = append(cmdArgs, "-p") cmdArgs = append(cmdArgs, portPair) for key, value := range runArgs.Volumes { - volumePair := key + ":" + value + volumePair := key + ":" + value + ":Z" // :Z is for SELinux relabeling cmdArgs = append(cmdArgs, "-v", volumePair) } From e22de163055e4bc65c7fd7dc2a844da2f378d0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20=C5=A0=C5=A5astn=C3=BD?= Date: Fri, 30 Jan 2026 14:29:43 +0100 Subject: [PATCH 3/4] Adjust stop+remove container behavior Remove unnecessary sleep and add check for empty containerID. --- internal/build/Build.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/build/Build.go b/internal/build/Build.go index 00d9309..1edce00 100644 --- a/internal/build/Build.go +++ b/internal/build/Build.go @@ -202,16 +202,16 @@ func (build *Build) RunBuild() (error, bool) { // Long function - it is hard to shellEvaluator.StdOut = file } - dockerRun := (*docker.DockerRun)(build.Docker) - removeHandler := dockerRun.GetUndoHandler() - defer removeHandler() - logger.InfoIndent("Starting docker container") + dockerRun := (*docker.DockerRun)(build.Docker) err = dockerRun.Run() if err != nil { return err, false } + removeHandler := dockerRun.GetUndoHandler() + defer removeHandler() + build.SSHCredentials.Port = build.Docker.Port logger.InfoIndent("Cloning Package git repository inside docker container") From dfb5169b616e6b80cf27fe9a03b45f1e07345434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikul=C3=A1=C5=A1=20=C5=A0=C5=A5astn=C3=BD?= Date: Fri, 6 Feb 2026 16:26:41 +0100 Subject: [PATCH 4/4] Change sysroot dir permission flag --- internal/sysroot/Sysroot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/sysroot/Sysroot.go b/internal/sysroot/Sysroot.go index 054e7a8..9783405 100644 --- a/internal/sysroot/Sysroot.go +++ b/internal/sysroot/Sysroot.go @@ -16,7 +16,7 @@ import ( const ( sysrootDirectoryName = "install_sysroot" - sysrootDirPermissions = 0777 + sysrootDirPermissions = 0755 // Constant for number of problematic files which will be printed when trying to overwrite files // in sysroot listFilesCount = 10