-
Notifications
You must be signed in to change notification settings - Fork 2
/
proxmox.go
177 lines (149 loc) · 5.25 KB
/
proxmox.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package main
import (
"encoding/json"
"fmt"
"log"
"regexp"
"strings"
"github.com/go-resty/resty/v2"
)
// Structure for the Proxmox API response for nodes
type Node struct {
Node string `json:"node"`
}
// Structure for the Proxmox API response for VMs
type VM struct {
VMID int `json:"vmid"` // VMID is an integer in the API response
Tags string `json:"tags"` // Tags separated by semicolons
}
// Structure for the Proxmox API response for VM configuration (contains nested "data" field)
type VMConfigResponse struct {
Data VMConfig `json:"data"` // Nested object containing ipconfig0 and name
}
type VMConfig struct {
IPConfig0 string `json:"ipconfig0"` // IP configuration
Name string `json:"name"` // Name of the VM
}
// Structure for network interface data of the node
type NetworkInterface struct {
Iface string `json:"iface"`
Address string `json:"address"`
CIDR string `json:"cidr"`
Type string `json:"type"`
Families []string `json:"families"`
}
type NodeNetworkResponse struct {
Data []NetworkInterface `json:"data"`
}
// Example structure for the Proxmox API response
type ProxmoxNodesResponse struct {
Data []Node `json:"data"`
}
type ProxmoxVMsResponse struct {
Data []VM `json:"data"`
}
// Resty client for HTTP requests
var client = resty.New()
// Generic function for Proxmox API requests
func fetchFromProxmox(url, apiToken string, result interface{}) error {
resp, err := client.R().
SetHeader("Authorization", "PVEAPIToken="+apiToken).
Get(url)
if err != nil {
return err
}
if resp.StatusCode() < 200 || resp.StatusCode() >= 300 {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode())
}
err = json.Unmarshal(resp.Body(), &result)
if err != nil {
return err
}
return nil
}
// Function to get and update DNS records from Proxmox, including VMs and node network data
func updateRecordsFromProxmox(records map[string]string, proxmoxURL, apiToken, dnsSuffix, useProxmoxTags, discoveryCIDR string) {
// Temporary variable to hold the new records
newRecords := map[string]string{}
// Fetching all nodes
var nodesResp ProxmoxNodesResponse
err := fetchFromProxmox(fmt.Sprintf("%s/api2/json/nodes", proxmoxURL), apiToken, &nodesResp)
if err != nil {
log.Printf("Error fetching node list: %v. Skipping update.", err)
return // Do not update records if an error occurs
}
// For each node, fetch VMs, their configuration, and network information
for _, node := range nodesResp.Data {
var vmsResp ProxmoxVMsResponse
err := fetchFromProxmox(fmt.Sprintf("%s/api2/json/nodes/%s/qemu", proxmoxURL, node.Node), apiToken, &vmsResp)
if err != nil {
log.Printf("Error fetching VMs for node %s: %v. Skipping this node.", node.Node, err)
continue // Skip this node and move to the next one
}
// For each VM, fetch configuration and extract IP address and name
for _, vm := range vmsResp.Data {
var configResp VMConfigResponse
err := fetchFromProxmox(fmt.Sprintf("%s/api2/json/nodes/%s/qemu/%d/config", proxmoxURL, node.Node, vm.VMID), apiToken, &configResp)
if err != nil {
log.Printf("Error fetching configuration for VM %d on node %s: %v. Skipping this VM.", vm.VMID, node.Node, err)
continue // Skip this VM and move to the next one
}
ip := extractIPFromConfig(configResp.Data.IPConfig0)
if ip != "" {
// Create DNS records based on the VM name
if configResp.Data.Name != "" {
newRecords[configResp.Data.Name+dnsSuffix] = ip
}
// Check if tags should be used to create DNS records
if useProxmoxTags == "true" && vm.Tags != "" {
tags := strings.Split(vm.Tags, ";")
for _, tag := range tags {
tag = strings.TrimSpace(tag) // Trim any extra spaces
tag = sanitizeTag(tag) // Additional tag sanitization
if tag != "" {
// Create a record based on the tag and IP address
newRecords[tag+dnsSuffix] = ip
}
}
}
}
}
// Fetch network information for the node
var nodeNetworkResp NodeNetworkResponse
err = fetchFromProxmox(fmt.Sprintf("%s/api2/json/nodes/%s/network", proxmoxURL, node.Node), apiToken, &nodeNetworkResp)
if err != nil {
log.Printf("Error fetching network information for node %s: %v. Skipping network records for this node.", node.Node, err)
continue
}
// Add network information for the interface that matches the DISCOVERY_NODE_CIDR
if discoveryCIDR != "" {
for _, iface := range nodeNetworkResp.Data {
if iface.CIDR == discoveryCIDR && iface.Address != "" {
// Add node's interface with matching CIDR to the DNS records
newRecords[node.Node+dnsSuffix] = iface.Address
break
}
}
}
}
// Update global records only if there were no errors
for k, v := range newRecords {
records[k] = v
}
log.Printf("Successfully updated records: %v", newRecords)
}
// Function to extract IP address from the ipconfig0 string
func extractIPFromConfig(ipconfig string) string {
// Example string: "ip=10.0.5.62/24,gw=10.0.5.1"
re := regexp.MustCompile(`ip=([\d\.]+)`)
matches := re.FindStringSubmatch(ipconfig)
if len(matches) > 1 {
return matches[1]
}
return ""
}
// Additional function to sanitize tags
func sanitizeTag(tag string) string {
// Add any logic to remove forbidden characters
return strings.ToLower(tag) // For example, convert all tags to lowercase
}