Skip to content

Commit a8c34cd

Browse files
authored
Add cloudstack_physicalnetwork and some underlying additional resources (#201)
1 parent cbb254b commit a8c34cd

13 files changed

+1819
-39
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package cloudstack
21+
22+
import (
23+
"encoding/json"
24+
"fmt"
25+
"log"
26+
"regexp"
27+
"strings"
28+
29+
"github.com/apache/cloudstack-go/v2/cloudstack"
30+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
31+
)
32+
33+
func dataSourceCloudStackPhysicalNetwork() *schema.Resource {
34+
return &schema.Resource{
35+
Read: dataSourceCloudStackPhysicalNetworkRead,
36+
Schema: map[string]*schema.Schema{
37+
"filter": dataSourceFiltersSchema(),
38+
39+
//Computed values
40+
"name": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
},
44+
"zone": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
},
48+
"broadcast_domain_range": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
"isolation_methods": {
53+
Type: schema.TypeList,
54+
Computed: true,
55+
Elem: &schema.Schema{Type: schema.TypeString},
56+
},
57+
"network_speed": {
58+
Type: schema.TypeString,
59+
Computed: true,
60+
},
61+
"vlan": {
62+
Type: schema.TypeString,
63+
Computed: true,
64+
},
65+
},
66+
}
67+
}
68+
69+
func dataSourceCloudStackPhysicalNetworkRead(d *schema.ResourceData, meta interface{}) error {
70+
cs := meta.(*cloudstack.CloudStackClient)
71+
p := cs.Network.NewListPhysicalNetworksParams()
72+
physicalNetworks, err := cs.Network.ListPhysicalNetworks(p)
73+
74+
if err != nil {
75+
return fmt.Errorf("Failed to list physical networks: %s", err)
76+
}
77+
filters := d.Get("filter")
78+
var physicalNetwork *cloudstack.PhysicalNetwork
79+
80+
for _, pn := range physicalNetworks.PhysicalNetworks {
81+
match, err := applyPhysicalNetworkFilters(pn, filters.(*schema.Set))
82+
if err != nil {
83+
return err
84+
}
85+
if match {
86+
physicalNetwork = pn
87+
}
88+
}
89+
90+
if physicalNetwork == nil {
91+
return fmt.Errorf("No physical network is matching with the specified regex")
92+
}
93+
log.Printf("[DEBUG] Selected physical network: %s\n", physicalNetwork.Name)
94+
95+
return physicalNetworkDescriptionAttributes(d, physicalNetwork)
96+
}
97+
98+
func physicalNetworkDescriptionAttributes(d *schema.ResourceData, physicalNetwork *cloudstack.PhysicalNetwork) error {
99+
d.SetId(physicalNetwork.Id)
100+
d.Set("name", physicalNetwork.Name)
101+
d.Set("broadcast_domain_range", physicalNetwork.Broadcastdomainrange)
102+
d.Set("network_speed", physicalNetwork.Networkspeed)
103+
d.Set("vlan", physicalNetwork.Vlan)
104+
105+
// Set isolation methods
106+
if physicalNetwork.Isolationmethods != "" {
107+
methods := strings.Split(physicalNetwork.Isolationmethods, ",")
108+
d.Set("isolation_methods", methods)
109+
}
110+
111+
// Set the zone
112+
d.Set("zone", physicalNetwork.Zonename)
113+
114+
// Physical networks don't support tags in CloudStack API
115+
116+
return nil
117+
}
118+
119+
func applyPhysicalNetworkFilters(physicalNetwork *cloudstack.PhysicalNetwork, filters *schema.Set) (bool, error) {
120+
var physicalNetworkJSON map[string]interface{}
121+
k, _ := json.Marshal(physicalNetwork)
122+
err := json.Unmarshal(k, &physicalNetworkJSON)
123+
if err != nil {
124+
return false, err
125+
}
126+
127+
for _, f := range filters.List() {
128+
m := f.(map[string]interface{})
129+
r, err := regexp.Compile(m["value"].(string))
130+
if err != nil {
131+
return false, fmt.Errorf("Invalid regex: %s", err)
132+
}
133+
updatedName := strings.ReplaceAll(m["name"].(string), "_", "")
134+
physicalNetworkField := physicalNetworkJSON[updatedName].(string)
135+
if !r.MatchString(physicalNetworkField) {
136+
return false, nil
137+
}
138+
}
139+
return true, nil
140+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package cloudstack
21+
22+
import (
23+
"testing"
24+
25+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
26+
)
27+
28+
func TestAccDataSourceCloudStackPhysicalNetwork_basic(t *testing.T) {
29+
resource.Test(t, resource.TestCase{
30+
PreCheck: func() { testAccPreCheck(t) },
31+
Providers: testAccProviders,
32+
Steps: []resource.TestStep{
33+
{
34+
Config: testAccDataSourceCloudStackPhysicalNetwork_basic,
35+
Check: resource.ComposeTestCheckFunc(
36+
resource.TestCheckResourceAttr(
37+
"data.cloudstack_physicalnetwork.foo", "name", "terraform-physical-network"),
38+
resource.TestCheckResourceAttr(
39+
"data.cloudstack_physicalnetwork.foo", "broadcast_domain_range", "ZONE"),
40+
),
41+
},
42+
},
43+
})
44+
}
45+
46+
const testAccDataSourceCloudStackPhysicalNetwork_basic = `
47+
resource "cloudstack_zone" "foo" {
48+
name = "terraform-zone-ds"
49+
dns1 = "8.8.8.8"
50+
internal_dns1 = "8.8.4.4"
51+
network_type = "Advanced"
52+
}
53+
54+
resource "cloudstack_physicalnetwork" "foo" {
55+
name = "terraform-physical-network"
56+
zone = cloudstack_zone.foo.name
57+
broadcast_domain_range = "ZONE"
58+
isolation_methods = ["VLAN"]
59+
}
60+
61+
data "cloudstack_physicalnetwork" "foo" {
62+
filter {
63+
name = "name"
64+
value = "terraform-physical-network"
65+
}
66+
depends_on = [cloudstack_physicalnetwork.foo]
67+
}`

cloudstack/provider.go

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -90,54 +90,58 @@ func Provider() *schema.Provider {
9090
"cloudstack_user": dataSourceCloudstackUser(),
9191
"cloudstack_vpn_connection": dataSourceCloudstackVPNConnection(),
9292
"cloudstack_pod": dataSourceCloudstackPod(),
93+
"cloudstack_physicalnetwork": dataSourceCloudStackPhysicalNetwork(),
9394
},
9495

9596
ResourcesMap: map[string]*schema.Resource{
96-
"cloudstack_affinity_group": resourceCloudStackAffinityGroup(),
97-
"cloudstack_attach_volume": resourceCloudStackAttachVolume(),
98-
"cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(),
99-
"cloudstack_configuration": resourceCloudStackConfiguration(),
100-
"cloudstack_disk": resourceCloudStackDisk(),
101-
"cloudstack_egress_firewall": resourceCloudStackEgressFirewall(),
102-
"cloudstack_firewall": resourceCloudStackFirewall(),
103-
"cloudstack_host": resourceCloudStackHost(),
104-
"cloudstack_instance": resourceCloudStackInstance(),
105-
"cloudstack_ipaddress": resourceCloudStackIPAddress(),
106-
"cloudstack_kubernetes_cluster": resourceCloudStackKubernetesCluster(),
107-
"cloudstack_kubernetes_version": resourceCloudStackKubernetesVersion(),
108-
"cloudstack_loadbalancer_rule": resourceCloudStackLoadBalancerRule(),
109-
"cloudstack_network": resourceCloudStackNetwork(),
110-
"cloudstack_network_acl": resourceCloudStackNetworkACL(),
111-
"cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(),
112-
"cloudstack_nic": resourceCloudStackNIC(),
113-
"cloudstack_port_forward": resourceCloudStackPortForward(),
114-
"cloudstack_private_gateway": resourceCloudStackPrivateGateway(),
115-
"cloudstack_secondary_ipaddress": resourceCloudStackSecondaryIPAddress(),
116-
"cloudstack_security_group": resourceCloudStackSecurityGroup(),
117-
"cloudstack_security_group_rule": resourceCloudStackSecurityGroupRule(),
118-
"cloudstack_ssh_keypair": resourceCloudStackSSHKeyPair(),
119-
"cloudstack_static_nat": resourceCloudStackStaticNAT(),
120-
"cloudstack_static_route": resourceCloudStackStaticRoute(),
121-
"cloudstack_template": resourceCloudStackTemplate(),
122-
"cloudstack_vpc": resourceCloudStackVPC(),
123-
"cloudstack_vpn_connection": resourceCloudStackVPNConnection(),
124-
"cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(),
125-
"cloudstack_vpn_gateway": resourceCloudStackVPNGateway(),
126-
"cloudstack_network_offering": resourceCloudStackNetworkOffering(),
127-
"cloudstack_disk_offering": resourceCloudStackDiskOffering(),
128-
"cloudstack_volume": resourceCloudStackVolume(),
129-
"cloudstack_zone": resourceCloudStackZone(),
130-
"cloudstack_service_offering": resourceCloudStackServiceOffering(),
131-
"cloudstack_account": resourceCloudStackAccount(),
132-
"cloudstack_user": resourceCloudStackUser(),
133-
"cloudstack_domain": resourceCloudStackDomain(),
97+
"cloudstack_affinity_group": resourceCloudStackAffinityGroup(),
98+
"cloudstack_attach_volume": resourceCloudStackAttachVolume(),
99+
"cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(),
100+
"cloudstack_configuration": resourceCloudStackConfiguration(),
101+
"cloudstack_disk": resourceCloudStackDisk(),
102+
"cloudstack_egress_firewall": resourceCloudStackEgressFirewall(),
103+
"cloudstack_firewall": resourceCloudStackFirewall(),
104+
"cloudstack_host": resourceCloudStackHost(),
105+
"cloudstack_instance": resourceCloudStackInstance(),
106+
"cloudstack_ipaddress": resourceCloudStackIPAddress(),
107+
"cloudstack_kubernetes_cluster": resourceCloudStackKubernetesCluster(),
108+
"cloudstack_kubernetes_version": resourceCloudStackKubernetesVersion(),
109+
"cloudstack_loadbalancer_rule": resourceCloudStackLoadBalancerRule(),
110+
"cloudstack_network": resourceCloudStackNetwork(),
111+
"cloudstack_network_acl": resourceCloudStackNetworkACL(),
112+
"cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(),
113+
"cloudstack_nic": resourceCloudStackNIC(),
114+
"cloudstack_port_forward": resourceCloudStackPortForward(),
115+
"cloudstack_private_gateway": resourceCloudStackPrivateGateway(),
116+
"cloudstack_secondary_ipaddress": resourceCloudStackSecondaryIPAddress(),
117+
"cloudstack_security_group": resourceCloudStackSecurityGroup(),
118+
"cloudstack_security_group_rule": resourceCloudStackSecurityGroupRule(),
119+
"cloudstack_ssh_keypair": resourceCloudStackSSHKeyPair(),
120+
"cloudstack_static_nat": resourceCloudStackStaticNAT(),
121+
"cloudstack_static_route": resourceCloudStackStaticRoute(),
122+
"cloudstack_template": resourceCloudStackTemplate(),
123+
"cloudstack_vpc": resourceCloudStackVPC(),
124+
"cloudstack_vpn_connection": resourceCloudStackVPNConnection(),
125+
"cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(),
126+
"cloudstack_vpn_gateway": resourceCloudStackVPNGateway(),
127+
"cloudstack_network_offering": resourceCloudStackNetworkOffering(),
128+
"cloudstack_disk_offering": resourceCloudStackDiskOffering(),
129+
"cloudstack_volume": resourceCloudStackVolume(),
130+
"cloudstack_zone": resourceCloudStackZone(),
131+
"cloudstack_service_offering": resourceCloudStackServiceOffering(),
132+
"cloudstack_account": resourceCloudStackAccount(),
133+
"cloudstack_user": resourceCloudStackUser(),
134+
"cloudstack_domain": resourceCloudStackDomain(),
135+
"cloudstack_physicalnetwork": resourceCloudStackPhysicalNetwork(),
136+
"cloudstack_traffic_type": resourceCloudStackTrafficType(),
137+
"cloudstack_network_service_provider": resourceCloudStackNetworkServiceProvider(),
134138
},
135139

136140
ConfigureFunc: providerConfigure,
137141
}
138142
}
139143

140-
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
144+
func providerConfigure(d *schema.ResourceData) (any, error) {
141145
apiURL, apiURLOK := d.GetOk("api_url")
142146
apiKey, apiKeyOK := d.GetOk("api_key")
143147
secretKey, secretKeyOK := d.GetOk("secret_key")

0 commit comments

Comments
 (0)