Skip to content

Commit b465bd5

Browse files
committed
Add support for empty yang containers to gnmi resource
1 parent 7b20b84 commit b465bd5

File tree

7 files changed

+47
-14
lines changed

7 files changed

+47
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 0.4.0 (unreleased)
22

33
- BREAKING CHANGE: Refactor resource import functionality to use a comma separated list of key attribute values instead of a gNMI path
4+
- Add support for empty YANG containers to the `iosxr_gnmi` resource using the `<EMPTY>` keyword
45

56
## 0.3.2
67

docs/guides/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ description: |-
1010
## 0.4.0 (unreleased)
1111

1212
- BREAKING CHANGE: Refactor resource import functionality to use a comma separated list of key attribute values instead of a gNMI path
13+
- Add support for empty YANG containers to the `iosxr_gnmi` resource using the `<EMPTY>` keyword
1314

1415
## 0.3.2
1516

docs/resources/gnmi.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ resource "iosxr_gnmi" "domain_host" {
6565

6666
### Optional
6767

68-
- `attributes` (Map of String) Map of key-value pairs which represents the attributes and its values.
68+
- `attributes` (Map of String) Map of key-value pairs which represents the attributes and its values. To indicate an empty YANG container use `<EMPTY>` as the value.
6969
- `delete` (Boolean) Delete object during destroy operation. Default value is `true`.
7070
- `device` (String) A device name from the provider configuration.
7171
- `lists` (Attributes List) YANG lists. (see [below for nested schema](#nestedatt--lists))
@@ -83,7 +83,7 @@ Required:
8383

8484
Optional:
8585

86-
- `items` (List of Map of String) List of maps of key-value pairs which represents the attributes and its values.
86+
- `items` (List of Map of String) List of maps of key-value pairs which represents the attributes and its values. To indicate an empty YANG container use `<EMPTY>` as the value.
8787
- `key` (String) YANG list key attribute(s). In case of multiple keys, those should be separated by a comma (`,`).
8888
- `values` (List of String) YANG leaf-list values.
8989

internal/provider/model_iosxr_gnmi.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ import (
2525
"github.com/CiscoDevNet/terraform-provider-iosxr/internal/provider/helpers"
2626
"github.com/hashicorp/terraform-plugin-framework/diag"
2727
"github.com/hashicorp/terraform-plugin-framework/types"
28+
"github.com/hashicorp/terraform-plugin-log/tflog"
2829
"github.com/tidwall/gjson"
2930
"github.com/tidwall/sjson"
3031
)
3132

33+
const (
34+
EMPTY_TAG string = "<EMPTY>"
35+
)
36+
3237
type Gnmi struct {
3338
Device types.String `tfsdk:"device"`
3439
Id types.String `tfsdk:"id"`
@@ -64,7 +69,12 @@ func (data Gnmi) toBody(ctx context.Context) string {
6469

6570
for attr, value := range attributes {
6671
attr = strings.ReplaceAll(attr, "/", ".")
67-
body, _ = sjson.Set(body, attr, value)
72+
tflog.Debug(ctx, fmt.Sprintf("Setting attribute %s to %s", attr, value))
73+
if value == EMPTY_TAG {
74+
body, _ = sjson.Set(body, attr, map[string]interface{}{})
75+
} else {
76+
body, _ = sjson.Set(body, attr, value)
77+
}
6878
}
6979

7080
for i := range data.Lists {
@@ -77,7 +87,11 @@ func (data Gnmi) toBody(ctx context.Context) string {
7787
attrs := ""
7888
for attr, value := range listAttributes {
7989
attr = strings.ReplaceAll(attr, "/", ".")
80-
attrs, _ = sjson.Set(attrs, attr, value)
90+
if value == EMPTY_TAG {
91+
attrs, _ = sjson.Set(attrs, attr, map[string]interface{}{})
92+
} else {
93+
attrs, _ = sjson.Set(attrs, attr, value)
94+
}
8195
}
8296
body, _ = sjson.SetRaw(body, listName+".-1", attrs)
8397
}
@@ -107,10 +121,9 @@ func (data *Gnmi) fromBody(ctx context.Context, res []byte) diag.Diagnostics {
107121
for attr := range attributes {
108122
attrPath := strings.ReplaceAll(attr, "/", ".")
109123
value := gjson.GetBytes(res, attrPath)
110-
if !value.Exists() ||
111-
(value.IsObject() && len(value.Map()) == 0) ||
112-
value.Raw == "[null]" {
113-
124+
if value.IsObject() && len(value.Map()) == 0 {
125+
attributes[attr] = types.StringValue(EMPTY_TAG)
126+
} else if !value.Exists() || value.Raw == "[null]" {
114127
if !helpers.Contains(keys, attr) {
115128
attributes[attr] = types.StringValue("")
116129
}
@@ -166,10 +179,9 @@ func (data *Gnmi) fromBody(ctx context.Context, res []byte) diag.Diagnostics {
166179
for attr := range listAttributes {
167180
attrPath := strings.ReplaceAll(attr, "/", ".")
168181
value := r.Get(attrPath)
169-
if !value.Exists() ||
170-
(value.IsObject() && len(value.Map()) == 0) ||
171-
value.Raw == "[null]" {
172-
182+
if value.IsObject() && len(value.Map()) == 0 {
183+
listAttributes[attr] = types.StringValue(EMPTY_TAG)
184+
} else if !value.Exists() || value.Raw == "[null]" {
173185
listAttributes[attr] = types.StringValue("")
174186
} else {
175187
listAttributes[attr] = types.StringValue(value.String())

internal/provider/resource_iosxr_gnmi.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (r *GnmiResource) Schema(ctx context.Context, req resource.SchemaRequest, r
7979
Default: booldefault.StaticBool(true),
8080
},
8181
"attributes": schema.MapAttribute{
82-
MarkdownDescription: "Map of key-value pairs which represents the attributes and its values.",
82+
MarkdownDescription: "Map of key-value pairs which represents the attributes and its values. To indicate an empty YANG container use `<EMPTY>` as the value.",
8383
Optional: true,
8484
ElementType: types.StringType,
8585
},
@@ -97,7 +97,7 @@ func (r *GnmiResource) Schema(ctx context.Context, req resource.SchemaRequest, r
9797
Optional: true,
9898
},
9999
"items": schema.ListAttribute{
100-
MarkdownDescription: "List of maps of key-value pairs which represents the attributes and its values.",
100+
MarkdownDescription: "List of maps of key-value pairs which represents the attributes and its values. To indicate an empty YANG container use `<EMPTY>` as the value.",
101101
Optional: true,
102102
ElementType: types.MapType{ElemType: types.StringType},
103103
},

internal/provider/resource_iosxr_gnmi_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ func TestAccIosxrGnmi(t *testing.T) {
7070
resource.TestCheckResourceAttr("iosxr_gnmi.test", "lists.0.values.0", "1.2.3.4"),
7171
),
7272
},
73+
{
74+
Config: testAccIosxrGnmiConfig_yangEmpty(),
75+
Check: resource.ComposeTestCheckFunc(
76+
resource.TestCheckResourceAttr("iosxr_gnmi.test", "attributes.redistribute/static", "<EMPTY>"),
77+
),
78+
},
7379
},
7480
})
7581
}
@@ -133,3 +139,15 @@ func testAccIosxrGnmiConfig_leafList() string {
133139
}
134140
`
135141
}
142+
143+
func testAccIosxrGnmiConfig_yangEmpty() string {
144+
return `
145+
resource "iosxr_gnmi" "test" {
146+
path = "Cisco-IOS-XR-um-router-bgp-cfg:/router/bgp/as[as-number=10]/address-families/address-family[af-name=ipv6-unicast]"
147+
attributes = {
148+
"af-name" = "ipv6-unicast"
149+
"redistribute/static" = "<EMPTY>"
150+
}
151+
}
152+
`
153+
}

templates/guides/changelog.md.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ description: |-
1010
## 0.4.0 (unreleased)
1111

1212
- BREAKING CHANGE: Refactor resource import functionality to use a comma separated list of key attribute values instead of a gNMI path
13+
- Add support for empty YANG containers to the `iosxr_gnmi` resource using the `<EMPTY>` keyword
1314

1415
## 0.3.2
1516

0 commit comments

Comments
 (0)