Merge pull request #1056 from aluzzardi/docker-load
Support loading artifacts into a Docker Engine
This commit is contained in:
commit
16b14524d5
@ -144,6 +144,16 @@ _No input._
|
|||||||
|
|
||||||
_No output._
|
_No output._
|
||||||
|
|
||||||
|
## op.#SaveImage
|
||||||
|
|
||||||
|
### op.#SaveImage Inputs
|
||||||
|
|
||||||
|
_No input._
|
||||||
|
|
||||||
|
### op.#SaveImage Outputs
|
||||||
|
|
||||||
|
_No output._
|
||||||
|
|
||||||
## op.#Subdir
|
## op.#Subdir
|
||||||
|
|
||||||
### op.#Subdir Inputs
|
### op.#Subdir Inputs
|
||||||
|
@ -31,15 +31,29 @@ A container image that can run any docker command
|
|||||||
|
|
||||||
### docker.#Command Inputs
|
### docker.#Command Inputs
|
||||||
|
|
||||||
| Name | Type | Description |
|
_No input._
|
||||||
| ------------- |:-------------: |:-------------: |
|
|
||||||
|*command* | `string` |Command to execute |
|
|
||||||
|*registries* | `[]` |Image registries |
|
|
||||||
|
|
||||||
### docker.#Command Outputs
|
### docker.#Command Outputs
|
||||||
|
|
||||||
_No output._
|
_No output._
|
||||||
|
|
||||||
|
## docker.#Load
|
||||||
|
|
||||||
|
Load a docker image into a docker engine
|
||||||
|
|
||||||
|
### docker.#Load Inputs
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------------- |:-------------: |:-------------: |
|
||||||
|
|*tag* | `string` |Name and optionally a tag in the 'name:tag' format |
|
||||||
|
|*source* | `dagger.#Artifact` |Image source |
|
||||||
|
|
||||||
|
### docker.#Load Outputs
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ------------- |:-------------: |:-------------: |
|
||||||
|
|*id* | `string` |Image ID |
|
||||||
|
|
||||||
## docker.#Pull
|
## docker.#Pull
|
||||||
|
|
||||||
Pull a docker container
|
Pull a docker container
|
||||||
@ -79,9 +93,7 @@ Push a docker image to a remote registry
|
|||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ------------- |:-------------: |:-------------: |
|
| ------------- |:-------------: |:-------------: |
|
||||||
|*ref* | `string` |Image reference (e.g: nginx:alpine) |
|
|*ref* | `string` |Image reference (e.g: nginx:alpine) |
|
||||||
|*run.command* | `"""\n # Run detach container\n OPTS=""\n \n if [ ! -z "$CONTAINER_NAME" ]; then\n \tOPTS="$OPTS --name $CONTAINER_NAME"\n fi\n \n if [ ! -z "$CONTAINER_PORTS" ]; then\n \tOPTS="$OPTS -p $CONTAINER_PORTS"\n fi\n \n docker container run -d $OPTS "$IMAGE_REF"\n """` |Command to execute |
|
|
||||||
|*run.env.IMAGE_REF* | `string` |- |
|
|*run.env.IMAGE_REF* | `string` |- |
|
||||||
|*run.registries* | `[]` |Image registries |
|
|
||||||
|
|
||||||
### docker.#Run Outputs
|
### docker.#Run Outputs
|
||||||
|
|
||||||
|
@ -14,14 +14,10 @@ import "alpha.dagger.io/docker/compose"
|
|||||||
|
|
||||||
### compose.#App Inputs
|
### compose.#App Inputs
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ------------- |:-------------: |:-------------: |
|
| ------------- |:-------------: |:-------------: |
|
||||||
|*name* | `*"source" \| string` |App name (use as COMPOSE_PROJECT_NAME) |
|
|*name* | `*"source" \| string` |App name (use as COMPOSE_PROJECT_NAME) |
|
||||||
|*registries* | `[]` |Image registries |
|
|*registries* | `[]` |Image registries |
|
||||||
|*run.command* | `"""\n if [ -n "$DOCKER_HOSTNAME" ]; then\n \tssh -i /key -fNT -o "StreamLocalBindUnlink=yes" -L "$(pwd)"/docker.sock:/var/run/docker.sock -p "$DOCKER_PORT" "$DOCKER_USERNAME"@"$DOCKER_HOSTNAME"\n \texport DOCKER_HOST="unix://$(pwd)/docker.sock"\n fi\n \n # Extend session duration\n echo "Host *\\nServerAliveInterval 240" \>\> "$HOME"/.ssh/config\n chmod 600 "$HOME"/.ssh/config\n \n # Move compose\n if [ -d "$SOURCE_DIR" ]; then\n \tif [ -f docker-compose.yaml ]; then\n \t\tcp docker-compose.yaml "$SOURCE_DIR"/docker-compose.yaml\n \tfi\n \tcd "$SOURCE_DIR"\n fi\n \n docker-compose build\n docker-compose up -d\n """` |Command to execute |
|
|
||||||
|*run.env.COMPOSE_PROJECT_NAME* | `*"source" \| string` |- |
|
|
||||||
|*run.package."docker-compose"* | `true` |- |
|
|
||||||
|*run.registries* | `[]` |Image registries |
|
|
||||||
|
|
||||||
### compose.#App Outputs
|
### compose.#App Outputs
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -261,6 +262,8 @@ func (p *Pipeline) doOp(ctx context.Context, op *compiler.Value, st llb.State) (
|
|||||||
return p.FetchContainer(ctx, op, st)
|
return p.FetchContainer(ctx, op, st)
|
||||||
case "push-container":
|
case "push-container":
|
||||||
return p.PushContainer(ctx, op, st)
|
return p.PushContainer(ctx, op, st)
|
||||||
|
case "save-image":
|
||||||
|
return p.SaveImage(ctx, op, st)
|
||||||
case "fetch-git":
|
case "fetch-git":
|
||||||
return p.FetchGit(ctx, op, st)
|
return p.FetchGit(ctx, op, st)
|
||||||
case "fetch-http":
|
case "fetch-http":
|
||||||
@ -872,6 +875,63 @@ func (p *Pipeline) PushContainer(ctx context.Context, op *compiler.Value, st llb
|
|||||||
return st, err
|
return st, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Pipeline) SaveImage(ctx context.Context, op *compiler.Value, st llb.State) (llb.State, error) {
|
||||||
|
tag, err := op.Lookup("tag").String()
|
||||||
|
if err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dest, err := op.Lookup("dest").String()
|
||||||
|
if err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeR, pipeW := io.Pipe()
|
||||||
|
var (
|
||||||
|
errCh = make(chan error)
|
||||||
|
image []byte
|
||||||
|
)
|
||||||
|
go func() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
image, err = io.ReadAll(pipeR)
|
||||||
|
errCh <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := p.s.Export(ctx, p.State(), &p.image, bk.ExportEntry{
|
||||||
|
Type: bk.ExporterDocker,
|
||||||
|
Attrs: map[string]string{
|
||||||
|
"name": tag,
|
||||||
|
},
|
||||||
|
Output: func(_ map[string]string) (io.WriteCloser, error) {
|
||||||
|
return pipeW, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := <-errCh; err != nil {
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if id, ok := resp.ExporterResponse["containerimage.config.digest"]; ok {
|
||||||
|
st = st.File(
|
||||||
|
llb.Mkdir("/dagger", fs.FileMode(0755)),
|
||||||
|
llb.WithCustomName(p.vertexNamef("Mkdir /dagger")),
|
||||||
|
).File(
|
||||||
|
llb.Mkfile("/dagger/image_id", fs.FileMode(0644), []byte(id)),
|
||||||
|
llb.WithCustomName(p.vertexNamef("Storing image id to /dagger/image_id")),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return st.File(
|
||||||
|
llb.Mkfile(dest, 0644, image),
|
||||||
|
llb.WithCustomName(p.vertexNamef("SaveImage %s", dest)),
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
func getSecretID(secretField *compiler.Value) (string, error) {
|
func getSecretID(secretField *compiler.Value) (string, error) {
|
||||||
if !secretField.HasAttr("secret") {
|
if !secretField.HasAttr("secret") {
|
||||||
return "", fmt.Errorf("invalid secret %q: not a secret", secretField.Path().String())
|
return "", fmt.Errorf("invalid secret %q: not a secret", secretField.Path().String())
|
||||||
|
2
stdlib/.dagger/env/docker-load/.gitignore
vendored
Normal file
2
stdlib/.dagger/env/docker-load/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# dagger state
|
||||||
|
state/**
|
30
stdlib/.dagger/env/docker-load/values.yaml
vendored
Normal file
30
stdlib/.dagger/env/docker-load/values.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
plan:
|
||||||
|
package: ./docker/tests/load
|
||||||
|
name: docker-load
|
||||||
|
inputs:
|
||||||
|
dockersocket:
|
||||||
|
socket:
|
||||||
|
unix: /var/run/docker.sock
|
||||||
|
source:
|
||||||
|
dir:
|
||||||
|
path: ./docker/tests/load/testdata
|
||||||
|
sops:
|
||||||
|
kms: []
|
||||||
|
gcp_kms: []
|
||||||
|
azure_kv: []
|
||||||
|
hc_vault: []
|
||||||
|
age:
|
||||||
|
- recipient: age1gxwmtwahzwdmrskhf90ppwlnze30lgpm056kuesrxzeuyclrwvpsupwtpk
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzZCt6S3VGQkM4ZU9TamhQ
|
||||||
|
c2J0RDZpdzNQZUJ6V1BBdHh3M1NhTmJLeXpFCldaOVNUYVhWQW5ma3JGUk9XZWZ2
|
||||||
|
YjZIM0tMUGRoSk1QYTFkalA4S2N3UzAKLS0tIFhMeXMvaGM4UFllYWFCNWVUZFd5
|
||||||
|
U09jNHNlK094NGoyZnRlSk56T1N6K1EKJs5D3S2zPWNrGCyLWDDjq7Iif0m2JoL6
|
||||||
|
gqEjofnPSD7SjgfNKIpeOWcQ1sI7wmI4GGgaTpdhd431XxOn/fU44w==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2021-10-12T22:18:14Z"
|
||||||
|
mac: ENC[AES256_GCM,data:HjlY0FzB5hsg/VfyBbVTNWDCYV41lhPeyHOVrMdRWiOKJnV1aKGV1826fMXKcmgJK39kovcEXaXmVYOv3qtpDTlIMcOdoEflbDY/fhZmaDxxNq6QSkYfmadO84YWvS1FyouCPVZzRDe9tBdNyIT5cCx8CrgZ5bebh9aNem3lqRs=,iv:juMn1S06I5mZP8fWytn2eUkOvjNQepn6MAzDWvLxrWM=,tag:0BxrbK6EaoB44RgUHD+dpQ==,type:str]
|
||||||
|
pgp: []
|
||||||
|
encrypted_suffix: secret
|
||||||
|
version: 3.7.1
|
@ -81,6 +81,12 @@ package op
|
|||||||
ref: string
|
ref: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#SaveImage: {
|
||||||
|
do: "save-image"
|
||||||
|
tag: string
|
||||||
|
dest: string
|
||||||
|
}
|
||||||
|
|
||||||
#FetchGit: {
|
#FetchGit: {
|
||||||
do: "fetch-git"
|
do: "fetch-git"
|
||||||
remote: string
|
remote: string
|
||||||
|
@ -31,11 +31,11 @@ import (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Command to execute
|
// Command to execute
|
||||||
command: string @dagger(input)
|
command: string
|
||||||
|
|
||||||
// Environment variables shared by all commands
|
// Environment variables shared by all commands
|
||||||
env: {
|
env: {
|
||||||
[string]: string @dagger(input)
|
[string]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount content from other artifacts
|
// Mount content from other artifacts
|
||||||
@ -44,17 +44,17 @@ import (
|
|||||||
from: dagger.#Artifact
|
from: dagger.#Artifact
|
||||||
} | {
|
} | {
|
||||||
secret: dagger.#Secret
|
secret: dagger.#Secret
|
||||||
} @dagger(input)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount persistent cache directories
|
// Mount persistent cache directories
|
||||||
cache: {
|
cache: {
|
||||||
[string]: true @dagger(input)
|
[string]: true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount temporary directories
|
// Mount temporary directories
|
||||||
tmpfs: {
|
tmpfs: {
|
||||||
[string]: true @dagger(input)
|
[string]: true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount docker socket
|
// Mount docker socket
|
||||||
@ -62,7 +62,7 @@ import (
|
|||||||
|
|
||||||
// Additional packages to install
|
// Additional packages to install
|
||||||
package: {
|
package: {
|
||||||
[string]: true | false | string @dagger(input)
|
[string]: true | false | string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image registries
|
// Image registries
|
||||||
@ -70,7 +70,7 @@ import (
|
|||||||
target?: string
|
target?: string
|
||||||
username: string
|
username: string
|
||||||
secret: dagger.#Secret
|
secret: dagger.#Secret
|
||||||
}] @dagger(input)
|
}]
|
||||||
|
|
||||||
// Copy contents from other artifacts
|
// Copy contents from other artifacts
|
||||||
copy: [string]: from: dagger.#Artifact
|
copy: [string]: from: dagger.#Artifact
|
||||||
@ -98,7 +98,7 @@ import (
|
|||||||
ssh-add /key > /dev/null
|
ssh-add /key > /dev/null
|
||||||
if [ "$?" != 0 ]; then
|
if [ "$?" != 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -z $FINGERPRINT ]]; then
|
if [[ ! -z $FINGERPRINT ]]; then
|
||||||
@ -131,7 +131,7 @@ import (
|
|||||||
for registry in registries {
|
for registry in registries {
|
||||||
op.#Exec & {
|
op.#Exec & {
|
||||||
args: ["/bin/bash", "-c", #"""
|
args: ["/bin/bash", "-c", #"""
|
||||||
echo "$TARGER_HOST" | docker login --username "$DOCKER_USERNAME" --password-stdin "$(cat /password)"
|
echo "$TARGER_HOST" | docker login --username "$DOCKER_USERNAME" --password-stdin "$(cat /password)"
|
||||||
"""#,
|
"""#,
|
||||||
]
|
]
|
||||||
env: {
|
env: {
|
||||||
|
@ -101,6 +101,74 @@ import (
|
|||||||
} & dagger.#Output
|
} & dagger.#Output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load a docker image into a docker engine
|
||||||
|
#Load: {
|
||||||
|
// Connect to a remote SSH server
|
||||||
|
ssh?: {
|
||||||
|
// ssh host
|
||||||
|
host: dagger.#Input & {string}
|
||||||
|
|
||||||
|
// ssh user
|
||||||
|
user: dagger.#Input & {string}
|
||||||
|
|
||||||
|
// ssh port
|
||||||
|
port: dagger.#Input & {*22 | int}
|
||||||
|
|
||||||
|
// private key
|
||||||
|
key: dagger.#Input & {dagger.#Secret}
|
||||||
|
|
||||||
|
// fingerprint
|
||||||
|
fingerprint?: dagger.#Input & {string}
|
||||||
|
|
||||||
|
// ssh key passphrase
|
||||||
|
keyPassphrase?: dagger.#Input & {dagger.#Secret}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mount local docker socket
|
||||||
|
socket?: dagger.#Stream & dagger.#Input
|
||||||
|
|
||||||
|
// Name and optionally a tag in the 'name:tag' format
|
||||||
|
tag: dagger.#Input & {string}
|
||||||
|
|
||||||
|
// Image source
|
||||||
|
source: dagger.#Input & {dagger.#Artifact}
|
||||||
|
|
||||||
|
save: #up: [
|
||||||
|
op.#Load & {from: source},
|
||||||
|
|
||||||
|
op.#SaveImage & {
|
||||||
|
"tag": tag
|
||||||
|
dest: "/image.tar"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
load: #Command & {
|
||||||
|
if ssh != _|_ {
|
||||||
|
"ssh": ssh
|
||||||
|
}
|
||||||
|
if socket != _|_ {
|
||||||
|
"socket": socket
|
||||||
|
}
|
||||||
|
|
||||||
|
copy: "/src": from: save
|
||||||
|
|
||||||
|
command: "docker load -i /src/image.tar"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image ID
|
||||||
|
id: {
|
||||||
|
string
|
||||||
|
|
||||||
|
#up: [
|
||||||
|
op.#Load & {from: save},
|
||||||
|
|
||||||
|
op.#Export & {
|
||||||
|
source: "/dagger/image_id"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} & dagger.#Output
|
||||||
|
}
|
||||||
|
|
||||||
#Run: {
|
#Run: {
|
||||||
// Connect to a remote SSH server
|
// Connect to a remote SSH server
|
||||||
ssh?: {
|
ssh?: {
|
||||||
|
32
stdlib/docker/tests/load/load.cue
Normal file
32
stdlib/docker/tests/load/load.cue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"alpha.dagger.io/dagger"
|
||||||
|
"alpha.dagger.io/random"
|
||||||
|
)
|
||||||
|
|
||||||
|
dockersocket: dagger.#Stream & dagger.#Input
|
||||||
|
|
||||||
|
source: dagger.#Artifact & dagger.#Input
|
||||||
|
|
||||||
|
TestLoad: {
|
||||||
|
suffix: random.#String & {
|
||||||
|
seed: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
image: #Build & {
|
||||||
|
"source": source
|
||||||
|
}
|
||||||
|
|
||||||
|
load: #Load & {
|
||||||
|
tag: "daggerci-image-load-\(suffix.out)"
|
||||||
|
source: image
|
||||||
|
socket: dockersocket
|
||||||
|
}
|
||||||
|
|
||||||
|
run: #Run & {
|
||||||
|
name: "daggerci-container-load-\(suffix.out)"
|
||||||
|
ref: load.id
|
||||||
|
socket: dockersocket
|
||||||
|
}
|
||||||
|
}
|
2
stdlib/docker/tests/load/testdata/Dockerfile
vendored
Normal file
2
stdlib/docker/tests/load/testdata/Dockerfile
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
FROM alpine
|
||||||
|
RUN echo test >> /test.txt
|
@ -126,6 +126,10 @@ setup() {
|
|||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "docker load" {
|
||||||
|
dagger -e docker-load up
|
||||||
|
}
|
||||||
|
|
||||||
@test "docker compose" {
|
@test "docker compose" {
|
||||||
dagger -e docker-compose up
|
dagger -e docker-compose up
|
||||||
}
|
}
|
||||||
@ -177,7 +181,7 @@ setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "google cloud: gke" {
|
@test "google cloud: gke" {
|
||||||
dagger -e google-gke up
|
dagger -e google-gke up
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "google cloud: secretmanager" {
|
@test "google cloud: secretmanager" {
|
||||||
|
Reference in New Issue
Block a user