Skip to content

Commit c589c79

Browse files
authored
feat(fgs): add new data source to query function tags (#7565)
1 parent 8974fe6 commit c589c79

File tree

4 files changed

+304
-0
lines changed

4 files changed

+304
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
subcategory: "FunctionGraph"
3+
layout: "huaweicloud"
4+
page_title: "HuaweiCloud: huaweicloud_fgs_function_tags"
5+
description: |-
6+
Use this data source to query function tags within HuaweiCloud.
7+
---
8+
9+
# huaweicloud_fgs_function_tags
10+
11+
Use this data source to query function tags within HuaweiCloud.
12+
13+
## Example Usage
14+
15+
### Query function tags by function ID
16+
17+
```hcl
18+
variable "function_id" {}
19+
20+
data "huaweicloud_fgs_function_tags" "test" {
21+
function_id = var.function_id
22+
}
23+
```
24+
25+
## Argument Reference
26+
27+
The following arguments are supported:
28+
29+
* `region` - (Optional, String) Specifies the region where the function is located and tags to be queried.
30+
If omitted, the provider-level region will be used.
31+
32+
* `function_id` - (Required, String) Specifies the ID of the function to which the tags belong.
33+
34+
## Attribute Reference
35+
36+
In addition to all arguments above, the following attributes are exported:
37+
38+
* `id` - The data source ID.
39+
40+
* `tags` - The list of the function tags.
41+
The [tags](#fgs_function_tags_attr) structure is documented below.
42+
43+
<a name="fgs_function_tags_attr"></a>
44+
The `tags` block supports:
45+
46+
* `key` - The key of the tag.
47+
48+
* `value` - The value of the tag.

huaweicloud/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,7 @@ func Provider() *schema.Provider {
10201020
"huaweicloud_fgs_dependencies": fgs.DataSourceDependencies(),
10211021
"huaweicloud_fgs_dependency_versions": fgs.DataSourceDependencieVersions(),
10221022
"huaweicloud_fgs_function_events": fgs.DataSourceFunctionEvents(),
1023+
"huaweicloud_fgs_function_tags": fgs.DataSourceFunctionTags(),
10231024
"huaweicloud_fgs_function_triggers": fgs.DataSourceFunctionTriggers(),
10241025
"huaweicloud_fgs_functions": fgs.DataSourceFunctions(),
10251026
"huaweicloud_fgs_quotas": fgs.DataSourceQuotas(),
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package fgs
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
9+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
10+
)
11+
12+
func TestAccDataFunctionTags_basic(t *testing.T) {
13+
var (
14+
base = "huaweicloud_fgs_function.test"
15+
16+
all = "data.huaweicloud_fgs_function_tags.all"
17+
dcForAllTags = acceptance.InitDataSourceCheck(all)
18+
19+
byFunctionId = "data.huaweicloud_fgs_function_tags.filter_by_function_id"
20+
dcByFunctionId = acceptance.InitDataSourceCheck(byFunctionId)
21+
)
22+
23+
resource.ParallelTest(t, resource.TestCase{
24+
PreCheck: func() {
25+
acceptance.TestAccPreCheck(t)
26+
},
27+
ProviderFactories: acceptance.TestAccProviderFactories,
28+
Steps: []resource.TestStep{
29+
{
30+
Config: testAccDataFunctionTags_basic(),
31+
Check: resource.ComposeTestCheckFunc(
32+
// Without filter parameters.
33+
dcForAllTags.CheckResourceExists(),
34+
resource.TestCheckResourceAttrSet(all, "function_id"),
35+
// Filter by function ID.
36+
dcByFunctionId.CheckResourceExists(),
37+
resource.TestCheckOutput("is_function_id_filter_useful", "true"),
38+
// Check the attributes.
39+
resource.TestCheckResourceAttrPair(byFunctionId, "function_id", base, "urn"),
40+
resource.TestCheckResourceAttr(byFunctionId, "tags.#", "2"),
41+
resource.TestCheckResourceAttr(byFunctionId, "tags.0.key", "foo"),
42+
resource.TestCheckResourceAttr(byFunctionId, "tags.0.value", "bar"),
43+
resource.TestCheckResourceAttr(byFunctionId, "tags.1.key", "key"),
44+
resource.TestCheckResourceAttr(byFunctionId, "tags.1.value", "value"),
45+
),
46+
},
47+
},
48+
})
49+
}
50+
51+
func testAccDataFunctionTags_basic() string {
52+
name := acceptance.RandomAccResourceName()
53+
54+
return fmt.Sprintf(`
55+
variable "function_code_content" {
56+
type = string
57+
default = <<EOT
58+
def main():
59+
print("Hello, World!")
60+
61+
if __name__ == "__main__":
62+
main()
63+
EOT
64+
}
65+
66+
resource "huaweicloud_fgs_function" "test" {
67+
name = "%[1]s"
68+
memory_size = 128
69+
runtime = "Python2.7"
70+
timeout = 3
71+
app = "default"
72+
handler = "index.handler"
73+
code_type = "inline"
74+
func_code = base64encode(var.function_code_content)
75+
76+
tags = {
77+
foo = "bar"
78+
key = "value"
79+
}
80+
}
81+
82+
# Without any filter parameter.
83+
data "huaweicloud_fgs_function_tags" "all" {
84+
function_id = huaweicloud_fgs_function.test.id
85+
}
86+
87+
# Filter by function ID.
88+
locals {
89+
function_id = huaweicloud_fgs_function.test.id
90+
}
91+
92+
data "huaweicloud_fgs_function_tags" "filter_by_function_id" {
93+
function_id = local.function_id
94+
}
95+
96+
locals {
97+
function_id_filter_result = [for v in data.huaweicloud_fgs_function_tags.filter_by_function_id.tags[*].key :
98+
v == "foo" || v == "key"]
99+
}
100+
101+
output "is_function_id_filter_useful" {
102+
value = length(local.function_id_filter_result) == 2 && alltrue(local.function_id_filter_result)
103+
}
104+
`, name)
105+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package fgs
2+
3+
import (
4+
"context"
5+
"strings"
6+
7+
"github.com/hashicorp/go-multierror"
8+
"github.com/hashicorp/go-uuid"
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/config"
15+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
16+
)
17+
18+
// @API FunctionGraph GET /v2/{project_id}/{resource_type}/{resource_id}/tags
19+
func DataSourceFunctionTags() *schema.Resource {
20+
return &schema.Resource{
21+
ReadContext: dataSourceFunctionTagsRead,
22+
23+
Schema: map[string]*schema.Schema{
24+
"region": {
25+
Type: schema.TypeString,
26+
Optional: true,
27+
Computed: true,
28+
Description: `The region where the function is located and tags to be queried.`,
29+
},
30+
31+
// Required parameter(s).
32+
"function_id": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
Description: `The ID of the function to which the tags belong.`,
36+
},
37+
38+
// Attribute(s).
39+
"tags": {
40+
Type: schema.TypeList,
41+
Computed: true,
42+
Elem: &schema.Resource{
43+
Schema: map[string]*schema.Schema{
44+
"key": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
Description: `The key of the tag.`,
48+
},
49+
"value": {
50+
Type: schema.TypeString,
51+
Computed: true,
52+
Description: `The value of the tag.`,
53+
},
54+
},
55+
},
56+
Description: `The list of the function tags.`,
57+
},
58+
59+
// Internal attribute(s).
60+
"sys_tags": {
61+
Type: schema.TypeList,
62+
Computed: true,
63+
Elem: &schema.Resource{
64+
Schema: map[string]*schema.Schema{
65+
"key": {
66+
Type: schema.TypeString,
67+
Computed: true,
68+
Description: `The key of the system tag.`,
69+
},
70+
"value": {
71+
Type: schema.TypeString,
72+
Computed: true,
73+
Description: `The value of the system tag.`,
74+
},
75+
},
76+
},
77+
Description: utils.SchemaDesc(
78+
`The list of the system tags.`,
79+
utils.SchemaDescInput{
80+
Internal: true,
81+
},
82+
),
83+
},
84+
},
85+
}
86+
}
87+
88+
func getFunctionTags(client *golangsdk.ServiceClient, functionId string) (interface{}, error) {
89+
httpUrl := "v2/{project_id}/functions/{function_id}/tags"
90+
getPath := client.Endpoint + httpUrl
91+
getPath = strings.ReplaceAll(getPath, "{project_id}", client.ProjectID)
92+
getPath = strings.ReplaceAll(getPath, "{function_id}", functionId)
93+
94+
getOpts := golangsdk.RequestOpts{
95+
KeepResponseBody: true,
96+
MoreHeaders: map[string]string{
97+
"Content-Type": "application/json",
98+
},
99+
}
100+
101+
requestResp, err := client.Request("GET", getPath, &getOpts)
102+
if err != nil {
103+
return nil, err
104+
}
105+
return utils.FlattenResponse(requestResp)
106+
}
107+
108+
func flattenFunctionTags(tags []interface{}) []map[string]interface{} {
109+
if len(tags) < 1 {
110+
return nil
111+
}
112+
113+
result := make([]map[string]interface{}, 0, len(tags))
114+
for _, tag := range tags {
115+
result = append(result, map[string]interface{}{
116+
"key": utils.PathSearch("key", tag, nil),
117+
"value": utils.PathSearch("value", tag, nil),
118+
})
119+
}
120+
121+
return result
122+
}
123+
124+
func dataSourceFunctionTagsRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
125+
cfg := meta.(*config.Config)
126+
region := cfg.GetRegion(d)
127+
client, err := cfg.NewServiceClient("fgs", region)
128+
if err != nil {
129+
return diag.Errorf("error creating FunctionGraph client: %s", err)
130+
}
131+
132+
functionId := d.Get("function_id").(string)
133+
resp, err := getFunctionTags(client, functionId)
134+
if err != nil {
135+
return diag.Errorf("error querying FunctionGraph function tags: %s", err)
136+
}
137+
138+
randomUUID, err := uuid.GenerateUUID()
139+
if err != nil {
140+
return diag.Errorf("unable to generate ID: %s", err)
141+
}
142+
d.SetId(randomUUID)
143+
144+
mErr := multierror.Append(nil,
145+
d.Set("region", region),
146+
d.Set("tags", flattenFunctionTags(utils.PathSearch("tags", resp, make([]interface{}, 0)).([]interface{}))),
147+
d.Set("sys_tags", flattenFunctionTags(utils.PathSearch("sys_tags", resp, make([]interface{}, 0)).([]interface{}))),
148+
)
149+
return diag.FromErr(mErr.ErrorOrNil())
150+
}

0 commit comments

Comments
 (0)