Skip to content

Commit

Permalink
Change PACK_USER_GID to PACK_GROUP_ID in export
Browse files Browse the repository at this point in the history
Fallback to PACK_USER_GID if PACK_GROUP_ID is missing

[#50]
  • Loading branch information
dgodd committed Oct 18, 2018
1 parent d260352 commit b5d7f45
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 48 deletions.
36 changes: 23 additions & 13 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,12 @@ func (b *BuildConfig) Export(group *lifecycle.BuildpackGroup) error {
buildpacks = append(buildpacks, b.ID)
}

if err := exportDaemon(b.Cli, buildpacks, b.WorkspaceVolume, b.RepoName, b.RunImage, b.Stdout); err != nil {
uid, gid, err := b.packUidGid(b.RunImage)
if err != nil {
return errors.Wrap(err, "export")
}

if err := exportDaemon(b.Cli, buildpacks, b.WorkspaceVolume, b.RepoName, b.RunImage, b.Stdout, uid, gid); err != nil {
return err
}
}
Expand Down Expand Up @@ -456,25 +461,30 @@ func (b *BuildConfig) packUidGid(builder string) (int, int, error) {
if err != nil {
return 0, 0, errors.Wrap(err, "reading builder env variables")
}
var found, uid, gid int
var sUID, sGID string
for _, kv := range i.Config.Env {
kv2 := strings.SplitN(kv, "=", 2)
if len(kv2) == 2 && kv2[0] == "PACK_USER_ID" {
uid, err = strconv.Atoi(kv2[1])
if err != nil {
return 0, 0, errors.Wrapf(err, "parsing pack uid: %s", kv2[1])
}
found++
sUID = kv2[1]
} else if len(kv2) == 2 && kv2[0] == "PACK_GROUP_ID" {
sGID = kv2[1]
} else if len(kv2) == 2 && kv2[0] == "PACK_USER_GID" {
gid, err = strconv.Atoi(kv2[1])
if err != nil {
return 0, 0, errors.Wrapf(err, "parsing pack gid: %s", kv2[1])
if sGID == "" {
sGID = kv2[1]
}
found++
}
}
if found < 2 {
return uid, gid, errors.New("not found pack uid & gid")
if sUID == "" || sGID == "" {
return 0, 0, errors.New("not found pack uid & gid")
}
var uid, gid int
uid, err = strconv.Atoi(sUID)
if err != nil {
return 0, 0, errors.Wrapf(err, "parsing pack uid: %s", sUID)
}
gid, err = strconv.Atoi(sGID)
if err != nil {
return 0, 0, errors.Wrapf(err, "parsing pack gid: %s", sGID)
}
return uid, gid, nil
}
Expand Down
29 changes: 23 additions & 6 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,14 +517,14 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
assertContains(t, metadata.Buildpacks[0].Layers["other"].SHA, "sha256:")
})

it("sets owner of layer files to PACK_USER_ID:PACK_USER_GID", func() {
it("sets owner of layer files to PACK_USER_ID:PACK_GROUP_ID", func() {
subject.RunImage = "packs/run-" + randString(8)
defer exec.Command("docker", "rmi", subject.RunImage)
cmd := exec.Command("docker", "build", "-t", subject.RunImage, "-")
cmd.Stdin = strings.NewReader(`
FROM packs/run
ENV PACK_USER_ID 1234
ENV PACK_USER_GID 5678
ENV PACK_GROUP_ID 5678
`)
assertNil(t, cmd.Run())

Expand All @@ -541,20 +541,37 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
cmd.Stdin = strings.NewReader(`
FROM packs/run
ENV PACK_USER_ID ''
ENV PACK_USER_GID 5678
ENV PACK_GROUP_ID 5678
`)
assertNil(t, cmd.Run())

err := subject.Export(group)
assertError(t, err, "export uid/gid: could not find PACK_USER_ID && PACK_USER_GID from run image")
assertError(t, err, "export: not found pack uid & gid")
})

it("falls back to PACK_USER_GID sets owner of layer files", func() {
subject.RunImage = "packs/run-" + randString(8)
defer exec.Command("docker", "rmi", subject.RunImage)
cmd := exec.Command("docker", "build", "-t", subject.RunImage, "-")
cmd.Stdin = strings.NewReader(`
FROM packs/run
ENV PACK_USER_ID 1234
ENV PACK_USER_GID 5678
`)
assertNil(t, cmd.Run())

assertNil(t, subject.Export(group))
txt, err := exec.Command("docker", "run", subject.RepoName, "ls", "-la", "/workspace/app/file.txt").Output()
assertNil(t, err)
assertContains(t, string(txt), " 1234 5678 ")
})
})
})

when("previous image exists", func() {
it("reuses images from previous layers", func() {
addLayer := "ADD --chown=pack:pack /workspace/io.buildpacks.samples.nodejs/mylayer /workspace/io.buildpacks.samples.nodejs/mylayer"
copyLayer := "COPY --from=prev --chown=pack:pack /workspace/io.buildpacks.samples.nodejs/mylayer /workspace/io.buildpacks.samples.nodejs/mylayer"
addLayer := "ADD --chown=1000:1000 /workspace/io.buildpacks.samples.nodejs/mylayer /workspace/io.buildpacks.samples.nodejs/mylayer"
copyLayer := "COPY --from=prev --chown=1000:1000 /workspace/io.buildpacks.samples.nodejs/mylayer /workspace/io.buildpacks.samples.nodejs/mylayer"

t.Log("create image and assert add new layer")
assertNil(t, subject.Export(group))
Expand Down
33 changes: 4 additions & 29 deletions exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import (
"github.com/buildpack/pack/fs"
"github.com/buildpack/pack/image"
"github.com/buildpack/packs"

"github.com/buildpack/packs"
)

func exportRegistry(group *lifecycle.BuildpackGroup, workspaceDir, repoName, stackName string, stdout, stderr io.Writer) (string, error) {
Expand Down Expand Up @@ -75,26 +73,7 @@ func exportRegistry(group *lifecycle.BuildpackGroup, workspaceDir, repoName, sta
return sha.String(), nil
}

func runImageUIDGID(cli Docker, ctx context.Context, runImage string) (string, error) {
i, _, err := cli.ImageInspectWithRaw(ctx, runImage)
if err != nil {
return "", errors.Wrap(err, "inspect image to find UID & GID")
}
var uid, gid string
for _, e := range i.Config.Env {
if strings.HasPrefix(e, "PACK_USER_ID=") {
uid = e[13:]
} else if strings.HasPrefix(e, "PACK_USER_GID=") {
gid = e[14:]
}
}
if uid == "" || gid == "" {
return "", errors.New("could not find PACK_USER_ID && PACK_USER_GID from run image")
}
return uid + ":" + gid, nil
}

func exportDaemon(cli Docker, buildpacks []string, workspaceVolume, repoName, runImage string, stdout io.Writer) error {
func exportDaemon(cli Docker, buildpacks []string, workspaceVolume, repoName, runImage string, stdout io.Writer, uid, gid int) error {
ctx := context.Background()
ctr, err := cli.ContainerCreate(ctx, &container.Config{
Image: runImage,
Expand All @@ -115,12 +94,7 @@ func exportDaemon(cli Docker, buildpacks []string, workspaceVolume, repoName, ru
return errors.Wrap(err, "copy from container")
}

chownUser, err := runImageUIDGID(cli, ctx, runImage)
if err != nil {
return errors.Wrap(err, "export uid/gid")
}

r2, layerChan, errChan := addDockerfileToTar(chownUser, runImage, repoName, buildpacks, r)
r2, layerChan, errChan := addDockerfileToTar(uid, gid, runImage, repoName, buildpacks, r)

res, err := cli.ImageBuild(ctx, r2, dockertypes.ImageBuildOptions{Tags: []string{repoName}})
if err != nil {
Expand Down Expand Up @@ -209,7 +183,8 @@ type dockerfileLayer struct {
data interface{}
}

func addDockerfileToTar(chownUser, runImage, repoName string, buildpacks []string, r io.Reader) (io.Reader, chan []dockerfileLayer, chan error) {
func addDockerfileToTar(uid, gid int, runImage, repoName string, buildpacks []string, r io.Reader) (io.Reader, chan []dockerfileLayer, chan error) {
chownUser := fmt.Sprintf("%d:%d", uid, gid)
dockerFile := "FROM " + runImage + "\n"
dockerFile += fmt.Sprintf("ADD --chown=%s /workspace/app /workspace/app\n", chownUser)
dockerFile += fmt.Sprintf("ADD --chown=%s /workspace/config /workspace/config\n", chownUser)
Expand Down

0 comments on commit b5d7f45

Please sign in to comment.