Skip to content

Commit

Permalink
Change implementation approach to use a separate resource
Browse files Browse the repository at this point in the history
  • Loading branch information
ddelnano committed Aug 21, 2023
1 parent c5bbedd commit 92b825f
Show file tree
Hide file tree
Showing 7 changed files with 492 additions and 164 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
87 changes: 64 additions & 23 deletions client/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,24 @@ func (net Network) Compare(obj interface{}) bool {
return false
}

// type sharedNetworkRequestParams struct {
// Pool string `mapstructure:"pool"`
// Name string `mapstructure:"name"`
// Description string `mapstructure:"description,omitempty"`
// Mtu int `mapstructure:"mtu,omitempty"`
// }

type CreateNetworkRequest struct {
BondMode string `mapstructure:"bondMode,omitempty"`
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"`
PIFs []string `mapstructure:"pifs,omitempty"`
Vlan int `mapstructure:"vlan,omitempty"`
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"`

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

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

// Does network.set apply for bonded networks? It uses the automatic and defaultIsLocked parameters.
// That API call also allows for nbd, which is not supported for bonded networks to my knowledge
type CreateBondedNetworkRequest struct {
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"`

Automatic bool `mapstructure:"automatic"`
DefaultIsLocked bool `mapstructure:"defaultIsLocked"`
}

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

type UpdateNetworkRequest struct {
Id string `mapstructure:"id"`
Automatic bool `mapstructure:"automatic"`
Expand Down Expand Up @@ -101,25 +126,42 @@ func (c *Client) CreateNetwork(netReq CreateNetworkRequest) (*Network, error) {
delete(params, "automatic")
delete(params, "defaultIsLocked")

var err error
if len(netReq.PIFs) > 0 {
log.Printf("[DEBUG] params for network.createBonded: %#v", params)
log.Printf("[DEBUG] params for network.create: %#v", params)
err := c.Call("network.create", params, &id)

var result map[string]interface{}
err = c.Call("network.createBonded", params, &result)
if err != nil {
return nil, err
}
return c.waitForModifyNetwork(result["uuid"].(string), netReq, 10*time.Second)
if err != nil {
return nil, err
}

log.Printf("[DEBUG] params for network.create: %#v", params)
err = c.Call("network.create", params, &id)
// 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) 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 {
Expand All @@ -129,7 +171,6 @@ func (c *Client) CreateNetwork(netReq CreateNetworkRequest) (*Network, error) {
DefaultIsLocked: netReq.DefaultIsLocked,
})
}

return c.waitForModifyNetwork(id, netReq, 10*time.Second)
}

Expand Down
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
188 changes: 188 additions & 0 deletions xoa/resource_xenorchestra_bonded_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package xoa

import (
"errors"
"fmt"

"github.com/ddelnano/terraform-provider-xenorchestra/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

var validBondModes []string = []string{"balance-slb", "active-backup", "lacp"}

func resourceXoaBondedNetwork() *schema.Resource {
return &schema.Resource{
Create: resourceBondedNetworkCreate,
Delete: resourceBondedNetworkDelete,
Read: resourceBondedNetworkRead,
Update: resourceBondedNetworkUpdate,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
// Verify if network.set applies for bonded networks unconditionally or if it
// only works with a subset of the parameters

"automatic": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"default_is_locked": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "This argument controls whether the network should enforce VIF locking. This defaults to `false` which means that no filtering rules are applied.",
},
"name_label": &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "The name label of the network.",
},
"name_description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: netDefaultDesc,
},
"pif_ids": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
ForceNew: true,
Description: "The pifs (uuid) that should be used for this network.",
},
"bond_mode": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "The bond mode that should be used for this network.",
ValidateFunc: validation.StringInSlice(validBondModes, false),
},
"pool_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The pool id that this network should belong to.",
},
"mtu": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 1500,
ForceNew: true,
Description: "The MTU of the network. Defaults to `1500` if unspecified.",
},
},
}
}

func resourceBondedNetworkCreate(d *schema.ResourceData, m interface{}) error {
c := m.(client.XOClient)

pifsReq := []string{}
for _, pif := range d.Get("pif_ids").([]interface{}) {
pifsReq = append(pifsReq, pif.(string))
}
network, err := c.CreateBondedNetwork(client.CreateBondedNetworkRequest{
Automatic: d.Get("automatic").(bool),
DefaultIsLocked: d.Get("default_is_locked").(bool),
BondMode: d.Get("bond_mode").(string),
Name: d.Get("name_label").(string),
Description: d.Get("name_description").(string),
Pool: d.Get("pool_id").(string),
Mtu: d.Get("mtu").(int),
PIFs: pifsReq,
})
if err != nil {
return err
}
if len(network.PIFs) < 1 {
return errors.New("network should contain more than one PIF")
}
fmt.Printf("[WARNING] attempting to set pif_ids\n")
if err := d.Set("pif_ids", pifsReq); err != nil {
return errors.New("failed to set pif_ids attribute.")
}
return bondedNetworkToData(network, d)
}

func resourceBondedNetworkRead(d *schema.ResourceData, m interface{}) error {
c := m.(client.XOClient)
network, err := c.GetNetwork(
client.Network{Id: d.Id()})

if _, ok := err.(client.NotFound); ok {
d.SetId("")
return nil
}

if err != nil {
return err
}

if len(network.PIFs) < 1 {
return errors.New("network should contain more than one PIF")
}
return bondedNetworkToData(network, d)
}

func resourceBondedNetworkUpdate(d *schema.ResourceData, m interface{}) error {
c := m.(client.XOClient)

netUpdateReq := client.UpdateNetworkRequest{
Id: d.Id(),
Automatic: d.Get("automatic").(bool),
DefaultIsLocked: d.Get("default_is_locked").(bool),
}
if d.HasChange("name_label") {
nameLabel := d.Get("name_label").(string)
netUpdateReq.NameLabel = &nameLabel
}
if d.HasChange("name_description") {
nameDescription := d.Get("name_description").(string)
netUpdateReq.NameDescription = &nameDescription
}
_, err := c.UpdateNetwork(netUpdateReq)
if err != nil {
return err
}
return resourceBondedNetworkRead(d, m)
}

func resourceBondedNetworkDelete(d *schema.ResourceData, m interface{}) error {
c := m.(client.XOClient)

err := c.DeleteNetwork(d.Id())

if err != nil {
return err
}
d.SetId("")
return nil
}

func bondedNetworkToData(network *client.Network, d *schema.ResourceData) error {
d.SetId(network.Id)
if err := d.Set("name_label", network.NameLabel); err != nil {
return err
}
if err := d.Set("name_description", network.NameDescription); err != nil {
return err
}
if err := d.Set("pool_id", network.PoolId); err != nil {
return err
}
if err := d.Set("mtu", network.MTU); err != nil {
return err
}

if err := d.Set("automatic", network.Automatic); err != nil {
return err
}
if err := d.Set("default_is_locked", network.DefaultIsLocked); err != nil {
return err
}
return nil
}
Loading

0 comments on commit 92b825f

Please sign in to comment.