Skip to content

Commit ed7ea5a

Browse files
committed
Add support for the new parameters added to CKS cluster deployement
1 parent 5105978 commit ed7ea5a

7 files changed

+508
-3
lines changed

cloudstack/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func Provider() *schema.Provider {
102102
"cloudstack_affinity_group": resourceCloudStackAffinityGroup(),
103103
"cloudstack_attach_volume": resourceCloudStackAttachVolume(),
104104
"cloudstack_autoscale_vm_profile": resourceCloudStackAutoScaleVMProfile(),
105+
"cloudstack_cni_configuration": resourceCloudStackCniConfiguration(),
105106
"cloudstack_configuration": resourceCloudStackConfiguration(),
106107
"cloudstack_cluster": resourceCloudStackCluster(),
107108
"cloudstack_disk": resourceCloudStackDisk(),
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
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+
"strings"
26+
27+
"github.com/apache/cloudstack-go/v2/cloudstack"
28+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
29+
)
30+
31+
func resourceCloudStackCniConfiguration() *schema.Resource {
32+
return &schema.Resource{
33+
Create: resourceCloudStackCniConfigurationCreate,
34+
Read: resourceCloudStackCniConfigurationRead,
35+
Delete: resourceCloudStackCniConfigurationDelete,
36+
Importer: &schema.ResourceImporter{
37+
State: importStatePassthrough,
38+
},
39+
40+
Schema: map[string]*schema.Schema{
41+
"name": {
42+
Type: schema.TypeString,
43+
Required: true,
44+
ForceNew: true,
45+
Description: "Name of the CNI configuration",
46+
},
47+
48+
"cni_config": {
49+
Type: schema.TypeString,
50+
Required: true,
51+
ForceNew: true,
52+
Description: "CNI Configuration content to be registered",
53+
},
54+
55+
"account": {
56+
Type: schema.TypeString,
57+
Optional: true,
58+
ForceNew: true,
59+
Description: "An optional account for the CNI configuration. Must be used with domain_id.",
60+
},
61+
62+
"domain_id": {
63+
Type: schema.TypeString,
64+
Optional: true,
65+
ForceNew: true,
66+
Description: "An optional domain ID for the CNI configuration. If the account parameter is used, domain_id must also be used.",
67+
},
68+
69+
"project_id": {
70+
Type: schema.TypeString,
71+
Optional: true,
72+
ForceNew: true,
73+
Description: "An optional project for the CNI configuration",
74+
},
75+
76+
"params": {
77+
Type: schema.TypeSet,
78+
Optional: true,
79+
ForceNew: true,
80+
Description: "List of variables declared in CNI configuration content",
81+
Elem: &schema.Schema{
82+
Type: schema.TypeString,
83+
},
84+
},
85+
},
86+
}
87+
}
88+
89+
func resourceCloudStackCniConfigurationCreate(d *schema.ResourceData, meta interface{}) error {
90+
cs := meta.(*cloudstack.CloudStackClient)
91+
92+
name := d.Get("name").(string)
93+
log.Printf("[DEBUG] Creating CNI configuration: %s", name)
94+
95+
p := cs.Configuration.NewRegisterCniConfigurationParams(name)
96+
97+
if v, ok := d.GetOk("cni_config"); ok {
98+
cniConfig := v.(string)
99+
log.Printf("[DEBUG] CNI config data length: %d bytes", len(cniConfig))
100+
p.SetCniconfig(cniConfig)
101+
} else {
102+
return fmt.Errorf("CNI configuration content is required but not provided")
103+
}
104+
105+
if account := d.Get("account").(string); account != "" {
106+
log.Printf("[DEBUG] Setting account: %s", account)
107+
p.SetAccount(account)
108+
}
109+
110+
if domainID := d.Get("domain_id").(string); domainID != "" {
111+
log.Printf("[DEBUG] Setting domain ID: %s", domainID)
112+
p.SetDomainid(domainID)
113+
}
114+
115+
if projectID := d.Get("project_id").(string); projectID != "" {
116+
log.Printf("[DEBUG] Setting project ID: %s", projectID)
117+
p.SetProjectid(projectID)
118+
}
119+
120+
if params, ok := d.GetOk("params"); ok {
121+
paramsList := []string{}
122+
for _, param := range params.(*schema.Set).List() {
123+
paramsList = append(paramsList, param.(string))
124+
}
125+
if len(paramsList) > 0 {
126+
paramsStr := strings.Join(paramsList, ",")
127+
log.Printf("[DEBUG] Setting params: %s", paramsStr)
128+
p.SetParams(paramsStr)
129+
}
130+
}
131+
132+
resp, err := cs.Configuration.RegisterCniConfiguration(p)
133+
if err != nil {
134+
return fmt.Errorf("Error creating CNI configuration %s: %s", name, err)
135+
}
136+
137+
log.Printf("[DEBUG] CNI configuration creation response: %+v", resp)
138+
139+
// List configurations to find the created one by name since direct ID access is not available
140+
listParams := cs.Configuration.NewListCniConfigurationParams()
141+
listParams.SetName(name)
142+
143+
// Add context parameters if available
144+
if account := d.Get("account").(string); account != "" {
145+
listParams.SetAccount(account)
146+
}
147+
if domainID := d.Get("domain_id").(string); domainID != "" {
148+
listParams.SetDomainid(domainID)
149+
}
150+
if projectID := d.Get("project_id").(string); projectID != "" {
151+
listParams.SetProjectid(projectID)
152+
}
153+
154+
listResp, err := cs.Configuration.ListCniConfiguration(listParams)
155+
if err != nil {
156+
return fmt.Errorf("Error listing CNI configurations after creation: %s", err)
157+
}
158+
159+
if listResp.Count == 0 {
160+
return fmt.Errorf("CNI configuration %s was created but could not be found", name)
161+
}
162+
163+
// Use the first (and should be only) result
164+
config := listResp.CniConfiguration[0]
165+
d.SetId(config.Id)
166+
log.Printf("[DEBUG] CNI configuration %s successfully created with ID: %s", name, d.Id())
167+
168+
return resourceCloudStackCniConfigurationRead(d, meta)
169+
}
170+
171+
func resourceCloudStackCniConfigurationRead(d *schema.ResourceData, meta interface{}) error {
172+
cs := meta.(*cloudstack.CloudStackClient)
173+
174+
log.Printf("[DEBUG] Reading CNI configuration: %s", d.Id())
175+
176+
p := cs.Configuration.NewListCniConfigurationParams()
177+
p.SetId(d.Id())
178+
179+
config, err := cs.Configuration.ListCniConfiguration(p)
180+
if err != nil {
181+
return fmt.Errorf("Error listing CNI configuration: %s", err)
182+
}
183+
if config.Count == 0 {
184+
log.Printf("[DEBUG] CNI configuration %s no longer exists", d.Id())
185+
d.SetId("")
186+
return nil
187+
}
188+
189+
d.Set("name", config.CniConfiguration[0].Name)
190+
d.Set("cni_config", config.CniConfiguration[0].Userdata)
191+
d.Set("account", config.CniConfiguration[0].Account)
192+
d.Set("domain_id", config.CniConfiguration[0].Domainid)
193+
d.Set("project_id", config.CniConfiguration[0].Projectid)
194+
195+
if config.CniConfiguration[0].Params != "" {
196+
paramsList := strings.Split(config.CniConfiguration[0].Params, ",")
197+
d.Set("params", paramsList)
198+
}
199+
200+
return nil
201+
}
202+
203+
func resourceCloudStackCniConfigurationDelete(d *schema.ResourceData, meta interface{}) error {
204+
cs := meta.(*cloudstack.CloudStackClient)
205+
206+
log.Printf("[DEBUG] Deleting CNI configuration: %s", d.Id())
207+
208+
p := cs.Configuration.NewDeleteCniConfigurationParams(d.Id())
209+
210+
_, err := cs.Configuration.DeleteCniConfiguration(p)
211+
if err != nil {
212+
if strings.Contains(err.Error(), "does not exist") ||
213+
strings.Contains(err.Error(), "not found") {
214+
log.Printf("[DEBUG] CNI configuration %s already deleted", d.Id())
215+
return nil
216+
}
217+
return fmt.Errorf("Error deleting CNI configuration %s: %s", d.Id(), err)
218+
}
219+
220+
log.Printf("[DEBUG] CNI configuration %s deleted", d.Id())
221+
return nil
222+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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+
"testing"
25+
26+
"github.com/apache/cloudstack-go/v2/cloudstack"
27+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
28+
"github.com/hashicorp/terraform-plugin-testing/terraform"
29+
)
30+
31+
func TestAccCloudStackCniConfiguration_basic(t *testing.T) {
32+
var cniConfig cloudstack.CniConfiguration
33+
34+
resource.Test(t, resource.TestCase{
35+
PreCheck: func() { testAccPreCheck(t) },
36+
Providers: testAccProviders,
37+
CheckDestroy: testAccCheckCloudStackCniConfigurationDestroy,
38+
Steps: []resource.TestStep{
39+
{
40+
Config: testAccCloudStackCniConfiguration_basic,
41+
Check: resource.ComposeTestCheckFunc(
42+
testAccCheckCloudStackCniConfigurationExists("cloudstack_cni_configuration.foo", &cniConfig),
43+
resource.TestCheckResourceAttr("cloudstack_cni_configuration.foo", "name", "test-cni-config"),
44+
resource.TestCheckResourceAttr("cloudstack_cni_configuration.foo", "params.#", "2"),
45+
),
46+
},
47+
},
48+
})
49+
}
50+
51+
func testAccCheckCloudStackCniConfigurationExists(n string, cniConfig *cloudstack.CniConfiguration) resource.TestCheckFunc {
52+
return func(s *terraform.State) error {
53+
rs, ok := s.RootModule().Resources[n]
54+
if !ok {
55+
return fmt.Errorf("Not found: %s", n)
56+
}
57+
58+
if rs.Primary.ID == "" {
59+
return fmt.Errorf("No CNI configuration ID is set")
60+
}
61+
62+
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
63+
config, _, err := cs.Configuration.GetCniConfigurationByID(rs.Primary.ID)
64+
if err != nil {
65+
return err
66+
}
67+
68+
if config.Id != rs.Primary.ID {
69+
return fmt.Errorf("CNI configuration not found")
70+
}
71+
72+
*cniConfig = *config
73+
return nil
74+
}
75+
}
76+
77+
func testAccCheckCloudStackCniConfigurationDestroy(s *terraform.State) error {
78+
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
79+
80+
for _, rs := range s.RootModule().Resources {
81+
if rs.Type != "cloudstack_cni_configuration" {
82+
continue
83+
}
84+
85+
if rs.Primary.ID == "" {
86+
return fmt.Errorf("No CNI configuration ID is set")
87+
}
88+
89+
_, _, err := cs.Configuration.GetCniConfigurationByID(rs.Primary.ID)
90+
if err == nil {
91+
return fmt.Errorf("CNI configuration %s still exists", rs.Primary.ID)
92+
}
93+
}
94+
95+
return nil
96+
}
97+
98+
const testAccCloudStackCniConfiguration_basic = `
99+
resource "cloudstack_cni_configuration" "foo" {
100+
name = "test-cni-config"
101+
cni_config = <<EOF
102+
{
103+
"cniVersion": "0.4.0",
104+
"name": "test-network",
105+
"type": "bridge",
106+
"bridge": "cni0",
107+
"isGateway": true,
108+
"ipMasq": true,
109+
"ipam": {
110+
"type": "host-local",
111+
"subnet": "10.244.0.0/16",
112+
"routes": [
113+
{ "dst": "0.0.0.0/0" }
114+
]
115+
}
116+
}
117+
EOF
118+
119+
params = ["subnet", "gateway"]
120+
}
121+
`

0 commit comments

Comments
 (0)