mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
feat: add CLI connector for unix domain socket (#186)
* feat: Add cli connector for unix domain socket * Update cmd/uncloud/main.go --------- Co-authored-by: Pasha Sviderski <me@psviderski.name>
This commit is contained in:
co-authored by
Pasha Sviderski
parent
e87207eae3
commit
91a09d5d37
+6
-5
@@ -58,11 +58,12 @@ func main() {
|
|||||||
conn = &config.MachineConnection{
|
conn = &config.MachineConnection{
|
||||||
SSHCLI: config.SSHDestination(dest),
|
SSHCLI: config.SSHDestination(dest),
|
||||||
}
|
}
|
||||||
} else {
|
} else if strings.HasPrefix(opts.connect, "unix://") {
|
||||||
dest := opts.connect
|
conn = &config.MachineConnection{
|
||||||
if strings.HasPrefix(dest, "ssh://") {
|
Unix: opts.connect[len("unix://"):],
|
||||||
dest = dest[len("ssh://"):]
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dest := strings.TrimPrefix(opts.connect, "ssh://")
|
||||||
conn = &config.MachineConnection{
|
conn = &config.MachineConnection{
|
||||||
SSH: config.SSHDestination(dest),
|
SSH: config.SSHDestination(dest),
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@ func main() {
|
|||||||
|
|
||||||
cmd.PersistentFlags().StringVar(&opts.connect, "connect", "",
|
cmd.PersistentFlags().StringVar(&opts.connect, "connect", "",
|
||||||
"Connect to a remote cluster machine without using the Uncloud configuration file. [$UNCLOUD_CONNECT]\n"+
|
"Connect to a remote cluster machine without using the Uncloud configuration file. [$UNCLOUD_CONNECT]\n"+
|
||||||
"Format: [ssh://]user@host[:port], ssh+cli://user@host[:port], or tcp://host:port")
|
"Format: [ssh://]user@host[:port], ssh+cli://user@host[:port], tcp://host:port, or unix:///path/to/uncloud.sock")
|
||||||
cmd.PersistentFlags().StringVar(&opts.configPath, "uncloud-config", "~/.config/uncloud/config.yaml",
|
cmd.PersistentFlags().StringVar(&opts.configPath, "uncloud-config", "~/.config/uncloud/config.yaml",
|
||||||
"Path to the Uncloud configuration file. [$UNCLOUD_CONFIG]")
|
"Path to the Uncloud configuration file. [$UNCLOUD_CONFIG]")
|
||||||
_ = cmd.MarkPersistentFlagFilename("uncloud-config", "yaml", "yml")
|
_ = cmd.MarkPersistentFlagFilename("uncloud-config", "yaml", "yml")
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ type MachineConnection struct {
|
|||||||
SSHKeyFile string `yaml:"ssh_key_file,omitempty"`
|
SSHKeyFile string `yaml:"ssh_key_file,omitempty"`
|
||||||
// TCP is the address and port of the machine's API server.
|
// TCP is the address and port of the machine's API server.
|
||||||
// The pointer is used to omit the field when not set. Otherwise, yaml marshalling includes an empty object.
|
// The pointer is used to omit the field when not set. Otherwise, yaml marshalling includes an empty object.
|
||||||
TCP *netip.AddrPort `yaml:"tcp,omitempty"`
|
TCP *netip.AddrPort `yaml:"tcp,omitempty"`
|
||||||
Host string `yaml:"host,omitempty"`
|
// Unix is the path to the machine's API unix socket.
|
||||||
PublicKey secret.Secret `yaml:"public_key,omitempty"`
|
Unix string `yaml:"unix,omitempty"`
|
||||||
MachineID string `yaml:"machine_id,omitempty"`
|
Host string `yaml:"host,omitempty"`
|
||||||
|
PublicKey secret.Secret `yaml:"public_key,omitempty"`
|
||||||
|
MachineID string `yaml:"machine_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MachineConnection) String() string {
|
func (c MachineConnection) String() string {
|
||||||
@@ -35,6 +37,8 @@ func (c MachineConnection) String() string {
|
|||||||
return "ssh+cli://" + string(c.SSHCLI)
|
return "ssh+cli://" + string(c.SSHCLI)
|
||||||
} else if c.TCP != nil && c.TCP.IsValid() {
|
} else if c.TCP != nil && c.TCP.IsValid() {
|
||||||
return fmt.Sprintf("tcp://%s", c.TCP)
|
return fmt.Sprintf("tcp://%s", c.TCP)
|
||||||
|
} else if c.Unix != "" {
|
||||||
|
return fmt.Sprintf("unix://%s", c.Unix)
|
||||||
}
|
}
|
||||||
return "unknown connection"
|
return "unknown connection"
|
||||||
}
|
}
|
||||||
@@ -50,12 +54,15 @@ func (c *MachineConnection) Validate() error {
|
|||||||
if c.TCP != nil && c.TCP.IsValid() {
|
if c.TCP != nil && c.TCP.IsValid() {
|
||||||
setCount++
|
setCount++
|
||||||
}
|
}
|
||||||
|
if c.Unix != "" {
|
||||||
|
setCount++
|
||||||
|
}
|
||||||
|
|
||||||
if setCount == 0 {
|
if setCount == 0 {
|
||||||
return errors.New("no connection method specified (ssh, ssh_cli, or tcp required)")
|
return errors.New("no connection method specified (ssh, ssh_cli, tcp, or unix required)")
|
||||||
}
|
}
|
||||||
if setCount > 1 {
|
if setCount > 1 {
|
||||||
return errors.New("only one connection method allowed per connection (ssh, ssh_cli, or tcp)")
|
return errors.New("only one connection method allowed per connection (ssh, ssh_cli, tcp, or unix)")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -53,6 +53,13 @@ func TestMachineConnection_String(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: "tcp://10.0.0.1:8080",
|
want: "tcp://10.0.0.1:8080",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "unix connection",
|
||||||
|
conn: MachineConnection{
|
||||||
|
Unix: "/run/uncloud/uncloud.sock",
|
||||||
|
},
|
||||||
|
want: "unix:///run/uncloud/uncloud.sock",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "no connection",
|
name: "no connection",
|
||||||
conn: MachineConnection{},
|
conn: MachineConnection{},
|
||||||
@@ -112,6 +119,13 @@ func TestMachineConnection_Validate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "unix only - valid",
|
||||||
|
conn: MachineConnection{
|
||||||
|
Unix: "/path/to/socket",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "no connection method - error",
|
name: "no connection method - error",
|
||||||
conn: MachineConnection{},
|
conn: MachineConnection{},
|
||||||
@@ -127,6 +141,15 @@ func TestMachineConnection_Validate(t *testing.T) {
|
|||||||
wantErr: true,
|
wantErr: true,
|
||||||
errMsg: "only one connection method allowed",
|
errMsg: "only one connection method allowed",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ssh and unix - error",
|
||||||
|
conn: MachineConnection{
|
||||||
|
SSH: "user@host",
|
||||||
|
Unix: "/path/to/socket",
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
errMsg: "only one connection method allowed",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ssh and tcp - error",
|
name: "ssh and tcp - error",
|
||||||
conn: MachineConnection{
|
conn: MachineConnection{
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ func connectCluster(ctx context.Context, conn config.MachineConnection) (*client
|
|||||||
useSSHCLI = true
|
useSSHCLI = true
|
||||||
} else if conn.TCP != nil && conn.TCP.IsValid() {
|
} else if conn.TCP != nil && conn.TCP.IsValid() {
|
||||||
return client.New(ctx, connector.NewTCPConnector(*conn.TCP))
|
return client.New(ctx, connector.NewTCPConnector(*conn.TCP))
|
||||||
|
} else if conn.Unix != "" {
|
||||||
|
return client.New(ctx, connector.NewUnixConnector(conn.Unix))
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("connection configuration is invalid")
|
return nil, errors.New("connection configuration is invalid")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package connector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnixConnector establishes a connection to the machine API through a unix domain socket.
|
||||||
|
type UnixConnector struct {
|
||||||
|
socketPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnixConnector(socketPath string) *UnixConnector {
|
||||||
|
return &UnixConnector{socketPath: socketPath}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UnixConnector) Connect(_ context.Context) (*grpc.ClientConn, error) {
|
||||||
|
// gRPC uses "unix:path" syntax for unix sockets.
|
||||||
|
target := "unix:" + c.socketPath
|
||||||
|
|
||||||
|
conn, err := grpc.NewClient(
|
||||||
|
target,
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create machine API client: %w", err)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UnixConnector) Dialer() (proxy.ContextDialer, error) {
|
||||||
|
return nil, fmt.Errorf("proxy connections are not supported over a unix connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UnixConnector) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user