From 5480fb991d6e8ca6f72b894c4bf2b061f8eebf8a Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Thu, 16 Sep 2021 17:18:05 -0700 Subject: [PATCH] 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)