Skip to content

Commit 3ba5e90

Browse files
committed
feat(servicestage/config_group): add new resource supports config group
1 parent 4ed097d commit 3ba5e90

File tree

4 files changed

+313
-0
lines changed

4 files changed

+313
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
subcategory: "ServiceStage"
3+
layout: "huaweicloud"
4+
page_title: "HuaweiCloud: huaweicloud_servicestagev3_configuration_group"
5+
description: |-
6+
Manages a configuration group resource within HuaweiCloud.
7+
---
8+
9+
# huaweicloud_servicestagev3_configuration_group
10+
11+
Manages a configuration group resource within HuaweiCloud.
12+
13+
## Example Usage
14+
15+
```hcl
16+
variables "config_group_name" {}
17+
18+
resource "huaweicloud_servicestagev3_configuration_group" "test" {
19+
name = var.config_group_name
20+
}
21+
```
22+
23+
## Argument Reference
24+
25+
The following arguments are supported:
26+
27+
* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource.
28+
If omitted, the provider-level region will be used. Changing this creates a new resource.
29+
30+
* `name` - (Required, String, NonUpdatable) Specifies the name of the configuration group.
31+
The valid length is limited from `2` to `64`, only letters, digits, hyphens (-) and underscores (_) are allowed.
32+
The name must start with a letter and end with a letter or a digit.
33+
34+
* `description` - (Optional, String, NonUpdatable) Specifies the description of the configuration group.
35+
The maximum length is `256` characters.
36+
37+
## Attribute Reference
38+
39+
In addition to all arguments above, the following attributes are exported:
40+
41+
* `id` - The resource ID, also configuration group ID.
42+
43+
* `creator` - The creator of the configuration group.
44+
45+
* `create_time` - The creation time of the configuration group, in milliseconds.
46+
47+
## Import
48+
49+
The resource can be imported using `id`, e.g.
50+
51+
```bash
52+
$ terraform import huaweicloud_servicestagev3_configuration_group.test <id>
53+
```

huaweicloud/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,7 @@ func Provider() *schema.Provider {
22852285
// v3 managements
22862286
"huaweicloud_servicestagev3_application": servicestage.ResourceV3Application(),
22872287
"huaweicloud_servicestagev3_component": servicestage.ResourceV3Component(),
2288+
"huaweicloud_servicestagev3_configuration_group": servicestage.ResourceV3ConfigurationGroup(),
22882289
"huaweicloud_servicestagev3_environment": servicestage.ResourceV3Environment(),
22892290
"huaweicloud_servicestagev3_environment_associate": servicestage.ResourceV3EnvironmentAssociate(),
22902291

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package servicestage
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10+
11+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
12+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
13+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/servicestage"
14+
)
15+
16+
func getV3ConfigurationGroup(conf *config.Config, state *terraform.ResourceState) (interface{}, error) {
17+
client, err := conf.NewServiceClient("servicestage", acceptance.HW_REGION_NAME)
18+
if err != nil {
19+
return nil, fmt.Errorf("error creating ServiceStage client: %s", err)
20+
}
21+
return servicestage.GetV3ConfigurationGroupById(client, state.Primary.ID)
22+
}
23+
24+
func TestAccV3ConfigurationGroup_basic(t *testing.T) {
25+
var (
26+
configurationGroup interface{}
27+
resourceName = "huaweicloud_servicestagev3_configuration_group.test"
28+
rc = acceptance.InitResourceCheck(resourceName, &configurationGroup, getV3ConfigurationGroup)
29+
30+
name = acceptance.RandomAccResourceName()
31+
)
32+
33+
resource.ParallelTest(t, resource.TestCase{
34+
PreCheck: func() { acceptance.TestAccPreCheck(t) },
35+
ProviderFactories: acceptance.TestAccProviderFactories,
36+
CheckDestroy: rc.CheckResourceDestroy(),
37+
Steps: []resource.TestStep{
38+
{
39+
Config: testAccV3ConfigurationGroup_basic(name),
40+
Check: resource.ComposeTestCheckFunc(
41+
rc.CheckResourceExists(),
42+
resource.TestCheckResourceAttr(resourceName, "name", name),
43+
resource.TestCheckResourceAttr(resourceName, "description", "Created by terraform test"),
44+
resource.TestCheckResourceAttrSet(resourceName, "creator"),
45+
resource.TestMatchResourceAttr(resourceName, "created_at",
46+
regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
47+
),
48+
},
49+
{
50+
ResourceName: resourceName,
51+
ImportState: true,
52+
ImportStateVerify: true,
53+
},
54+
},
55+
})
56+
}
57+
58+
func testAccV3ConfigurationGroup_basic(name string) string {
59+
return fmt.Sprintf(`
60+
resource "huaweicloud_servicestagev3_configuration_group" "test" {
61+
name = "%[1]s"
62+
description = "Created by terraform test"
63+
}
64+
`, name)
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package servicestage
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/hashicorp/go-multierror"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
12+
"github.com/chnsz/golangsdk"
13+
14+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/common"
15+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
16+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
17+
)
18+
19+
var v3ConfigurationGroupNonUpdatableParams = []string{"name", "description"}
20+
21+
// @API ServiceStage POST /v3/{project_id}/cas/config-groups
22+
// @API ServiceStage GET /v3/{project_id}/cas/config-groups/{config_group_id}
23+
// @API ServiceStage DELETE /v3/{project_id}/cas/config-groups/{config_group_id}
24+
func ResourceV3ConfigurationGroup() *schema.Resource {
25+
return &schema.Resource{
26+
CreateContext: resourceV3ConfigurationGroupCreate,
27+
ReadContext: resourceV3ConfigurationGroupRead,
28+
UpdateContext: resourceV3ConfigurationGroupUpdate,
29+
DeleteContext: resourceV3ConfigurationGroupDelete,
30+
31+
CustomizeDiff: config.FlexibleForceNew(v3ConfigurationGroupNonUpdatableParams),
32+
33+
Importer: &schema.ResourceImporter{
34+
StateContext: schema.ImportStatePassthroughContext,
35+
},
36+
37+
Schema: map[string]*schema.Schema{
38+
"region": {
39+
Type: schema.TypeString,
40+
Optional: true,
41+
Computed: true,
42+
ForceNew: true,
43+
},
44+
"name": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
Description: `The name of the configuration group.`,
48+
},
49+
"description": {
50+
Type: schema.TypeString,
51+
Optional: true,
52+
Description: `The description of the configuration group.`,
53+
},
54+
"creator": {
55+
Type: schema.TypeString,
56+
Computed: true,
57+
Description: `The creator of the configuration group.`,
58+
},
59+
"created_at": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
Description: `The creation time of the configuration group, in milliseconds.`,
63+
},
64+
},
65+
}
66+
}
67+
68+
func buildV3ConfigurationGroupCreateBodyParams(d *schema.ResourceData) map[string]interface{} {
69+
return map[string]interface{}{
70+
"name": d.Get("name"),
71+
"description": utils.ValueIgnoreEmpty(d.Get("description")),
72+
}
73+
}
74+
75+
func resourceV3ConfigurationGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
76+
var (
77+
cfg = meta.(*config.Config)
78+
httpUrl = "v3/{project_id}/cas/config-groups"
79+
)
80+
client, err := cfg.NewServiceClient("servicestage", cfg.GetRegion(d))
81+
if err != nil {
82+
return diag.Errorf("error creating ServiceStage client: %s", err)
83+
}
84+
85+
createPath := client.Endpoint + httpUrl
86+
createPath = strings.ReplaceAll(createPath, "{project_id}", client.ProjectID)
87+
opt := golangsdk.RequestOpts{
88+
KeepResponseBody: true,
89+
MoreHeaders: map[string]string{
90+
"Content-Type": "application/json;charset=utf8",
91+
},
92+
JSONBody: utils.RemoveNil(buildV3ConfigurationGroupCreateBodyParams(d)),
93+
}
94+
95+
requestResp, err := client.Request("POST", createPath, &opt)
96+
if err != nil {
97+
return diag.Errorf("error creating configuration group: %s", err)
98+
}
99+
100+
respBody, err := utils.FlattenResponse(requestResp)
101+
if err != nil {
102+
return diag.FromErr(err)
103+
}
104+
105+
configGroupId := utils.PathSearch("id", respBody, "").(string)
106+
if configGroupId == "" {
107+
return diag.Errorf("unable to find the configuration group ID from the API response")
108+
}
109+
d.SetId(configGroupId)
110+
111+
return resourceV3ConfigurationGroupRead(ctx, d, meta)
112+
}
113+
114+
// GetV3ConfigurationGroupById is a method used to get configuration group detail bu its ID.
115+
func GetV3ConfigurationGroupById(client *golangsdk.ServiceClient, configGroupId string) (interface{}, error) {
116+
httpUrl := "v3/{project_id}/cas/config-groups/{config_group_id}"
117+
getPath := client.Endpoint + httpUrl
118+
getPath = strings.ReplaceAll(getPath, "{project_id}", client.ProjectID)
119+
getPath = strings.ReplaceAll(getPath, "{config_group_id}", configGroupId)
120+
opt := golangsdk.RequestOpts{
121+
KeepResponseBody: true,
122+
MoreHeaders: map[string]string{
123+
"Content-Type": "application/json;charset=utf8",
124+
},
125+
}
126+
127+
requestResp, err := client.Request("GET", getPath, &opt)
128+
if err != nil {
129+
return nil, err
130+
}
131+
132+
return utils.FlattenResponse(requestResp)
133+
}
134+
135+
func resourceV3ConfigurationGroupRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
136+
var (
137+
cfg = meta.(*config.Config)
138+
region = cfg.GetRegion(d)
139+
configGroupId = d.Id()
140+
)
141+
client, err := cfg.NewServiceClient("servicestage", region)
142+
if err != nil {
143+
return diag.Errorf("error creating ServiceStage client: %s", err)
144+
}
145+
146+
respBody, err := GetV3ConfigurationGroupById(client, configGroupId)
147+
if err != nil {
148+
return common.CheckDeletedDiag(d, err, fmt.Sprintf("error retrieving configuration group (%s)", configGroupId))
149+
}
150+
151+
mErr := multierror.Append(nil,
152+
d.Set("region", region),
153+
d.Set("name", utils.PathSearch("name", respBody, nil)),
154+
d.Set("description", utils.PathSearch("description", respBody, nil)),
155+
d.Set("creator", utils.PathSearch("creator", respBody, nil)),
156+
d.Set("created_at", utils.FormatTimeStampRFC3339(int64(utils.PathSearch("create_time", respBody,
157+
float64(0)).(float64))/1000, false)))
158+
159+
return diag.FromErr(mErr.ErrorOrNil())
160+
}
161+
162+
func resourceV3ConfigurationGroupUpdate(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics {
163+
return nil
164+
}
165+
166+
func resourceV3ConfigurationGroupDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
167+
var (
168+
cfg = meta.(*config.Config)
169+
region = cfg.GetRegion(d)
170+
httpUrl = "v3/{project_id}/cas/config-groups/{config_group_id}"
171+
configGroupId = d.Id()
172+
)
173+
client, err := cfg.NewServiceClient("servicestage", region)
174+
if err != nil {
175+
return diag.Errorf("error creating ServiceStage client: %s", err)
176+
}
177+
178+
deletePath := client.Endpoint + httpUrl
179+
deletePath = strings.ReplaceAll(deletePath, "{project_id}", client.ProjectID)
180+
deletePath = strings.ReplaceAll(deletePath, "{config_group_id}", configGroupId)
181+
opt := golangsdk.RequestOpts{
182+
KeepResponseBody: true,
183+
MoreHeaders: map[string]string{
184+
"Content-Type": "application/json;charset=utf8",
185+
},
186+
}
187+
188+
// The delete API always returns 200 status code whether config group is exist.
189+
_, err = client.Request("DELETE", deletePath, &opt)
190+
if err != nil {
191+
return common.CheckDeletedDiag(d, err, fmt.Sprintf("error deleting configuration group (%s)", configGroupId))
192+
}
193+
return nil
194+
}

0 commit comments

Comments
 (0)