Skip to content

Commit

Permalink
Add xenorchestra_bonded_network resource (#253)
Browse files Browse the repository at this point in the history
* First attempt on bonded support. Implemented within the existing xenorchestra_network resource

* Change implementation approach to use a separate resource

* Remove stale comments and commented code

* Add documentation for xenorchestra_bonded_network

* Minor comment edits

* Add example for using PIFs on a VLAN and remove unnecessary print statement
  • Loading branch information
ddelnano authored Sep 27, 2023
1 parent 7a13658 commit bb40c5d
Show file tree
Hide file tree
Showing 9 changed files with 597 additions and 24 deletions.
1 change: 1 addition & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type XOClient interface {
CreateNetwork(netReq CreateNetworkRequest) (*Network, error)
GetNetwork(netReq Network) (*Network, error)
UpdateNetwork(netReq UpdateNetworkRequest) (*Network, error)
CreateBondedNetwork(netReq CreateBondedNetworkRequest) (*Network, error)
GetNetworks() ([]Network, error)
DeleteNetwork(id string) error

Expand Down
62 changes: 57 additions & 5 deletions client/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,21 @@ func (net Network) Compare(obj interface{}) bool {
}

type CreateNetworkRequest struct {
// The first set of members are shared between bonded and non bonded networks
// These should be kept in sync with the CreateBondedNetworkRequest struct
// Refactoring these fields to an embedded struct means that the caller must
// know the embedded structs existance. Since the list is relatively small
// this was deemed a more appropriate tradeoff to make the API nicer.
Automatic bool `mapstructure:"automatic"`
DefaultIsLocked bool `mapstructure:"defaultIsLocked"`
Pool string `mapstructure:"pool"`
Name string `mapstructure:"name"`
Nbd bool `mapstructure:"nbd,omitempty"`
Description string `mapstructure:"description,omitempty"`
Mtu int `mapstructure:"mtu,omitempty"`
PIF string `mapstructure:"pif,omitempty"`
Vlan int `mapstructure:"vlan,omitempty"`
Automatic bool `mapstructure:"automatic"`
DefaultIsLocked bool `mapstructure:"defaultIsLocked"`

Nbd bool `mapstructure:"nbd,omitempty"`
PIF string `mapstructure:"pif,omitempty"`
Vlan int `mapstructure:"vlan,omitempty"`
}

// Nbd and Automatic are eventually consistent. This ensures that waitForModifyNetwork will
Expand All @@ -70,6 +76,24 @@ func (c CreateNetworkRequest) Propagated(obj interface{}) bool {
return false
}

type CreateBondedNetworkRequest struct {
// The first set of members are shared between bonded and non bonded networks
// These should be kept in sync with the CreateNetworkRequest struct
Automatic bool `mapstructure:"automatic"`
DefaultIsLocked bool `mapstructure:"defaultIsLocked"`
Pool string `mapstructure:"pool"`
Name string `mapstructure:"name"`
Description string `mapstructure:"description,omitempty"`
Mtu int `mapstructure:"mtu,omitempty"`

BondMode string `mapstructure:"bondMode,omitempty"`
PIFs []string `mapstructure:"pifs,omitempty"`
}

func (c CreateBondedNetworkRequest) Propagated(obj interface{}) bool {
return true
}

type UpdateNetworkRequest struct {
Id string `mapstructure:"id"`
Automatic bool `mapstructure:"automatic"`
Expand Down Expand Up @@ -119,6 +143,34 @@ func (c *Client) CreateNetwork(netReq CreateNetworkRequest) (*Network, error) {
return c.waitForModifyNetwork(id, netReq, 10*time.Second)
}

func (c *Client) CreateBondedNetwork(netReq CreateBondedNetworkRequest) (*Network, error) {
var params map[string]interface{}
mapstructure.Decode(netReq, &params)

delete(params, "automatic")
delete(params, "defaultIsLocked")

log.Printf("[DEBUG] params for network.createBonded: %#v", params)

var result map[string]interface{}
err := c.Call("network.createBonded", params, &result)
if err != nil {
return nil, err
}

id := result["uuid"].(string)
// Neither automatic nor defaultIsLocked can be specified in the network.create RPC.
// Update them afterwards if the user requested it during creation.
if netReq.Automatic || netReq.DefaultIsLocked {
_, err = c.UpdateNetwork(UpdateNetworkRequest{
Id: id,
Automatic: netReq.Automatic,
DefaultIsLocked: netReq.DefaultIsLocked,
})
}
return c.waitForModifyNetwork(id, netReq, 10*time.Second)
}

func (c *Client) waitForModifyNetwork(id string, target RefreshComparison, timeout time.Duration) (*Network, error) {
refreshFn := func() (result interface{}, state string, err error) {
network, err := c.GetNetwork(Network{Id: id})
Expand Down
18 changes: 10 additions & 8 deletions client/pif.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import (
)

type PIF struct {
Device string `json:"device"`
Host string `json:"$host"`
Network string `json:"$network"`
Id string `json:"id"`
Uuid string `json:"uuid"`
PoolId string `json:"$poolId"`
Attached bool `json:"attached"`
Vlan int `json:"vlan"`
Device string `json:"device"`
Host string `json:"$host"`
Network string `json:"$network"`
Id string `json:"id"`
Uuid string `json:"uuid"`
PoolId string `json:"$poolId"`
Attached bool `json:"attached"`
Vlan int `json:"vlan"`
IsBondMaster bool `json:"isBondMaster,omitempty"`
IsBondSlave bool `json:"isBondSlave,omitempty"`
}

func (p PIF) Compare(obj interface{}) bool {
Expand Down
7 changes: 2 additions & 5 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,9 @@ provider "xenorchestra" {
<!-- schema generated by tfplugindocs -->
## Schema

### Required
### Optional

- `insecure` (Boolean) Whether SSL should be verified or not. Can be set via the XOA_INSECURE environment variable.
- `password` (String) Password for xoa api. Can be set via the XOA_PASSWORD environment variable.
- `url` (String) Hostname of the xoa router. Can be set via the XOA_URL environment variable.
- `username` (String) User account for xoa api. Can be set via the XOA_USER environment variable.

### Optional

- `insecure` (Boolean) Whether SSL should be verified or not. Can be set via the XOA_INSECURE environment variable.
87 changes: 87 additions & 0 deletions docs/resources/bonded_network.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "xenorchestra_bonded_network Resource - terraform-provider-xenorchestra"
subcategory: ""
description: |-
A resource for managing Bonded Xen Orchestra networks. See the XCP-ng networking docs https://xcp-ng.org/docs/networking.html for more details.
---

# xenorchestra_bonded_network (Resource)

A resource for managing Bonded Xen Orchestra networks. See the XCP-ng [networking docs](https://xcp-ng.org/docs/networking.html) for more details.

## Example Usage

```terraform
data "xenorchestra_host" "host1" {
name_label = "Your host"
}
data "xenorchestra_pif" "eth1" {
device = "eth1"
vlan = -1
host_id = data.xenorchestra_host.host1.id
}
data "xenorchestra_pif" "eth2" {
device = "eth2"
vlan = -1
host_id = data.xenorchestra_host.host1.id
}
# Create a bonded network from normal PIFs
resource "xenorchestra_bonded_network" "network" {
name_label = "new network name"
bond_mode = "active-backup"
pool_id = data.xenorchestra_host.host1.pool_id
pif_ids = [
data.xenorchestra_pif.eth1.id,
data.xenorchestra_pif.eth2.id,
]
}
# Create a bonded network from PIFs on VLANs
data "xenorchestra_pif" "eth1_vlan" {
device = "eth1"
vlan = 15
host_id = data.xenorchestra_host.host1.id
}
data "xenorchestra_pif" "eth2_vlan" {
device = "eth2"
vlan = 15
host_id = data.xenorchestra_host.host1.id
}
# Create a bonded network from normal PIFs
resource "xenorchestra_bonded_network" "network_vlan" {
name_label = "new network name"
bond_mode = "active-backup"
pool_id = data.xenorchestra_host.host1.pool_id
pif_ids = [
data.xenorchestra_pif.eth1_vlan.id,
data.xenorchestra_pif.eth2_vlan.id,
]
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name_label` (String) The name label of the network.
- `pool_id` (String) The pool id that this network should belong to.

### Optional

- `automatic` (Boolean)
- `bond_mode` (String) The bond mode that should be used for this network.
- `default_is_locked` (Boolean) This argument controls whether the network should enforce VIF locking. This defaults to `false` which means that no filtering rules are applied.
- `mtu` (Number) The MTU of the network. Defaults to `1500` if unspecified.
- `name_description` (String)
- `pif_ids` (List of String) The pifs (uuid) that should be used for this network.

### Read-Only

- `id` (String) The ID of this resource.
50 changes: 50 additions & 0 deletions examples/resources/xenorchestra_bonded_network/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
data "xenorchestra_host" "host1" {
name_label = "Your host"
}

data "xenorchestra_pif" "eth1" {
device = "eth1"
vlan = -1
host_id = data.xenorchestra_host.host1.id
}

data "xenorchestra_pif" "eth2" {
device = "eth2"
vlan = -1
host_id = data.xenorchestra_host.host1.id
}

# Create a bonded network from normal PIFs
resource "xenorchestra_bonded_network" "network" {
name_label = "new network name"
bond_mode = "active-backup"
pool_id = data.xenorchestra_host.host1.pool_id
pif_ids = [
data.xenorchestra_pif.eth1.id,
data.xenorchestra_pif.eth2.id,
]
}

# Create a bonded network from PIFs on VLANs
data "xenorchestra_pif" "eth1_vlan" {
device = "eth1"
vlan = 15
host_id = data.xenorchestra_host.host1.id
}

data "xenorchestra_pif" "eth2_vlan" {
device = "eth2"
vlan = 15
host_id = data.xenorchestra_host.host1.id
}

# Create a bonded network from normal PIFs
resource "xenorchestra_bonded_network" "network_vlan" {
name_label = "new network name"
bond_mode = "active-backup"
pool_id = data.xenorchestra_host.host1.pool_id
pif_ids = [
data.xenorchestra_pif.eth1_vlan.id,
data.xenorchestra_pif.eth2_vlan.id,
]
}
13 changes: 7 additions & 6 deletions xoa/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ func Provider() *schema.Provider {
},
},
ResourcesMap: map[string]*schema.Resource{
"xenorchestra_acl": resourceAcl(),
"xenorchestra_cloud_config": resourceCloudConfigRecord(),
"xenorchestra_network": resourceXoaNetwork(),
"xenorchestra_vm": resourceRecord(),
"xenorchestra_resource_set": resourceResourceSet(),
"xenorchestra_vdi": resourceVDIRecord(),
"xenorchestra_acl": resourceAcl(),
"xenorchestra_bonded_network": resourceXoaBondedNetwork(),
"xenorchestra_cloud_config": resourceCloudConfigRecord(),
"xenorchestra_network": resourceXoaNetwork(),
"xenorchestra_vm": resourceRecord(),
"xenorchestra_resource_set": resourceResourceSet(),
"xenorchestra_vdi": resourceVDIRecord(),
},
DataSourcesMap: map[string]*schema.Resource{
"xenorchestra_cloud_config": dataSourceXoaCloudConfig(),
Expand Down
Loading

0 comments on commit bb40c5d

Please sign in to comment.