Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data opennebula virtual network address range #550

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions opennebula/data_opennebula_virtual_network_address_range.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package opennebula

import (
"context"
"fmt"
"log"
"strconv"
"strings"

vn "github.com/OpenNebula/one/src/oca/go/src/goca/schemas/virtualnetwork"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// Define the schema for the data source.
func dataSourceOpennebulaVirtualNetworkAddressRange() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceOpennebulaVirtualNetworkAddressRangeRead,
Schema: map[string]*schema.Schema{
"virtual_network_id": {
Type: schema.TypeInt,
Required: true,
Description: "Id of the virtual network",
},
"id": {
Type: schema.TypeString,
Required: true,
Description: "Id of the virtual network range",
},
"ar_type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of the Address Range: IP4, IP6, IP4_6",
},
"ip4": {
Type: schema.TypeString,
Computed: true,
Description: "Start IPv4 of the range to be allocated",
},
"ip4_end": {
Type: schema.TypeString,
Computed: true,
Description: "End IPv4 of the range to be allocated",
},
"ip6": {
Type: schema.TypeString,
Computed: true,
Description: "Start IPv6 of the range to be allocated",
},
"ip6_end": {
Type: schema.TypeString,
Computed: true,
Description: "End IPv6 of the range to be allocated",
},
"ip6_global": {
Type: schema.TypeString,
Computed: true,
Description: "Global IPv6 of the range to be allocated",
},
"ip6_global_end": {
Type: schema.TypeString,
Computed: true,
Description: "End Global IPv6 of the range to be allocated",
},
"ip6_ula": {
Type: schema.TypeString,
Computed: true,
Description: "ULA IPv6 of the range to be allocated",
},
"ip6_ula_end": {
Type: schema.TypeString,
Computed: true,
Description: "End ULA IPv6 of the range to be allocated",
},
"size": {
Type: schema.TypeInt,
Computed: true,
Description: "Count of addresses in the IP range",
},
"mac": {
Type: schema.TypeString,
Computed: true,
Description: "Start MAC of the range to be allocated",
},
"mac_end": {
Type: schema.TypeString,
Computed: true,
Description: "End MAC of the range to be allocated",
},
"global_prefix": {
Type: schema.TypeString,
Computed: true,
Description: "Global prefix for IP6 or IP4_6",
},
"ula_prefix": {
Type: schema.TypeString,
Computed: true,
Description: "ULA prefix for IP6 or IP4_6",
},
"held_ips": {
Type: schema.TypeSet,
Computed: true,
Description: "List of IPs held in this address range",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"custom": {
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

// Read the address range of a virtual network.
func dataSourceOpennebulaVirtualNetworkAddressRangeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics

// Get configuration from meta.
config := meta.(*Configuration)
controller := config.Controller
virtualNetworkID := d.Get("virtual_network_id").(int)
addressRangeIDStr := d.Get("id").(string)

// Convert addressRangeIDStr to an integer.
addressRangeID, err := strconv.Atoi(addressRangeIDStr)
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid address range ID",
Detail: fmt.Sprintf("Address Range ID should be an integer, got: %s", addressRangeIDStr),
})
return diags
}

// Retrieve information about the virtual network.
virtualNetworkInfo, err := controller.VirtualNetwork(virtualNetworkID).Info(false)
if err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Failed to retrieve information about the virtual network",
Detail: fmt.Sprintf("Virtual Network (ID:%d): %s", virtualNetworkID, err),
})
return diags
}

// Validate the address range ID.
if addressRangeID < 0 || addressRangeID >= len(virtualNetworkInfo.ARs) {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Address Range ID out of bounds",
Detail: fmt.Sprintf("Address Range ID (ID:%d) is out of bounds for Virtual Network (ID:%d)", addressRangeID, virtualNetworkID),
})
return diags
}

// Get the specified address range.
addressRange := virtualNetworkInfo.ARs[addressRangeID]

// Flatten the address range and set the fields.
flattenedAddressRange := flattenAddressRange(addressRange)
for key, value := range flattenedAddressRange {
d.Set(key, value)
}

// Set the ID of the resource.
d.SetId(fmt.Sprintf("%d", addressRangeID))
log.Printf("[INFO] Successfully retrieved address range of the virtual network\n")

return diags
}

// Flatten the structure of a virtual network address range into a usable form.
func flattenAddressRange(ar vn.AR) map[string]interface{} {
addressRange := make(map[string]interface{})

// Populate fields.
addressRange["ar_type"] = ar.Type
addressRange["ip4"] = ar.IP
addressRange["ip4_end"] = ar.IPEnd
addressRange["ip6"] = ar.IP6
addressRange["ip6_end"] = ar.IP6End
addressRange["ip6_global"] = ar.IP6Global
addressRange["ip6_global_end"] = ar.IP6GlobalEnd
addressRange["ip6_ula"] = ar.IP6ULA
addressRange["ip6_ula_end"] = ar.IP6ULAEnd
addressRange["size"] = ar.Size
addressRange["mac"] = ar.MAC
addressRange["mac_end"] = ar.MACEnd
addressRange["global_prefix"] = ar.GlobalPrefix
addressRange["ula_prefix"] = ar.ULAPrefix

// Flatten held IPs.
heldIPs := make([]interface{}, len(ar.Leases))
for i, lease := range ar.Leases {
heldIPs[i] = lease.IP
}
addressRange["held_ips"] = heldIPs

// Flatten custom attributes.
custom := make(map[string]interface{})
for _, pair := range ar.Custom {
custom[strings.ToLower(pair.Key())] = pair.Value
}
addressRange["custom"] = custom

return addressRange
}
165 changes: 165 additions & 0 deletions opennebula/data_opennebula_virtual_network_address_range_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package opennebula

import (
"context"
"strconv"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccDataSourceOpennebulaVirtualNetworkAddressRange(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVirtualNetworkAddressRangeDestroy,
Steps: []resource.TestStep{
{
Config: testAccDataSourceVirtualNetworkAddressRangeConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("opennebula_virtual_network.test_vnet", "id"),
resource.TestCheckResourceAttrSet("opennebula_virtual_network_address_range.test_ar_1", "id"),
resource.TestCheckResourceAttrSet("opennebula_virtual_network_address_range.test_ar_2", "id"),
),
},
{
Config: testAccDataSourceVirtualNetworkAddressRangeConfig + testAccDataSourceVirtualNetworkAddressRange1,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(
"data.opennebula_virtual_network_address_range.test_ar_1", "virtual_network_id",
"opennebula_virtual_network.test_vnet", "id",
),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ar_type", "IP4"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "size", "16"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip4", "172.16.100.110"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip4_end", "172.16.100.125"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "global_prefix", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ula_prefix", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6_end", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6_global", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6_global_end", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6_ula", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "ip6_ula_end", ""),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "mac", "02:00:00:00:00:01"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "mac_end", "02:00:00:00:00:10"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "held_ips.#", "1"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "held_ips.0", "172.16.100.112"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "custom.%", "2"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "custom.key1", "value1"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_1", "custom.key2", "value2"),
),
},
{
Config: testAccDataSourceVirtualNetworkAddressRangeConfig + testAccDataSourceVirtualNetworkAddressRange2,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(
"data.opennebula_virtual_network_address_range.test_ar_2", "virtual_network_id",
"opennebula_virtual_network.test_vnet", "id",
),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_2", "ar_type", "IP6_STATIC"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_2", "size", "15"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_2", "ip6", "2001:db8::1"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_2", "ip6_end", "2001:db8::f"),
resource.TestCheckResourceAttr("data.opennebula_virtual_network_address_range.test_ar_2", "mac", "02:00:00:00:01:01"),
),
},
},
})
}

func testAccCheckVirtualNetworkAddressRangeDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Configuration)
controller := config.Controller

for _, rs := range s.RootModule().Resources {
if rs.Type == "opennebula_virtual_network" && rs.Primary.Attributes["name"] == "test_vnet" {
vnID, _ := strconv.ParseUint(rs.Primary.ID, 10, 0)
vnc := controller.VirtualNetwork(int(vnID))

// Wait for Virtual Network deleted
stateConf := &resource.StateChangeConf{
Pending: []string{"exists"},
Target: []string{"deleted"},
Refresh: func() (any, string, error) {

vn, _ := vnc.Info(false)
if vn == nil {
return vn, "deleted", nil
}

return vn, "exists", nil
},
Timeout: 1 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err := stateConf.WaitForStateContext(context.Background())

return err
}
}

return nil
}

var testAccDataSourceVirtualNetworkAddressRangeConfig = `
resource "opennebula_virtual_network" "test_vnet" {
name = "test-vnet"
type = "dummy"
bridge = "onebr"
mtu = 1500
gateway = "172.16.100.1"
dns = "172.16.100.1"
network_mask = "255.255.255.0"
network_address = "172.16.100.0"
search_domain = "example.com"

permissions = "642"
group = "oneadmin"
security_groups = [0]
tags = {
env = "dev"
customer = "test"
}
}

resource "opennebula_virtual_network_address_range" "test_ar_1" {
virtual_network_id = opennebula_virtual_network.test_vnet.id
ar_type = "IP4"
size = 16
ip4 = "172.16.100.110"
hold_ips = ["172.16.100.112"]
mac = "02:00:00:00:00:01"
custom = {
key1 = "value1"
key2 = "value2"
}
}

resource "opennebula_virtual_network_address_range" "test_ar_2" {
virtual_network_id = opennebula_virtual_network.test_vnet.id
ar_type = "IP6_STATIC"
size = 15
ip6 = "2001:db8::1"
prefix_length = "64"
mac = "02:00:00:00:01:01"
}
`

var testAccDataSourceVirtualNetworkAddressRange1 = `
data "opennebula_virtual_network_address_range" "test_ar_1" {
virtual_network_id = opennebula_virtual_network.test_vnet.id
id = opennebula_virtual_network_address_range.test_ar_1.id
}
`

var testAccDataSourceVirtualNetworkAddressRange2 = `
data "opennebula_virtual_network_address_range" "test_ar_2" {
virtual_network_id = opennebula_virtual_network.test_vnet.id
id = opennebula_virtual_network_address_range.test_ar_2.id
}
`
Loading
Loading