0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31:10 +00:00

feat(provider): add optional SSH port param to node in provider ssh block (#520)

* feat: Add optional SSH port param to node in provider ssh block

* fix: minor cleanups

---------

Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Rafał Safin 2023-09-03 01:43:08 +02:00 committed by GitHub
parent 4cccebaa62
commit 124cac247c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 26 deletions

View File

@ -208,3 +208,4 @@ Proxmox `provider` block:
specified multiple times to provide configuration fo multiple nodes.
- `name` - (Required) The name of the node.
- `address` - (Required) The IP address of the node.
- `port` - (Optional) SSH port of the node. Defaults to 22.

View File

@ -12,6 +12,7 @@ import (
"regexp"
"strings"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
@ -68,6 +69,7 @@ type proxmoxProviderModel struct {
Nodes []struct {
Name types.String `tfsdk:"name"`
Address types.String `tfsdk:"address"`
Port types.Int64 `tfsdk:"port"`
} `tfsdk:"node"`
} `tfsdk:"ssh"`
}
@ -167,6 +169,11 @@ func (p *proxmoxProvider) Schema(_ context.Context, _ provider.SchemaRequest, re
Description: "The address of the Proxmox VE node.",
Required: true,
},
"port": schema.Int64Attribute{
Description: "The port of the Proxmox VE node.",
Optional: true,
Validators: []validator.Int64{int64validator.Between(1, 65535)},
},
},
},
},
@ -291,8 +298,9 @@ func (p *proxmoxProvider) Configure(
sshPassword := utils.GetAnyStringEnv("PROXMOX_VE_SSH_PASSWORD")
sshAgent := utils.GetAnyBoolEnv("PROXMOX_VE_SSH_AGENT")
sshAgentSocket := utils.GetAnyStringEnv("SSH_AUTH_SOCK", "PROXMOX_VE_SSH_AUTH_SOCK")
nodeOverrides := map[string]string{}
nodeOverrides := map[string]ssh.ProxmoxNode{}
//nolint: nestif
if len(config.SSH) > 0 {
if !config.SSH[0].Username.IsNull() {
sshUsername = config.SSH[0].Username.ValueString()
@ -311,7 +319,15 @@ func (p *proxmoxProvider) Configure(
}
for _, n := range config.SSH[0].Nodes {
nodeOverrides[n.Name.ValueString()] = n.Address.ValueString()
nodePort := int32(n.Port.ValueInt64())
if nodePort == 0 {
nodePort = 22
}
nodeOverrides[n.Name.ValueString()] = ssh.ProxmoxNode{
Address: n.Address.ValueString(),
Port: nodePort,
}
}
}
@ -370,12 +386,12 @@ type apiResolver struct {
c api.Client
}
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, error) {
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (ssh.ProxmoxNode, error) {
nc := &nodes.Client{Client: r.c, NodeName: nodeName}
networkDevices, err := nc.ListNetworkInterfaces(ctx)
if err != nil {
return "", fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
return ssh.ProxmoxNode{}, fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
}
nodeAddress := ""
@ -388,22 +404,23 @@ func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, err
}
if nodeAddress == "" {
return "", fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
return ssh.ProxmoxNode{}, fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
}
nodeAddressParts := strings.Split(nodeAddress, "/")
node := ssh.ProxmoxNode{Address: nodeAddressParts[0], Port: 22}
return nodeAddressParts[0], nil
return node, nil
}
type apiResolverWithOverrides struct {
ar apiResolver
overrides map[string]string
overrides map[string]ssh.ProxmoxNode
}
func (r *apiResolverWithOverrides) Resolve(ctx context.Context, nodeName string) (string, error) {
if ip, ok := r.overrides[nodeName]; ok {
return ip, nil
func (r *apiResolverWithOverrides) Resolve(ctx context.Context, nodeName string) (ssh.ProxmoxNode, error) {
if node, ok := r.overrides[nodeName]; ok {
return node, nil
}
return r.ar.Resolve(ctx, nodeName)

View File

@ -74,19 +74,20 @@ func NewClient(
// ExecuteNodeCommands executes commands on a given node.
func (c *client) ExecuteNodeCommands(ctx context.Context, nodeName string, commands []string) error {
ip, err := c.nodeLookup.Resolve(ctx, nodeName)
node, err := c.nodeLookup.Resolve(ctx, nodeName)
if err != nil {
return fmt.Errorf("failed to find node endpoint: %w", err)
}
tflog.Debug(ctx, "executing commands on the node using SSH", map[string]interface{}{
"node_address": ip,
"node_address": node.Address,
"node_port": node.Port,
"commands": commands,
})
closeOrLogError := utils.CloseOrLogError(ctx)
sshClient, err := c.openNodeShell(ctx, ip)
sshClient, err := c.openNodeShell(ctx, node)
if err != nil {
return err
}
@ -212,13 +213,13 @@ func (c *client) NodeUpload(
}
// openNodeShell establishes a new SSH connection to a node.
func (c *client) openNodeShell(ctx context.Context, nodeAddress string) (*ssh.Client, error) {
func (c *client) openNodeShell(ctx context.Context, node ProxmoxNode) (*ssh.Client, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to determine the home directory: %w", err)
}
sshHost := fmt.Sprintf("%s:22", nodeAddress)
sshHost := fmt.Sprintf("%s:%d", node.Address, node.Port)
sshPath := path.Join(homeDir, ".ssh")
if _, err = os.Stat(sshPath); os.IsNotExist(err) {

View File

@ -10,7 +10,13 @@ import (
"context"
)
// ProxmoxNode represents node address and port for SSH connection.
type ProxmoxNode struct {
Address string
Port int32
}
// NodeResolver is an interface for resolving node names to IP addresses to use for SSH connection.
type NodeResolver interface {
Resolve(ctx context.Context, nodeName string) (string, error)
Resolve(ctx context.Context, nodeName string) (ProxmoxNode, error)
}

View File

@ -129,12 +129,15 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{},
sshConf[mkProviderSSHAgentSocket] = sshAgentSocket
}
nodeOverrides := map[string]string{}
nodeOverrides := map[string]ssh.ProxmoxNode{}
if ns, ok := sshConf[mkProviderSSHNode]; ok {
for _, n := range ns.([]interface{}) {
node := n.(map[string]interface{})
nodeOverrides[node[mkProviderSSHNodeName].(string)] = node[mkProviderSSHNodeAddress].(string)
nodeOverrides[node[mkProviderSSHNodeName].(string)] = ssh.ProxmoxNode{
Address: node[mkProviderSSHNodeAddress].(string),
Port: node[mkProviderSSHNodePort].(int32),
}
}
}
@ -161,12 +164,12 @@ type apiResolver struct {
c api.Client
}
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, error) {
func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (ssh.ProxmoxNode, error) {
nc := &nodes.Client{Client: r.c, NodeName: nodeName}
networkDevices, err := nc.ListNetworkInterfaces(ctx)
if err != nil {
return "", fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
return ssh.ProxmoxNode{}, fmt.Errorf("failed to list network devices of node \"%s\": %w", nc.NodeName, err)
}
nodeAddress := ""
@ -179,22 +182,23 @@ func (r *apiResolver) Resolve(ctx context.Context, nodeName string) (string, err
}
if nodeAddress == "" {
return "", fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
return ssh.ProxmoxNode{}, fmt.Errorf("failed to determine the IP address of node \"%s\"", nc.NodeName)
}
nodeAddressParts := strings.Split(nodeAddress, "/")
node := ssh.ProxmoxNode{Address: nodeAddressParts[0], Port: 22}
return nodeAddressParts[0], nil
return node, nil
}
type apiResolverWithOverrides struct {
ar apiResolver
overrides map[string]string
overrides map[string]ssh.ProxmoxNode
}
func (r *apiResolverWithOverrides) Resolve(ctx context.Context, nodeName string) (string, error) {
if ip, ok := r.overrides[nodeName]; ok {
return ip, nil
func (r *apiResolverWithOverrides) Resolve(ctx context.Context, nodeName string) (ssh.ProxmoxNode, error) {
if node, ok := r.overrides[nodeName]; ok {
return node, nil
}
return r.ar.Resolve(ctx, nodeName)

View File

@ -31,6 +31,7 @@ const (
mkProviderSSHNode = "node"
mkProviderSSHNodeName = "name"
mkProviderSSHNodeAddress = "address"
mkProviderSSHNodePort = "port"
)
func createSchema() map[string]*schema.Schema {
@ -155,6 +156,13 @@ func createSchema() map[string]*schema.Schema {
Description: "The address of the Proxmox VE node.",
ValidateFunc: validation.IsIPAddress,
},
mkProviderSSHNodePort: {
Type: schema.TypeInt,
Optional: true,
Description: "The port of the Proxmox VE node.",
Default: 22,
ValidateFunc: validation.IsPortNumber,
},
},
},
},