Merge pull request #1275 from samalba/engine-push

Support for engine.#Push
This commit is contained in:
Andrea Luzzardi 2021-12-21 13:49:11 +01:00 committed by GitHub
commit 074dfcbdf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 159 additions and 1 deletions

87
plan/task/push.go Normal file
View File

@ -0,0 +1,87 @@
package task
import (
"context"
"fmt"
"github.com/docker/distribution/reference"
bk "github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
"github.com/rs/zerolog/log"
"go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/plancontext"
"go.dagger.io/dagger/solver"
)
func init() {
Register("Push", func() Task { return &pushTask{} })
}
type pushTask struct {
}
func (c *pushTask) Run(ctx context.Context, pctx *plancontext.Context, s solver.Solver, v *compiler.Value) (*compiler.Value, error) {
lg := log.Ctx(ctx)
rawDest, err := v.Lookup("dest").String()
if err != nil {
return nil, err
}
dest, err := reference.ParseNormalizedNamed(rawDest)
if err != nil {
return nil, fmt.Errorf("failed to parse ref %s: %w", rawDest, err)
}
// Add the default tag "latest" to a reference if it only has a repo name.
dest = reference.TagNameOnly(dest)
// Read auth info
auth, err := decodeAuthValue(pctx, v.Lookup("auth"))
if err != nil {
return nil, err
}
for _, a := range auth {
s.AddCredentials(a.Target, a.Username, a.Secret.PlainText())
lg.Debug().Str("target", a.Target).Msg("add target credentials")
}
// Get input state
input, err := pctx.FS.FromValue(v.Lookup("input"))
if err != nil {
return nil, err
}
st, err := input.Result().ToState()
if err != nil {
return nil, err
}
// Decode the image config
imageConfig := dockerfile2llb.ImageConfig{}
if err := v.Lookup("config").Decode(&imageConfig); err != nil {
return nil, err
}
// Export image
lg.Debug().Str("dest", dest.String()).Msg("export image")
resp, err := s.Export(ctx, st, &dockerfile2llb.Image{Config: imageConfig}, bk.ExportEntry{
Type: bk.ExporterImage,
Attrs: map[string]string{
"name": dest.String(),
"push": "true",
},
}, pctx.Platform.Get())
if err != nil {
return nil, err
}
digest, hasImageDigest := resp.ExporterResponse["containerimage.digest"]
if !hasImageDigest {
return nil, fmt.Errorf("image push target %q did not return an image digest", dest.String())
}
imageRef := fmt.Sprintf("%s@%s", resp.ExporterResponse["image.name"], digest)
// Fill result
return compiler.NewValue().FillFields(map[string]interface{}{
"result": imageRef,
})
}

View File

@ -2,7 +2,6 @@ package engine
// Upload a container image to a remote repository
#Push: {
@dagger(notimplemented)
$dagger: task: _name: "Push"
// Target repository address

View File

@ -14,6 +14,11 @@ setup() {
"$DAGGER" --europa up ./pull_auth.cue
}
@test "task: #Push" {
cd "$TESTDIR"/tasks/push
"$DAGGER" --europa up ./push.cue
}
@test "task: #ReadFile" {
cd "$TESTDIR"/tasks/readfile
"$DAGGER" --europa up

67
tests/tasks/push/push.cue Normal file
View File

@ -0,0 +1,67 @@
package main
import (
"strings"
"alpha.dagger.io/europa/dagger/engine"
)
engine.#Plan & {
inputs: secrets: dockerHubToken: envvar: "DOCKERHUB_TOKEN"
#auth: [{
target: "daggerio/ci-test:private-pull"
username: "daggertest"
secret: inputs.secrets.dockerHubToken.contents
}]
actions: {
randomString: {
baseImage: engine.#Pull & {
source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3"
}
image: engine.#Exec & {
input: baseImage.output
args: [
"sh", "-c", "echo -n $RANDOM > /output.txt",
]
}
outputFile: engine.#ReadFile & {
input: image.output
path: "/output.txt"
}
output: outputFile.contents
}
// Push image with random content
push: engine.#Push & {
dest: "daggerio/ci-test:\(randomString.output)"
input: randomString.image.output
config: Env: ["FOO=\(randomString.output)"]
auth: #auth
}
// Pull same image and check the content
pull: engine.#Pull & {
source: "daggerio/ci-test:\(randomString.output)"
auth: #auth
} & {
// check digest
digest: strings.Split(push.result, "@")[1]
// check image config
config: {
Env: ["FOO=\(randomString.output)"]
}
}
pullOutputFile: engine.#ReadFile & {
input: pull.output
path: "/output.txt"
}
// Check output file in the pulled image
pullContent: string & pullOutputFile.contents & randomString.contents
}
}