|
|
|
@ -16,6 +16,59 @@ import (
|
|
|
|
|
"github.com/ztrue/tracerr" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type Opts struct { |
|
|
|
|
Context string //Directory where sources are located
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func downloadHTTPFunc(src SourceDescription) error { |
|
|
|
|
tmpFile, err := ioutil.TempFile(os.TempDir(), ".sourceHTTP") |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
resp, err := http.Get(src.Source) |
|
|
|
|
defer func() { |
|
|
|
|
_ = tmpFile.Close() |
|
|
|
|
_ = os.Remove(tmpFile.Name()) |
|
|
|
|
_ = resp.Close |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if _, err := io.Copy(tmpFile, resp.Body); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if src.IsArchive { |
|
|
|
|
logrus.Infof("Extracting archive into %s", src.Target) |
|
|
|
|
compressor := oci.ArchiveCompressorNone |
|
|
|
|
if strings.Contains(src.Source, "gz") { |
|
|
|
|
compressor = oci.ArchiveCompressorGzip |
|
|
|
|
} |
|
|
|
|
rd, err := oci.NewTarReader(compressor, tmpFile.Name()) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.ExtractTreeInto(src.Target); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.Close(); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
if _, err = fileutils.CopyFile(tmpFile.Name(), src.Target); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func InstallSourcesInsideZone(config Image) error { |
|
|
|
|
for _, src := range config.Sources { |
|
|
|
|
switch src.Type { |
|
|
|
@ -29,79 +82,46 @@ func InstallSourcesInsideZone(config Image) error {
|
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if src.Target[len(src.Target)-1] == '/' || src.IsArchive { |
|
|
|
|
if src.IsArchive { |
|
|
|
|
logrus.Infof("Extracting archive %s to %s", src.Name, src.Target) |
|
|
|
|
compressor := oci.ArchiveCompressorNone |
|
|
|
|
if strings.Contains(src.Source, "gz") { |
|
|
|
|
if strings.HasSuffix(src.Source, ".gz") { |
|
|
|
|
compressor = oci.ArchiveCompressorGzip |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rd, err := oci.NewTarReader(compressor, absSRC) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.ExtractTreeInto(src.Target); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.Close(); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = os.Remove(src.Source); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Info("successful") |
|
|
|
|
} |
|
|
|
|
case SourceTypeHttp: |
|
|
|
|
f := func(src SourceDescription) error { |
|
|
|
|
tmpFile, err := ioutil.TempFile(os.TempDir(), ".sourceHTTP") |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
resp, err := http.Get(src.Source) |
|
|
|
|
defer func() { |
|
|
|
|
_ = tmpFile.Close() |
|
|
|
|
_ = os.Remove(tmpFile.Name()) |
|
|
|
|
_ = resp.Close |
|
|
|
|
}() |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
if _, err := io.Copy(tmpFile, resp.Body); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if src.IsArchive { |
|
|
|
|
logrus.Infof("Extracting archive into %s", src.Target) |
|
|
|
|
compressor := oci.ArchiveCompressorNone |
|
|
|
|
if strings.Contains(src.Source, "gz") { |
|
|
|
|
compressor = oci.ArchiveCompressorGzip |
|
|
|
|
} |
|
|
|
|
rd, err := oci.NewTarReader(compressor, tmpFile.Name()) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
if err = rd.ExtractTreeInto(src.Target); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
if err = rd.Close(); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if _, err = fileutils.CopyFile(tmpFile.Name(), src.Target); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
case SourceTypeHttp: |
|
|
|
|
logrus.Infof("Downloading http(s) source %s from %s", src.Name, src.Source) |
|
|
|
|
if err := f(src); err != nil { |
|
|
|
|
return err |
|
|
|
|
if err := downloadHTTPFunc(src); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Info("successful") |
|
|
|
|
case SourceTypeGit: |
|
|
|
|
git, err := exec.LookPath("git") |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var repo, branch string |
|
|
|
|
if idx := strings.Index(src.Source, "@"); idx >= 0 { |
|
|
|
|
repo, branch = src.Source[:idx], src.Source[idx+1:] |
|
|
|
@ -109,58 +129,72 @@ func InstallSourcesInsideZone(config Image) error {
|
|
|
|
|
repo = src.Source |
|
|
|
|
branch = "master" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Infof("Cloning git repo %s", src.Source) |
|
|
|
|
gitCmd := exec.Command(git, "clone", "--single-branch", "-b", branch, repo, src.Target) |
|
|
|
|
if out, err := gitCmd.CombinedOutput(); err != nil { |
|
|
|
|
logrus.Errorf("failed git clone %s", out) |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Info("successful") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func CopySourcesIntoZone(config Image, zonepath string, allowLocal bool) error { |
|
|
|
|
func CopySourcesIntoZone(config Image, zonepath string, allowLocal bool, buildOpts Opts) error { |
|
|
|
|
for i, src := range config.Sources { |
|
|
|
|
if !allowLocal { |
|
|
|
|
logrus.Debugf("local file source not allowed on this host ignoring Source %s", src.Name) |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch src.Type { |
|
|
|
|
case SourceTypeFile: |
|
|
|
|
logrus.Infof("Copying local file %s into zonepath %s", src.Name, zonepath) |
|
|
|
|
absSRC, err := filepath.Abs(src.Source) |
|
|
|
|
absSRC, err := filepath.Abs(filepath.Join(buildOpts.Context, src.Source)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if src.Target[len(src.Target)-1] == '/' || src.IsArchive { |
|
|
|
|
if src.IsArchive { |
|
|
|
|
if src.IsRoot { |
|
|
|
|
//TODO move this code into the zone context by implementing podinit and empty container base
|
|
|
|
|
logrus.Infof("Extracting Rootfilesystem into %s, inside %s", src.Target, zonepath) |
|
|
|
|
absTarget, err := filepath.Abs(zonepath + "/root/" + src.Target) |
|
|
|
|
absTarget, err := filepath.Abs(filepath.Join(zonepath, "root", src.Target)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
compressor := oci.ArchiveCompressorNone |
|
|
|
|
if strings.Contains(src.Source, "gz") { |
|
|
|
|
compressor = oci.ArchiveCompressorGzip |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rd, err := oci.NewTarReader(compressor, absSRC) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.ExtractTreeInto(absTarget); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = rd.Close(); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Info("successful") |
|
|
|
|
} else { |
|
|
|
|
logrus.Debugf("Copying archive %s into zonepath %s", src.Source, zonepath) |
|
|
|
|
src.Source = fmt.Sprintf("/.sourceArchive.%d", i) |
|
|
|
|
absTarget, err := filepath.Abs(zonepath + src.Source) |
|
|
|
|
if strings.HasSuffix(src.Source, ".gz") { |
|
|
|
|
src.Source = fmt.Sprintf("/.sourceArchive.%d.gz", i) |
|
|
|
|
} else { |
|
|
|
|
src.Source = fmt.Sprintf("/.sourceArchive.%d", i) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
absTarget, err := filepath.Abs(filepath.Join(zonepath, "root", src.Source)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
@ -173,7 +207,7 @@ func CopySourcesIntoZone(config Image, zonepath string, allowLocal bool) error {
|
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
logrus.Debugf("Copying file %s into zonepath %s", src.Source, zonepath) |
|
|
|
|
absTarget, err := filepath.Abs(zonepath + "/" + src.Target) |
|
|
|
|
absTarget, err := filepath.Abs(filepath.Join(zonepath, "root", src.Target)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
@ -181,8 +215,47 @@ func CopySourcesIntoZone(config Image, zonepath string, allowLocal bool) error {
|
|
|
|
|
if _, err = fileutils.CopyFile(absSRC, absTarget); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case SourceTypeDirectory: |
|
|
|
|
// Create a tar archive of the directory and copy it into the zone
|
|
|
|
|
absSRC, err := filepath.Abs(filepath.Join(buildOpts.Context, src.Source)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
src.Source = fmt.Sprintf("/.sourceArchive.%d.tar.gz", i) |
|
|
|
|
src.IsArchive = true |
|
|
|
|
src.Type = SourceTypeFile |
|
|
|
|
|
|
|
|
|
err = func() error { |
|
|
|
|
f, err := os.Create(filepath.Join(zonepath, "root", src.Source)) |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
defer f.Close() |
|
|
|
|
|
|
|
|
|
wr, err := oci.NewTarWriter(oci.ArchiveCompressorGzip, f) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := wr.AddTree(absSRC, src.Target); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := wr.Close(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
}() |
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
config.Sources[i] = src |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
@ -204,14 +277,15 @@ func CopyFilesBetweenImages(config CopyOperation, srcImagePath, destImagePath st
|
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Debugf("Copying %s -> %s", absSRC, absTgt) |
|
|
|
|
if _, err := fileutils.CopyFile(absSRC, absTgt); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Debugf("Done") |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
func PerformActions(imageConfig Image) error { |
|
|
|
|
for _, act := range imageConfig.Actions { |
|
|
|
|
if act.Provide { |
|
|
|
@ -227,7 +301,23 @@ func PerformActions(imageConfig Image) error {
|
|
|
|
|
if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
//Make non executable files executable. We assume that this was a user error
|
|
|
|
|
stat, err := os.Stat(cmdBin) |
|
|
|
|
if err != nil && os.IsNotExist(err) { |
|
|
|
|
logrus.Debugf("Tried to call nonexitent binary %s", cmdBin) |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} else if err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !IsExecAny(stat.Mode()) { |
|
|
|
|
if err := os.Chmod(cmdBin, stat.Mode()|0111); err != nil { |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cmd := exec.Command(cmdBin, cmdArg...) |
|
|
|
|
cmd.Stdout = os.Stdout |
|
|
|
|
cmd.Stderr = os.Stderr |
|
|
|
@ -237,6 +327,7 @@ func PerformActions(imageConfig Image) error {
|
|
|
|
|
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//OK to whoever got the idea that the locale should determine the encoding of any file you open with your program
|
|
|
|
|
// screw you. I am talking to you Python, Ruby and Perl....
|
|
|
|
|
cmd.Env = append(cmd.Env, "LANG=C.UTF-8") |
|
|
|
@ -246,7 +337,24 @@ func PerformActions(imageConfig Image) error {
|
|
|
|
|
logrus.Error("failed") |
|
|
|
|
return tracerr.Wrap(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logrus.Info("successful") |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func IsExecOwner(mode os.FileMode) bool { |
|
|
|
|
return mode&0100 != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func IsExecGroup(mode os.FileMode) bool { |
|
|
|
|
return mode&0010 != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func IsExecOther(mode os.FileMode) bool { |
|
|
|
|
return mode&0001 != 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func IsExecAny(mode os.FileMode) bool { |
|
|
|
|
return mode&0111 != 0 |
|
|
|
|
} |
|
|
|
|