From 5480fb991d6e8ca6f72b894c4bf2b061f8eebf8a Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Thu, 16 Sep 2021 17:18:05 -0700 Subject: [PATCH 1/3] dagger.#Socket support Signed-off-by: Andrea Luzzardi --- cmd/dagger/cmd/input/root.go | 1 + cmd/dagger/cmd/input/socket.go | 51 +++++++++++++++++++ docs/reference/dagger/README.md | 12 +++++ environment/pipeline.go | 23 +++++++++ ...kersocketprovider.go => socketprovider.go} | 24 +++++---- state/input.go | 22 ++++++++ stdlib/dagger/dagger.cue | 7 +++ 7 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 cmd/dagger/cmd/input/socket.go rename solver/{dockersocketprovider.go => socketprovider.go} (58%) diff --git a/cmd/dagger/cmd/input/root.go b/cmd/dagger/cmd/input/root.go index e53448f8..8f691f3e 100644 --- a/cmd/dagger/cmd/input/root.go +++ b/cmd/dagger/cmd/input/root.go @@ -32,6 +32,7 @@ func init() { yamlCmd, listCmd, boolCmd, + socketCmd, unsetCmd, ) } diff --git a/cmd/dagger/cmd/input/socket.go b/cmd/dagger/cmd/input/socket.go new file mode 100644 index 00000000..8bf1b417 --- /dev/null +++ b/cmd/dagger/cmd/input/socket.go @@ -0,0 +1,51 @@ +package input + +import ( + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.dagger.io/dagger/cmd/dagger/logger" + "go.dagger.io/dagger/state" +) + +var socketCmd = &cobra.Command{ + Use: "socket ", + Short: "Add a socket input", + Args: cobra.ExactArgs(2), + PreRun: func(cmd *cobra.Command, args []string) { + // Fix Viper bug for duplicate flags: + // https://github.com/spf13/viper/issues/233 + if err := viper.BindPFlags(cmd.Flags()); err != nil { + panic(err) + } + }, + Run: func(cmd *cobra.Command, args []string) { + lg := logger.New() + ctx := lg.WithContext(cmd.Context()) + + unix := args[1] + + st, err := os.Stat(unix) + if err != nil { + lg.Fatal().Err(err).Str("path", unix).Msg("invalid unix socket") + } + + if st.Mode()&os.ModeSocket == 0 { + lg.Fatal().Str("path", unix).Msg("not a unix socket") + } + + updateEnvironmentInput( + ctx, + cmd, + args[0], + state.SocketInput(unix), + ) + }, +} + +func init() { + if err := viper.BindPFlags(boolCmd.Flags()); err != nil { + panic(err) + } +} diff --git a/docs/reference/dagger/README.md b/docs/reference/dagger/README.md index 60694e45..8bd33ae0 100644 --- a/docs/reference/dagger/README.md +++ b/docs/reference/dagger/README.md @@ -21,3 +21,15 @@ _No input._ ### dagger.#Secret Outputs _No output._ + +## dagger.#Socket + +Dagger socket. Can be mounted as a UNIX socket. + +### dagger.#Socket Inputs + +_No input._ + +### dagger.#Socket Outputs + +_No output._ diff --git a/environment/pipeline.go b/environment/pipeline.go index e515e040..79bd276f 100644 --- a/environment/pipeline.go +++ b/environment/pipeline.go @@ -492,6 +492,7 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value) return nil, fmt.Errorf("invalid mount source: %q", s) } } + // eg. mount: "/foo": secret: mysecret if secret := mnt.Lookup("secret"); secret.Exists() { id, err := getSecretID(secret) @@ -505,6 +506,28 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value) ), nil } + // eg. mount: "/var/run/docker.sock": socket: mysocket + if socket := mnt.Lookup("socket"); socket.Exists() { + if !socket.HasAttr("socket") { + return nil, fmt.Errorf("invalid socket %q: not a socket", socket.Path().String()) + } + + unixValue := socket.Lookup("unix") + if !unixValue.Exists() { + return nil, fmt.Errorf("invalid socket %q: not a unix socket", socket.Path().String()) + } + + unix, err := unixValue.String() + if err != nil { + return nil, fmt.Errorf("invalid unix path id: %w", err) + } + + return llb.AddSSHSocket( + llb.SSHID(fmt.Sprintf("unix=%s", unix)), + llb.SSHSocketTarget(dest), + ), nil + } + // eg. mount: "/foo": { from: www.source } if !mnt.Lookup("from").Exists() { return nil, fmt.Errorf("invalid mount: should have %s structure", diff --git a/solver/dockersocketprovider.go b/solver/socketprovider.go similarity index 58% rename from solver/dockersocketprovider.go rename to solver/socketprovider.go index 6eb79091..2e232fc7 100644 --- a/solver/dockersocketprovider.go +++ b/solver/socketprovider.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "strings" "time" "github.com/moby/buildkit/session" @@ -13,33 +14,32 @@ import ( ) const ( - DockerSocketID = "docker.sock" - DockerSocketPath = "/var/run/docker.sock" + unixPrefix = "unix=" ) -type DockerSocketProvider struct { +type SocketProvider struct { } func NewDockerSocketProvider() session.Attachable { - return &DockerSocketProvider{} + return &SocketProvider{} } -func (sp *DockerSocketProvider) Register(server *grpc.Server) { +func (sp *SocketProvider) Register(server *grpc.Server) { sshforward.RegisterSSHServer(server, sp) } -func (sp *DockerSocketProvider) CheckAgent(ctx context.Context, req *sshforward.CheckAgentRequest) (*sshforward.CheckAgentResponse, error) { +func (sp *SocketProvider) CheckAgent(ctx context.Context, req *sshforward.CheckAgentRequest) (*sshforward.CheckAgentResponse, error) { id := sshforward.DefaultID if req.ID != "" { id = req.ID } - if id != DockerSocketID { + if !strings.HasPrefix(id, unixPrefix) { return &sshforward.CheckAgentResponse{}, fmt.Errorf("invalid socket forward key %s", id) } return &sshforward.CheckAgentResponse{}, nil } -func (sp *DockerSocketProvider) ForwardAgent(stream sshforward.SSH_ForwardAgentServer) error { +func (sp *SocketProvider) ForwardAgent(stream sshforward.SSH_ForwardAgentServer) error { id := sshforward.DefaultID opts, _ := metadata.FromIncomingContext(stream.Context()) // if no metadata continue with empty object @@ -48,13 +48,15 @@ func (sp *DockerSocketProvider) ForwardAgent(stream sshforward.SSH_ForwardAgentS id = v[0] } - if id != DockerSocketID { + if !strings.HasPrefix(id, unixPrefix) { return fmt.Errorf("invalid socket forward key %s", id) } - conn, err := net.DialTimeout("unix", DockerSocketPath, time.Second) + id = strings.TrimPrefix(id, unixPrefix) + + conn, err := net.DialTimeout("unix", id, time.Second) if err != nil { - return fmt.Errorf("failed to connect to %s: %w", DockerSocketPath, err) + return fmt.Errorf("failed to connect to %s: %w", id, err) } defer conn.Close() diff --git a/state/input.go b/state/input.go index 5c75fb08..d4525dde 100644 --- a/state/input.go +++ b/state/input.go @@ -37,6 +37,7 @@ type Input struct { YAML *yamlInput `yaml:"yaml,omitempty"` File *fileInput `yaml:"file,omitempty"` Bool *boolInput `yaml:"bool,omitempty"` + Socket *socketInput `yaml:"socket,omitempty"` } func (i Input) Compile(key string, state *State) (*compiler.Value, error) { @@ -59,6 +60,8 @@ func (i Input) Compile(key string, state *State) (*compiler.Value, error) { return i.File.Compile(key, state) case i.Bool != nil: return i.Bool.Compile(key, state) + case i.Socket != nil: + return i.Socket.Compile(key, state) default: return nil, fmt.Errorf("input has not been set") } @@ -281,3 +284,22 @@ func (i fileInput) Compile(_ string, _ *State) (*compiler.Value, error) { } return value, nil } + +// A socket input value +func SocketInput(data string) Input { + i := socketInput{ + Unix: data, + } + return Input{ + Socket: &i, + } +} + +type socketInput struct { + Unix string `json:"unix,omitempty"` +} + +func (i socketInput) Compile(_ string, _ *State) (*compiler.Value, error) { + socketValue := fmt.Sprintf(`{unix: %q}`, i.Unix) + return compiler.Compile("", socketValue) +} diff --git a/stdlib/dagger/dagger.cue b/stdlib/dagger/dagger.cue index 9731bfb1..bf08e6e9 100644 --- a/stdlib/dagger/dagger.cue +++ b/stdlib/dagger/dagger.cue @@ -14,6 +14,13 @@ import ( ... } +// Dagger socket. Can be mounted as a UNIX socket. +#Socket: { + @dagger(socket) + + unix: string +} + // Secret value #Secret: { @dagger(secret) From 408f147fab04f9c4f249cec3bdcf3354dfaf539e Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Fri, 17 Sep 2021 11:51:06 -0700 Subject: [PATCH 2/3] socket: add tests Signed-off-by: Andrea Luzzardi --- tests/compute/dockersocket/main.cue | 18 ------------------ tests/core.bats | 12 +++++++++--- tests/core/socket/main.cue | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 21 deletions(-) delete mode 100644 tests/compute/dockersocket/main.cue create mode 100644 tests/core/socket/main.cue diff --git a/tests/compute/dockersocket/main.cue b/tests/compute/dockersocket/main.cue deleted file mode 100644 index a554623c..00000000 --- a/tests/compute/dockersocket/main.cue +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "alpha.dagger.io/dagger/op" - "alpha.dagger.io/docker" -) - -TestDockerSocket: #up: [ - op.#Load & { - from: docker.#Client - }, - - op.#Exec & { - always: true - mount: "/var/run/docker.sock": "docker.sock" - args: ["docker", "info"] - }, -] diff --git a/tests/core.bats b/tests/core.bats index a3e7e582..57ec21a5 100644 --- a/tests/core.bats +++ b/tests/core.bats @@ -148,9 +148,15 @@ setup() { assert_output --partial "secret=mySecret;hash=" } -@test "compute: docker socket" { - skip "docker socket support disabled" - run "$DAGGER" compute "$TESTDIR"/compute/dockersocket +@test "core: socket" { + dagger init + + dagger_new_with_plan test-socket "$TESTDIR"/core/socket + + # Set dir input + "$DAGGER" input socket dockersocket /var/run/docker.sock + + "$DAGGER" up } @test "compute: exclude" { diff --git a/tests/core/socket/main.cue b/tests/core/socket/main.cue new file mode 100644 index 00000000..5bd4ef1e --- /dev/null +++ b/tests/core/socket/main.cue @@ -0,0 +1,23 @@ +package main + +import ( + "alpha.dagger.io/dagger" + "alpha.dagger.io/dagger/op" + "alpha.dagger.io/alpine" +) + +dockersocket: dagger.#Socket & dagger.#Input + +TestDockerSocket: #up: [ + op.#Load & { + from: alpine.#Image & { + package: "docker-cli": true + } + }, + + op.#Exec & { + always: true + mount: "/var/run/docker.sock": socket: dockersocket + args: ["docker", "info"] + }, +] From 0f4a55a48241be257ac13fa7604d313b17cc7764 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Fri, 17 Sep 2021 15:17:28 -0700 Subject: [PATCH 3/3] socket -> stream Signed-off-by: Andrea Luzzardi --- docs/reference/dagger/README.md | 8 ++++---- environment/pipeline.go | 12 ++++++------ stdlib/dagger/dagger.cue | 6 +++--- tests/core.bats | 4 ++-- tests/core/{socket => stream}/main.cue | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) rename tests/core/{socket => stream}/main.cue (73%) diff --git a/docs/reference/dagger/README.md b/docs/reference/dagger/README.md index 8bd33ae0..78a571c5 100644 --- a/docs/reference/dagger/README.md +++ b/docs/reference/dagger/README.md @@ -22,14 +22,14 @@ _No input._ _No output._ -## dagger.#Socket +## dagger.#Stream -Dagger socket. Can be mounted as a UNIX socket. +Dagger stream. Can be mounted as a UNIX socket. -### dagger.#Socket Inputs +### dagger.#Stream Inputs _No input._ -### dagger.#Socket Outputs +### dagger.#Stream Outputs _No output._ diff --git a/environment/pipeline.go b/environment/pipeline.go index 79bd276f..21b4ab87 100644 --- a/environment/pipeline.go +++ b/environment/pipeline.go @@ -506,15 +506,15 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value) ), nil } - // eg. mount: "/var/run/docker.sock": socket: mysocket - if socket := mnt.Lookup("socket"); socket.Exists() { - if !socket.HasAttr("socket") { - return nil, fmt.Errorf("invalid socket %q: not a socket", socket.Path().String()) + // eg. mount: "/var/run/docker.sock": stream: mystream + if stream := mnt.Lookup("stream"); stream.Exists() { + if !stream.HasAttr("stream") { + return nil, fmt.Errorf("invalid stream %q: not a stream", stream.Path().String()) } - unixValue := socket.Lookup("unix") + unixValue := stream.Lookup("unix") if !unixValue.Exists() { - return nil, fmt.Errorf("invalid socket %q: not a unix socket", socket.Path().String()) + return nil, fmt.Errorf("invalid stream %q: not a unix socket", stream.Path().String()) } unix, err := unixValue.String() diff --git a/stdlib/dagger/dagger.cue b/stdlib/dagger/dagger.cue index bf08e6e9..35da3ce6 100644 --- a/stdlib/dagger/dagger.cue +++ b/stdlib/dagger/dagger.cue @@ -14,9 +14,9 @@ import ( ... } -// Dagger socket. Can be mounted as a UNIX socket. -#Socket: { - @dagger(socket) +// Dagger stream. Can be mounted as a UNIX socket. +#Stream: { + @dagger(stream) unix: string } diff --git a/tests/core.bats b/tests/core.bats index 57ec21a5..6a46f595 100644 --- a/tests/core.bats +++ b/tests/core.bats @@ -148,10 +148,10 @@ setup() { assert_output --partial "secret=mySecret;hash=" } -@test "core: socket" { +@test "core: stream" { dagger init - dagger_new_with_plan test-socket "$TESTDIR"/core/socket + dagger_new_with_plan test-stream "$TESTDIR"/core/stream # Set dir input "$DAGGER" input socket dockersocket /var/run/docker.sock diff --git a/tests/core/socket/main.cue b/tests/core/stream/main.cue similarity index 73% rename from tests/core/socket/main.cue rename to tests/core/stream/main.cue index 5bd4ef1e..dc77480a 100644 --- a/tests/core/socket/main.cue +++ b/tests/core/stream/main.cue @@ -6,7 +6,7 @@ import ( "alpha.dagger.io/alpine" ) -dockersocket: dagger.#Socket & dagger.#Input +dockersocket: dagger.#Stream & dagger.#Input TestDockerSocket: #up: [ op.#Load & { @@ -17,7 +17,7 @@ TestDockerSocket: #up: [ op.#Exec & { always: true - mount: "/var/run/docker.sock": socket: dockersocket + mount: "/var/run/docker.sock": stream: dockersocket args: ["docker", "info"] }, ]