Skip to content
This repository has been archived by the owner on Jun 17, 2024. It is now read-only.

Commit

Permalink
Re-designed the resource_configuration schema
Browse files Browse the repository at this point in the history
1. Re-designed the resource_configuration schema
2. Updated the create and update logic as per the new schema
3. Modify read deployment to read all the resource properties retuned from the API

Signed-off-by: Prativa Bawri <bawrip@vmware.com>
  • Loading branch information
Prativa20 committed Mar 20, 2020
1 parent 9c401d0 commit f30550d
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 216 deletions.
6 changes: 3 additions & 3 deletions sdk/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ type BusinessGroup struct {

// RequestResourceView - resource view of a provisioned request
type RequestResourceView struct {
Content []DeploymentResource `json:"content,omitempty"`
Links []interface{} `json:"links,omitempty"`
Content []interface{} `json:"content,omitempty"`
Links []interface{} `json:"links,omitempty"`
}

// DeploymentResource - deployment level view of the provisionined request
Expand All @@ -55,7 +55,7 @@ type DeploymentResource struct {
RequestID string `json:"requestId,omitempty"`
ResourceID string `json:"resourceId,omitempty"`
ResourceType string `json:"resourceType,omitempty"`
ResourcesData DeploymentResourceData `json:"data,omitempty"`
ResourcesData map[string]interface{} `json:"data,omitempty"`
}

// DeploymentResourceData - view of the resources/machines in a deployment
Expand Down
2 changes: 2 additions & 0 deletions sdk/vra7_sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func (c *APIClient) GetCatalogItemRequestTemplate(catalogItemID string) (*Catalo
if unmarshallErr != nil {
return nil, unmarshallErr
}
// j, _ := json.Marshal(requestTemplate)
// log.Critical("the template is ====> %v ", string(j))
return &requestTemplate, nil
}

Expand Down
25 changes: 20 additions & 5 deletions utils/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package utils
import (
"bytes"
"encoding/json"
"github.com/op/go-logging"
"reflect"
"strconv"
"strings"

"github.com/op/go-logging"
)

// terraform provider constants
Expand Down Expand Up @@ -58,8 +59,8 @@ func ConvertInterfaceToString(interfaceData interface{}) string {
return stringData
}

// Parse value and if it's JSON string, unmarshal it
func UnmarshalJsonStringIfNecessary(field string, value interface{}) interface{} {
// UnmarshalJSONStringIfNecessary parses value and if it's JSON string, unmarshal it
func UnmarshalJSONStringIfNecessary(field string, value interface{}) interface{} {
// Cast value to string. Provider schema requires DeploymentConfiguration to be map[string]string
stringValue, ok := value.(string)

Expand Down Expand Up @@ -117,7 +118,7 @@ func ReplaceValueInRequestTemplate(templateInterface map[string]interface{}, fie
} else if key == field {
//If value type is not map then compare field name with provided field name
//If both matches then update field value with provided value
templateInterface[key] = value
templateInterface[key] = UnmarshalJSONStringIfNecessary(field, value)
return templateInterface, true
}
}
Expand All @@ -135,9 +136,23 @@ func AddValueToRequestTemplate(templateInterface map[string]interface{}, field s
template, _ := v.(map[string]interface{})
v = AddValueToRequestTemplate(template, field, value)
} else { //if i == "data" {
templateInterface[field] = value
templateInterface[field] = UnmarshalJSONStringIfNecessary(field, value)
}
}
//Return updated map interface type
return templateInterface
}

// ResourceMapper returns the mapping of resource attributes from ResourceView APIs
// to Catalog Item Request Template APIs
func ResourceMapper() map[string]string {
m := make(map[string]string)
m["MachineName"] = "name"
m["MachineDescription"] = "description"
m["MachineMemory"] = "memory"
m["MachineStorage"] = "storage"
m["MachineCPU"] = "cpu"
m["MachineStatus"] = "status"
m["MachineType"] = "type"
return m
}
19 changes: 10 additions & 9 deletions utils/utilities_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package utils

import (
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func TestUnmarshalJsonStringIfNecessaryFunction(t *testing.T) {
Expand All @@ -13,15 +14,15 @@ func TestUnmarshalJsonStringIfNecessaryFunction(t *testing.T) {
"key1": "string",
"key2": 1,
}}
computedValue1 := UnmarshalJsonStringIfNecessary(fieldName, notStringValue)
computedValue1 := UnmarshalJSONStringIfNecessary(fieldName, notStringValue)
assertLocal.Equal(notStringValue, computedValue1)

var notJsonStringValue = "some custom value"
computedValue2 := UnmarshalJsonStringIfNecessary(fieldName, notJsonStringValue)
assertLocal.Equal(notJsonStringValue, computedValue2)
var notJSONStringValue = "some custom value"
computedValue2 := UnmarshalJSONStringIfNecessary(fieldName, notJSONStringValue)
assertLocal.Equal(notJSONStringValue, computedValue2)

var jsonStringValue = "[\"bg1\", \"bg2\"]"
var expectedJsonValue = []interface{}{"bg1", "bg2"}
computedValue3 := UnmarshalJsonStringIfNecessary(fieldName, jsonStringValue)
assertLocal.Equal(expectedJsonValue, computedValue3)
var jSONStringValue = "[\"bg1\", \"bg2\"]"
var expectedJSONValue = []interface{}{"bg1", "bg2"}
computedValue3 := UnmarshalJSONStringIfNecessary(fieldName, jSONStringValue)
assertLocal.Equal(expectedJSONValue, computedValue3)
}
166 changes: 166 additions & 0 deletions vra7/resource_configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package vra7

import (
"reflect"
"strconv"

"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-vra7/utils"
)

// ResourceConfigurationStruct - structure representing the resource_configuration
type ResourceConfigurationStruct struct {
Name string `json:"name"`
Configuration map[string]interface{} `json:"configuration"`
}

func resourceConfigurationSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"configuration": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"name": {
Type: schema.TypeString,
Required: true,
},
},
},
}
}

func expandResourceConfiguration(rConfigurations []interface{}) []ResourceConfigurationStruct {
configs := make([]ResourceConfigurationStruct, 0, len(rConfigurations))

for _, config := range rConfigurations {
configMap := config.(map[string]interface{})

rConfig := ResourceConfigurationStruct{
Name: configMap["name"].(string),
Configuration: configMap["configuration"].(map[string]interface{}),
}
configs = append(configs, rConfig)
}
return configs
}

func flattenResourceConfigurations(configs []ResourceConfigurationStruct) []map[string]interface{} {
if len(configs) == 0 {
return make([]map[string]interface{}, 0)
}
rConfigs := make([]map[string]interface{}, 0, len(configs))
for _, config := range configs {
componentName, resourceDataMap := parseDataMap(config.Configuration)
helper := make(map[string]interface{})
helper["name"] = componentName
helper["configuration"] = resourceDataMap
rConfigs = append(rConfigs, helper)
}
return rConfigs
}

func parseDataMap(resourceData map[string]interface{}) (string, map[string]interface{}) {
m := make(map[string]interface{})
componentName := ""
resourcePropertyMapper := utils.ResourceMapper()
for key, value := range resourceData {

// Component property is within data of a resource, so fetching it from there and putting it as resource level property
if key == "Component" {
componentName = convToString(value)
}
if i, ok := resourcePropertyMapper[key]; ok {
key = i
}
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Slice:
parseArray(key, m, value.([]interface{}))
case reflect.Map:
parseMap(key, m, value.(map[string]interface{}))
default:
m[key] = convToString(value)
}
}
return componentName, m
}

func parseMap(prefix string, m map[string]interface{}, data map[string]interface{}) {

for key, value := range data {
v := reflect.ValueOf(value)

switch v.Kind() {
case reflect.Slice:
parseArray(prefix+"."+key, m, value.([]interface{}))
case reflect.Map:
parseMap(prefix+"."+key, m, value.(map[string]interface{}))
default:
m[prefix+"."+key] = convToString(value)
}
}
}

func parseArray(prefix string, m map[string]interface{}, value []interface{}) {

for index, val := range value {
v := reflect.ValueOf(val)
switch v.Kind() {
case reflect.Map:
/* for properties like NETWORK_LIST, DISK_VOLUMES etc, the value is a slice of map as follows.
Out of all the information, only data is important information, so leaving out rest of the properties
"NETWORK_LIST":[
{
"componentTypeId":"",
"componentId":null,
"classId":"",
"typeFilter":null,
"data":{
"NETWORK_MAC_ADDRESS":"00:50:56:b6:78:c6",
"NETWORK_NAME":"dvPortGroup-wdc-sdm-vm-1521"
}
}
]
*/
objMap := val.(map[string]interface{})
for k, v := range objMap {
if k == "data" {
parseMap(prefix+"."+convToString(index), m, v.(map[string]interface{}))
}
}
default:
m[prefix+"."+convToString(index)] = convToString(val)
}
}
}

func convToString(value interface{}) string {

v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.String:
return value.(string)
case reflect.Float64:
return strconv.FormatFloat(value.(float64), 'f', 0, 64)
case reflect.Float32:
return strconv.FormatFloat(value.(float64), 'f', 0, 32)
case reflect.Int:
return strconv.Itoa(value.(int))
case reflect.Int32:
return strconv.Itoa(value.(int))
case reflect.Int64:
return strconv.FormatInt(value.(int64), 10)
case reflect.Bool:
return strconv.FormatBool(value.(bool))
}
return ""
}
Loading

0 comments on commit f30550d

Please sign in to comment.