Skip to content

Commit 09200bd

Browse files
committed
Merge branch 'main' of https://github.com/apache/cloudstack-terraform-provider into add-autoscale-support
2 parents 532ff37 + afa7a18 commit 09200bd

File tree

59 files changed

+7415
-257
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+7415
-257
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ When Docker started the container you can go to http://localhost:8080/client and
142142
Once the login page is shown and you can login, you need to provision a simulated data-center:
143143

144144
```sh
145-
docker exec -it cloudstack-simulator python /root/tools/marvin/marvin/deployDataCenter.py -i /root/setup/dev/advanced.cfg
145+
docker exec -it simulator python /root/tools/marvin/marvin/deployDataCenter.py -i /root/setup/dev/advanced.cfg
146146
```
147147

148148
If you refresh the client or login again, you will now get passed the initial welcome screen and be able to go to your account details and retrieve the API key and secret. Export those together with the URL:
@@ -206,7 +206,7 @@ Check and ensure TF provider passes builds, GA and run this for local checks:
206206
goreleaser release --snapshot --clean
207207
```
208208

209-
Next, create a personalised Github token: https://github.com/settings/tokens/new?scopes=repo,write:packages
209+
Next, create a personalised Github token: https://github.com/settings/tokens/new?scopes=repo,write:packages
210210

211211
```
212212
export GITHUB_TOKEN="YOUR_GH_TOKEN"
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
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+
"fmt"
24+
"log"
25+
"reflect"
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 dataSourceCloudstackCluster() *schema.Resource {
34+
return &schema.Resource{
35+
Read: datasourceCloudStackClusterRead,
36+
Schema: map[string]*schema.Schema{
37+
"filter": dataSourceFiltersSchema(),
38+
39+
//Computed values
40+
"id": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
},
44+
"allocation_state": {
45+
Description: "Allocation state of this cluster for allocation of new resources",
46+
Type: schema.TypeString,
47+
Computed: true,
48+
},
49+
"cluster_name": {
50+
Description: "the cluster name",
51+
Type: schema.TypeString,
52+
Computed: true,
53+
},
54+
"name": {
55+
Type: schema.TypeString,
56+
Computed: true,
57+
},
58+
"cluster_type": {
59+
Description: "Type of the cluster: CloudManaged, ExternalManaged",
60+
Type: schema.TypeString,
61+
Computed: true,
62+
},
63+
"guest_vswitch_name": {
64+
Description: "Name of virtual switch used for guest traffic in the cluster. This would override zone wide traffic label setting.",
65+
Type: schema.TypeString,
66+
Computed: true,
67+
},
68+
"guest_vswitch_type": {
69+
Description: "Type of virtual switch used for guest traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)",
70+
Type: schema.TypeString,
71+
Computed: true,
72+
},
73+
"hypervisor": {
74+
Description: "hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator,Ovm3",
75+
Type: schema.TypeString,
76+
Computed: true,
77+
},
78+
"ovm3_cluster": {
79+
Description: "Ovm3 native OCFS2 clustering enabled for cluster",
80+
Type: schema.TypeString,
81+
Computed: true,
82+
},
83+
"ovm3_pool": {
84+
Description: "Ovm3 native pooling enabled for cluster",
85+
Type: schema.TypeString,
86+
Computed: true,
87+
},
88+
"ovm3_vip": {
89+
Description: "Ovm3 vip to use for pool (and cluster)",
90+
Type: schema.TypeString,
91+
Computed: true,
92+
},
93+
"ovm3vip": {
94+
Type: schema.TypeString,
95+
Computed: true,
96+
},
97+
"password": {
98+
Description: "the password for the host",
99+
Type: schema.TypeString,
100+
Computed: true,
101+
Sensitive: true,
102+
},
103+
"public_vswitch_name": {
104+
Description: "Name of virtual switch used for public traffic in the cluster. This would override zone wide traffic label setting.",
105+
Type: schema.TypeString,
106+
Computed: true,
107+
},
108+
"public_vswitch_type": {
109+
Description: "Type of virtual switch used for public traffic in the cluster. Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch)",
110+
Type: schema.TypeString,
111+
Computed: true,
112+
},
113+
"pod_id": {
114+
Description: "The Pod ID for the cluster",
115+
Type: schema.TypeString,
116+
Computed: true,
117+
},
118+
"pod_name": {
119+
Type: schema.TypeString,
120+
Computed: true,
121+
},
122+
"url": {
123+
Description: "the URL",
124+
Type: schema.TypeString,
125+
Computed: true,
126+
},
127+
"username": {
128+
Description: "the username for the cluster",
129+
Type: schema.TypeString,
130+
Computed: true,
131+
},
132+
"vsm_ip_address": {
133+
Description: "the ipaddress of the VSM associated with this cluster",
134+
Type: schema.TypeString,
135+
Computed: true,
136+
},
137+
"vsm_password": {
138+
Description: "the password for the VSM associated with this cluster",
139+
Type: schema.TypeString,
140+
Computed: true,
141+
Sensitive: true,
142+
},
143+
"vsm_username": {
144+
Description: "the username for the VSM associated with this cluster",
145+
Type: schema.TypeString,
146+
Computed: true,
147+
},
148+
"zone_id": {
149+
Description: "the Zone ID for the cluster",
150+
Type: schema.TypeString,
151+
Computed: true,
152+
},
153+
"zone_name": {
154+
Type: schema.TypeString,
155+
Computed: true,
156+
},
157+
"managed_state": {
158+
Type: schema.TypeString,
159+
Computed: true,
160+
},
161+
"cpu_overcommit_ratio": {
162+
Type: schema.TypeString,
163+
Computed: true,
164+
},
165+
"memory_overcommit_ratio": {
166+
Type: schema.TypeString,
167+
Computed: true,
168+
},
169+
"arch": {
170+
Type: schema.TypeString,
171+
Computed: true,
172+
},
173+
"capacity": {
174+
Type: schema.TypeList,
175+
Computed: true,
176+
Elem: &schema.Resource{
177+
Schema: map[string]*schema.Schema{
178+
"capacity_allocated": {
179+
Type: schema.TypeInt,
180+
Computed: true,
181+
},
182+
"capacity_total": {
183+
Type: schema.TypeInt,
184+
Computed: true,
185+
},
186+
"capacity_used": {
187+
Type: schema.TypeInt,
188+
Computed: true,
189+
},
190+
"cluster_id": {
191+
Type: schema.TypeString,
192+
Computed: true,
193+
},
194+
"cluster_name": {
195+
Type: schema.TypeString,
196+
Computed: true,
197+
},
198+
"name": {
199+
Type: schema.TypeString,
200+
Computed: true,
201+
},
202+
"percent_used": {
203+
Type: schema.TypeInt,
204+
Computed: true,
205+
},
206+
"pod_id": {
207+
Type: schema.TypeString,
208+
Computed: true,
209+
},
210+
"pod_name": {
211+
Type: schema.TypeString,
212+
Computed: true,
213+
},
214+
"type": {
215+
Type: schema.TypeString,
216+
Computed: true,
217+
},
218+
"zone_id": {
219+
Type: schema.TypeString,
220+
Computed: true,
221+
},
222+
"zone_name": {
223+
Type: schema.TypeString,
224+
Computed: true,
225+
},
226+
},
227+
},
228+
},
229+
},
230+
}
231+
}
232+
233+
func dsFlattenClusterCapacity(capacity []cloudstack.ClusterCapacity) []map[string]interface{} {
234+
cap := make([]map[string]interface{}, len(capacity))
235+
for i, c := range capacity {
236+
cap[i] = map[string]interface{}{
237+
"capacity_allocated": c.Capacityallocated,
238+
"capacity_total": c.Capacitytotal,
239+
"capacity_used": c.Capacityused,
240+
"cluster_id": c.Clusterid,
241+
"cluster_name": c.Clustername,
242+
"name": c.Name,
243+
"percent_used": c.Percentused,
244+
"pod_id": c.Podid,
245+
"pod_name": c.Podname,
246+
"type": c.Type,
247+
"zone_id": c.Zoneid,
248+
"zone_name": c.Zonename,
249+
}
250+
}
251+
return cap
252+
}
253+
254+
func datasourceCloudStackClusterRead(d *schema.ResourceData, meta interface{}) error {
255+
cs := meta.(*cloudstack.CloudStackClient)
256+
p := cs.Cluster.NewListClustersParams()
257+
258+
csClusters, err := cs.Cluster.ListClusters(p)
259+
if err != nil {
260+
return fmt.Errorf("failed to list clusters: %s", err)
261+
}
262+
263+
filters := d.Get("filter")
264+
265+
for _, cluster := range csClusters.Clusters {
266+
match, err := applyClusterFilters(cluster, filters.(*schema.Set))
267+
if err != nil {
268+
return err
269+
}
270+
if match {
271+
return clusterDescriptionAttributes(d, cluster)
272+
}
273+
}
274+
275+
return fmt.Errorf("no clusters found")
276+
}
277+
278+
func clusterDescriptionAttributes(d *schema.ResourceData, cluster *cloudstack.Cluster) error {
279+
d.SetId(cluster.Id)
280+
281+
fields := map[string]interface{}{
282+
"id": cluster.Id,
283+
"allocation_state": cluster.Allocationstate,
284+
"cluster_name": cluster.Name,
285+
"name": cluster.Name,
286+
"cluster_type": cluster.Clustertype,
287+
"hypervisor": cluster.Hypervisortype,
288+
"ovm3_vip": cluster.Ovm3vip,
289+
"ovm3vip": cluster.Ovm3vip,
290+
"pod_id": cluster.Podid,
291+
"pod_name": cluster.Podname,
292+
"zone_id": cluster.Zoneid,
293+
"zone_name": cluster.Zonename,
294+
"managed_state": cluster.Managedstate,
295+
"cpu_overcommit_ratio": cluster.Cpuovercommitratio,
296+
"memory_overcommit_ratio": cluster.Memoryovercommitratio,
297+
"arch": cluster.Arch,
298+
"capacity": dsFlattenClusterCapacity(cluster.Capacity),
299+
}
300+
301+
// Set fields that may not be available in all cluster responses to empty strings
302+
// These are typically only available during cluster creation/configuration
303+
emptyStringFields := []string{
304+
"guest_vswitch_name",
305+
"guest_vswitch_type",
306+
"ovm3_cluster",
307+
"ovm3_pool",
308+
"password",
309+
"public_vswitch_name",
310+
"public_vswitch_type",
311+
"url",
312+
"username",
313+
"vsm_ip_address",
314+
"vsm_password",
315+
"vsm_username",
316+
}
317+
318+
for k, v := range fields {
319+
if err := d.Set(k, v); err != nil {
320+
log.Printf("[WARN] Error setting %s: %s", k, err)
321+
}
322+
}
323+
324+
for _, field := range emptyStringFields {
325+
if err := d.Set(field, ""); err != nil {
326+
log.Printf("[WARN] Error setting %s: %s", field, err)
327+
}
328+
}
329+
330+
return nil
331+
}
332+
333+
func applyClusterFilters(cluster *cloudstack.Cluster, filters *schema.Set) (bool, error) {
334+
val := reflect.ValueOf(cluster).Elem()
335+
336+
for _, f := range filters.List() {
337+
filter := f.(map[string]interface{})
338+
r, err := regexp.Compile(filter["value"].(string))
339+
if err != nil {
340+
return false, fmt.Errorf("invalid regex: %s", err)
341+
}
342+
updatedName := strings.ReplaceAll(filter["name"].(string), "_", "")
343+
clusterField := val.FieldByNameFunc(func(fieldName string) bool {
344+
if strings.EqualFold(fieldName, updatedName) {
345+
updatedName = fieldName
346+
return true
347+
}
348+
return false
349+
}).String()
350+
351+
if r.MatchString(clusterField) {
352+
return true, nil
353+
}
354+
}
355+
356+
return false, nil
357+
}

0 commit comments

Comments
 (0)