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:
parent
4cccebaa62
commit
124cac247c
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user