Skip to content

Commit

Permalink
Merge pull request Telmate#209 from dandyrow/config_network
Browse files Browse the repository at this point in the history
Adding network support
  • Loading branch information
mleone87 committed Oct 24, 2022
2 parents 6efe2d4 + aeb7364 commit 98e99c2
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 2 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,24 @@ export PM_HTTP_HEADERS=Key,Value,Key1,Value1 (only if required)

./proxmox-api-go deleteStorage

./proxmox-api-go getNetworkList node

./proxmox-api-go getNetworkInterface node interfaceName

./proxmox-api-go createNetwork < network.json

./proxmox-api-go updateNetwork < network.json

./proxmox-api-go deleteNetwork node iface

./proxmox-api-go applyNetwork node

./proxmox-api-go revertNetwork node

./proxmox-api-go node reboot proxmox-node-name

./proxmox-api-go node shutdown proxmox-node-name

```
## Proxy server support
Expand Down
74 changes: 74 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,80 @@ func main() {
failError(err)
fmt.Printf("Storage %s removed\n", storageid)

// Network
case "getNetworkList":
if len(flag.Args()) < 2 {
failError(fmt.Errorf("error: Proxmox node name required"))
}
node := flag.Args()[1]
typeFilter := ""
if len(flag.Args()) == 3 {
typeFilter = flag.Args()[2]
}
exitStatus, err := c.GetNetworkList(node, typeFilter)
if err != nil {
failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus))
}
log.Printf("List of current network configuration: %s", exitStatus)

case "getNetworkInterface":
if len(flag.Args()) < 3 {
failError(fmt.Errorf("error: Proxmox node name and network interface name required"))
}
node := flag.Args()[1]
iface := flag.Args()[2]
exitStatus, err := c.GetNetworkInterface(node, iface)
if err != nil {
failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus))
}
log.Printf("Network interface %s configuration: %s", iface, exitStatus)

case "createNetwork":
config, err := proxmox.NewConfigNetworkFromJSON(GetConfig(*fConfigFile))
failError(err)
failError(config.CreateNetwork(c))
log.Printf("Network %s has been created\n", config.Iface)

case "updateNetwork":
config, err := proxmox.NewConfigNetworkFromJSON(GetConfig(*fConfigFile))
failError(err)
failError(config.UpdateNetwork(c))
log.Printf("Network %s has been updated\n", config.Iface)

case "deleteNetwork":
if len(flag.Args()) < 3 {
failError(fmt.Errorf("error: Proxmox node name and network interface name required"))
}
node := flag.Args()[1]
iface := flag.Args()[2]
exitStatus, err := c.DeleteNetwork(node, iface)
if err != nil {
failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus))
}
log.Printf("Network interface %s deleted", iface)

case "applyNetwork":
if len(flag.Args()) < 2 {
failError(fmt.Errorf("error: Proxmox node name required"))
}
node := flag.Args()[1]
exitStatus, err := c.ApplyNetwork(node)
if err != nil {
failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus))
}
log.Printf("Network configuration on node %s has been applied\n", node)

case "revertNetwork":
if len(flag.Args()) < 2 {
failError(fmt.Errorf("error: Proxmox node name required"))
}
node := flag.Args()[1]
exitStatus, err := c.RevertNetwork(node)
if err != nil {
failError(fmt.Errorf("error: %+v\n api error: %s", err, exitStatus))
}
log.Printf("Network configuration on node %s has been reverted\n", node)

default:
fmt.Printf("unknown action, try start|stop vmid\n")
}
Expand Down
89 changes: 87 additions & 2 deletions proxmox/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,71 @@ func (c *Client) DeleteStorage(id string) error {
return c.DeleteUrl("/storage/" + id)
}

// Network

// GetNetworkList gets a json encoded list of currently configured network interfaces on the
// passed in node. The typeFilter parameter can be used to filter by interface type. Pass in
// the empty string "" for typeFilter to list all network interfaces on the node.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) GetNetworkList(node string, typeFilter string) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network", node)
if typeFilter != "" {
url += fmt.Sprintf("?type=%s", typeFilter)
}
resp, err := c.session.Get(url, nil, nil)
exitStatus = c.HandleTaskError(resp)
return
}

// GetNetworkInterface gets a json encoded object containing the configuration of the network
// interface with the name passed in as iface from the passed in node.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) GetNetworkInterface(node string, iface string) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network/%s", node, iface)
resp, err := c.session.Get(url, nil, nil)
exitStatus = c.HandleTaskError(resp)
return
}

// CreateNetwork creates a network with the configuration of the passed in parameters
// on the passed in node.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) CreateNetwork(node string, params map[string]interface{}) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network", node)
return c.CreateItemReturnStatus(params, url)
}

// UpdateNetwork updates the network corresponding to the passed in interface name on the passed
// in node with the configuration in the passed in parameters.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) UpdateNetwork(node string, iface string, params map[string]interface{}) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network/%s", node, iface)
return c.UpdateItemReturnStatus(params, url)
}

// DeleteNetwork deletes the network with the passed in iface name on the passed in node.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) DeleteNetwork(node string, iface string) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network/%s", node, iface)
resp, err := c.session.Delete(url, nil, nil)
exitStatus = c.HandleTaskError(resp)
return
}

// ApplyNetwork applies the pending network configuration on the passed in node.
// It returns the body from the API response and any HTTP error the API returns.
func (c Client) ApplyNetwork(node string) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network", node)
return c.UpdateItemWithTask(nil, url)
}

// RevertNetwork reverts the pending network configuration on the passed in node.
// It returns the body from the API response and any HTTP error the API returns.
func (c *Client) RevertNetwork(node string) (exitStatus string, err error) {
url := fmt.Sprintf("/nodes/%s/network", node)
return c.DeleteUrlWithTask(url)
}

// Shared
func (c *Client) GetItemConfigMapStringInterface(url, text, message string) (map[string]interface{}, error) {
data, err := c.GetItemConfig(url, text, message)
Expand Down Expand Up @@ -1814,6 +1879,15 @@ func (c *Client) CreateItem(Params map[string]interface{}, url string) (err erro
return
}

// CreateItemReturnStatus creates an item on the Proxmox API.
// It returns the body of the HTTP response and any HTTP error occurred during the request.
func (c *Client) CreateItemReturnStatus(params map[string]interface{}, url string) (exitStatus string, err error) {
reqbody := ParamsToBody(params)
resp, err := c.session.Post(url, nil, nil, &reqbody)
exitStatus = c.HandleTaskError(resp)
return
}

// Create Item and wait on proxmox for the task to complete
func (c *Client) CreateItemWithTask(Params map[string]interface{}, url string) (exitStatus string, err error) {
reqbody := ParamsToBody(Params)
Expand All @@ -1831,6 +1905,15 @@ func (c *Client) UpdateItem(Params map[string]interface{}, url string) (err erro
return
}

// UpdateItemReturnStatus updates an item on the Proxmox API.
// It returns the body of the HTTP response and any HTTP error occurred during the request.
func (c *Client) UpdateItemReturnStatus(params map[string]interface{}, url string) (exitStatus string, err error) {
reqbody := ParamsToBody(params)
resp, err := c.session.Put(url, nil, nil, &reqbody)
exitStatus = c.HandleTaskError(resp)
return
}

// Update Item and wait on proxmox for the task to complete
func (c *Client) UpdateItemWithTask(Params map[string]interface{}, url string) (exitStatus string, err error) {
reqbody := ParamsToBodyWithAllEmpty(Params)
Expand Down Expand Up @@ -1862,7 +1945,8 @@ func (c *Client) GetItemList(url string) (list map[string]interface{}, err error
return
}

// Close task responce
// HandleTaskError reads the body from the passed in HTTP response and closes it.
// It returns the body of the passed in HTTP response.
func (c *Client) HandleTaskError(resp *http.Response) (exitStatus string) {
defer resp.Body.Close()
// This might not work if we never got a body. We'll ignore errors in trying to read,
Expand All @@ -1871,7 +1955,8 @@ func (c *Client) HandleTaskError(resp *http.Response) (exitStatus string) {
return string(b)
}

// Check if the proxmox task has been completed
// CheckTask polls the API to check if the Proxmox task has been completed.
// It returns the body of the HTTP response and any HTTP error occurred during the request.
func (c *Client) CheckTask(resp *http.Response) (exitStatus string, err error) {
taskResponse, err := ResponseJSON(resp)
if err != nil {
Expand Down
86 changes: 86 additions & 0 deletions proxmox/config_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package proxmox

import (
"encoding/json"
"fmt"
)

// ConfigNetwork maps go variables to API parameters.
type ConfigNetwork struct {
Iface string `json:"iface,omitempty"`
Node string `json:"node,omitempty"`
Type string `json:"type,omitempty"`
Address string `json:"address,omitempty"`
Address6 string `json:"address6,omitempty"`
Autostart bool `json:"autostart,omitempty"`
BondPrimary string `json:"bond-primary,omitempty"`
BondMode string `json:"bond_mode,omitempty"`
BondXmitHashPolicy string `json:"bond_xmit_hash_policy,omitempty"`
BridgePorts string `json:"bridge_ports,omitempty"`
BridgeVlanAware bool `json:"bridge_vlan_aware,omitempty"`
CIDR string `json:"cidr,omitempty"`
CIDR6 string `json:"cidr6,omitempty"`
Comments string `json:"comments,omitempty"`
Comments6 string `json:"comments6,omitempty"`
Gateway string `json:"gateway,omitempty"`
Gateway6 string `json:"gateway6,omitempty"`
MTU int `json:"mtu,omitempty"`
Netmask string `json:"netmask,omitempty"`
Netmask6 int `json:"netmask6,omitempty"`
OVSBonds string `json:"ovs_bonds,omitempty"`
OVSBridge string `json:"ovs_bridge,omitempty"`
OVSOptions string `json:"ovs_options,omitempty"`
OVSPorts string `json:"ovs_ports,omitempty"`
OVSTag int `json:"ovs_tag,omitempty"`
Slaves string `json:"slaves,omitempty"`
VlanID int `json:"vlan-id,omitempty"`
VlanRawDevice string `json:"vlan-raw-device,omitempty"`
}

// NewConfigNetworkFromJSON takes in a byte array from a json encoded network
// configuration and stores it in config.
// It returns the newly created config with the passed in configuration stored
// and an error if one occurs unmarshalling the input data.
func NewConfigNetworkFromJSON(input []byte) (config *ConfigNetwork, err error) {
config = &ConfigNetwork{}
err = json.Unmarshal([]byte(input), config)
return
}

// MapToAPIParams converts the stored config into a parameter map to be
// sent to the API.
func (config ConfigNetwork) MapToAPIParams() map[string]interface{} {
params, _ := json.Marshal(&config)
var paramMap map[string]interface{}
json.Unmarshal(params, &paramMap)
return paramMap
}

// CreateNetwork creates a network on the Proxmox host with the stored
// config.
// It returns an error if the creation of the network fails.
func (config ConfigNetwork) CreateNetwork(client *Client) (err error) {
paramMap := config.MapToAPIParams()

exitStatus, err := client.CreateNetwork(config.Node, paramMap)
if err != nil {
params, _ := json.Marshal(&paramMap)
return fmt.Errorf("error creating network: %v\n\t\t api response: %s\n\t\t params: %v", err, exitStatus, string(params))
}
return
}


// UpdateNetwork updates a network on the Proxmox host with the stored
// config.
// It returns an error if updating the network fails.
func (config ConfigNetwork) UpdateNetwork(client *Client) (err error) {
paramMap := config.MapToAPIParams()

exitStatus, err := client.UpdateNetwork(config.Node, config.Iface, paramMap)
if err != nil {
params, _ := json.Marshal(paramMap)
return fmt.Errorf("error creating network: %v\n\t\t api response: %s\n\t\t params: %v", err, exitStatus, string(params))
}
return
}

0 comments on commit 98e99c2

Please sign in to comment.