ignore the order of the elements in a list (#455)

This commit is contained in:
Heng Lu 2024-04-22 14:47:20 +08:00 коммит произвёл GitHub
Родитель 388e86e417
Коммит 1a5e281f85
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 238 добавлений и 5 удалений

Просмотреть файл

@ -14,6 +14,7 @@ ENHANCEMENTS:
- `azapi_resource` resource, `azapi_update_resource` resource, `azapi_resource_action` resource, `azapi_data_plane_resource` resource, `azapi_resource_action` data source, `azapi_resource` data source, `azapi_resource_list` data source: The `output` field supports the dynamic schema and allows user to read the output as an HCL object.
- `azapi` provider: Support `client_id_file_path`and `client_secret_file_path` fields, which are used to specify the file path of the client id and client secret.
- `azapi_data_plane_resource` resource: Support `Microsoft.Synapse/workspaces/databases` type.
- `azapi_resource` resource, `azapi_update_resource` resource: Ignore the order of the elements in a list if the element has a `name` field as identifier.
BUG FIXES:
- Fix a bug that `azapi_resource_action` doesn't support 204 status code as a success response.

Просмотреть файл

@ -129,6 +129,20 @@ func TestAccGenericUpdateResource_ignoreChangesArray(t *testing.T) {
})
}
func TestAccGenericUpdateResource_ignoreOrderInArray(t *testing.T) {
data := acceptance.BuildTestData(t, "azapi_update_resource", "test")
r := GenericUpdateResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.ignoreOrderInArray(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
})
}
func (r GenericUpdateResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) {
resourceType := state.Attributes["type"]
id, err := parse.ResourceIDWithResourceType(state.ID, resourceType)
@ -372,6 +386,69 @@ resource "azapi_update_resource" "test" {
`, r.template(data), data.RandomInt())
}
func (r GenericUpdateResource) ignoreOrderInArray(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
resource "azapi_resource" "vnet" {
type = "Microsoft.Network/virtualNetworks@2023-09-01"
parent_id = azurerm_resource_group.test.id
name = "acctest%[2]d"
location = azurerm_resource_group.test.location
body = {
properties = {
addressSpace = {
addressPrefixes = [
"10.0.0.0/16",
]
}
dhcpOptions = {
dnsServers = [
]
}
subnets = [
{
name = "first"
properties = {
addressPrefix = "10.0.3.0/24"
}
},
{
name = "second"
properties = {
addressPrefix = "10.0.4.0/24"
}
}
]
}
}
}
resource "azapi_update_resource" "test" {
type = "Microsoft.Network/virtualNetworks@2022-07-01"
resource_id = azapi_resource.vnet.id
body = {
properties = {
subnets = [
{
name = "second"
properties = {
addressPrefix = "10.0.4.0/24"
}
},
{
name = "first"
properties = {
addressPrefix = "10.0.3.0/24"
}
}
]
}
}
}
`, r.template(data), data.RandomInt())
}
func (GenericUpdateResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
terraform {

Просмотреть файл

@ -81,12 +81,23 @@ func UpdateObject(old interface{}, new interface{}, option UpdateJsonOption) int
}
case []interface{}:
if newArr, ok := new.([]interface{}); ok {
if len(oldValue) != len(newArr) {
return newArr
}
res := make([]interface{}, 0)
for index := range oldValue {
res = append(res, UpdateObject(oldValue[index], newArr[index], option))
used := make([]bool, len(newArr))
for _, oldItem := range oldValue {
for index, newItem := range newArr {
if areSameArrayItems(oldItem, newItem) {
res = append(res, UpdateObject(oldItem, newItem, option))
used[index] = true
break
}
}
}
for index, newItem := range newArr {
if !used[index] {
res = append(res, newItem)
}
}
return res
}
@ -103,6 +114,31 @@ func UpdateObject(old interface{}, new interface{}, option UpdateJsonOption) int
return new
}
func areSameArrayItems(a, b interface{}) bool {
aId := identifierOfArrayItem(a)
bId := identifierOfArrayItem(b)
if aId == "" || bId == "" {
return false
}
return aId == bId
}
func identifierOfArrayItem(input interface{}) string {
inputMap, ok := input.(map[string]interface{})
if !ok {
return ""
}
name := inputMap["name"]
if name == nil {
return ""
}
nameValue, ok := name.(string)
if !ok {
return ""
}
return nameValue
}
// ExtractObject is used to extract object from old for a json path
func ExtractObject(old interface{}, path string) interface{} {
if len(path) == 0 {

Просмотреть файл

@ -17,6 +17,125 @@ func Test_UpdateObject(t *testing.T) {
}{
{
OldJson: `
{
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"dhcpOptions": {
"dnsServers": null
},
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "10.0.3.0/24"
}
}
]
}
}
`,
NewJson: `
{
"etag": "W/\"5633f421-aaa4-4cf3-b9a6-40625807bd75\"",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/virtualNetworks/henglu422",
"location": "westus",
"name": "henglu422",
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"dhcpOptions": {
"dnsServers": []
},
"enableDdosProtection": false,
"provisioningState": "Succeeded",
"resourceGuid": "86ec5186-a958-4b83-b5e7-3b88a728c34c",
"subnets": [
{
"etag": "W/\"5633f421-aaa4-4cf3-b9a6-40625807bd75\"",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/virtualNetworks/henglu422/subnets/henglu422",
"name": "henglu422",
"properties": {
"addressPrefix": "10.0.2.0/24",
"delegations": [],
"networkSecurityGroup": {
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/networkSecurityGroups/NRMS-zpedr2ai6dglmhenglu422"
},
"privateEndpointNetworkPolicies": "Disabled",
"privateLinkServiceNetworkPolicies": "Enabled",
"provisioningState": "Succeeded"
},
"type": "Microsoft.Network/virtualNetworks/subnets"
},
{
"etag": "W/\"5633f421-aaa4-4cf3-b9a6-40625807bd75\"",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/virtualNetworks/henglu422/subnets/default",
"name": "default",
"properties": {
"addressPrefix": "10.0.3.0/24",
"delegations": [],
"networkSecurityGroup": {
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/networkSecurityGroups/NRMS-zpedr2ai6dglmhenglu422"
},
"privateEndpointNetworkPolicies": "Disabled",
"privateLinkServiceNetworkPolicies": "Enabled",
"provisioningState": "Succeeded"
},
"type": "Microsoft.Network/virtualNetworks/subnets"
}
],
"virtualNetworkPeerings": []
},
"type": "Microsoft.Network/virtualNetworks"
}
`,
ExpectJson: `
{
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"dhcpOptions": {
"dnsServers": []
},
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "10.0.3.0/24"
}
},
{
"etag": "W/\"5633f421-aaa4-4cf3-b9a6-40625807bd75\"",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/virtualNetworks/henglu422/subnets/henglu422",
"name": "henglu422",
"properties": {
"addressPrefix": "10.0.2.0/24",
"delegations": [],
"networkSecurityGroup": {
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/henglu422/providers/Microsoft.Network/networkSecurityGroups/NRMS-zpedr2ai6dglmhenglu422"
},
"privateEndpointNetworkPolicies": "Disabled",
"privateLinkServiceNetworkPolicies": "Enabled",
"provisioningState": "Succeeded"
},
"type": "Microsoft.Network/virtualNetworks/subnets"
}
]
}
}
`,
},
{
OldJson: `
{
"properties": {
"compression": "None",