From ff1922cef6c6f97375430017334c3af1fecb1709 Mon Sep 17 00:00:00 2001 From: skylerto Date: Tue, 16 Jul 2019 16:05:52 -0400 Subject: [PATCH] Adds support for generic responses Uses Go `map[string]string` instead of `DeploymentResourceData` to abstract generic properties from the responses of vRA deployment resources. This solves issues where we might want to handle custom properties on the blueprints, as well as XaaS blueprints that contain entirely custom properties. Signed-off-by: skylerto --- sdk/schema.go | 33 +---------------------- utils/utilities.go | 44 +++++++++++++++++++++++++++++++ utils/utilities_test.go | 45 ++++++++++++++++++++++++++++++++ vra7/resource_vra7_deployment.go | 38 ++++++++++++++------------- 4 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 utils/utilities_test.go diff --git a/sdk/schema.go b/sdk/schema.go index f8f7716a..23039937 100644 --- a/sdk/schema.go +++ b/sdk/schema.go @@ -55,38 +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"` -} - -// DeploymentResourceData - view of the resources/machines in a deployment -type DeploymentResourceData struct { - Memory int `json:"MachineMemory,omitempty"` - CPU int `json:"MachineCPU,omitempty"` - IPAddress string `json:"ip_address,omitempty"` - Storage int `json:"MachineStorage,omitempty"` - MachineInterfaceType string `json:"MachineInterfaceType,omitempty"` - MachineName string `json:"MachineName,omitempty"` - MachineGuestOperatingSystem string `json:"MachineGuestOperatingSystem,omitempty"` - MachineDestructionDate string `json:"MachineDestructionDate,omitempty"` - MachineGroupName string `json:"MachineGroupName,omitempty"` - MachineBlueprintName string `json:"MachineBlueprintName,omitempty"` - MachineReservationName string `json:"MachineReservationName,omitempty"` - MachineType string `json:"MachineType,omitempty"` - MachineID string `json:"machineId,omitempty"` - MachineExpirationDate string `json:"MachineExpirationDate,omitempty"` - Component string `json:"Component,omitempty"` - Expire bool `json:"Expire,omitempty"` - Reconfigure bool `json:"Reconfigure,omitempty"` - Reset bool `json:"Reset,omitempty"` - Reboot bool `json:"Reboot,omitempty"` - PowerOff bool `json:"PowerOff,omitempty"` - Destroy bool `json:"Destroy,omitempty"` - Shutdown bool `json:"Shutdown,omitempty"` - Suspend bool `json:"Suspend,omitempty"` - Reprovision bool `json:"Reprovision,omitempty"` - ChangeLease bool `json:"ChangeLease,omitempty"` - ChangeOwner bool `json:"ChangeOwner,omitempty"` - CreateSnapshot bool `json:"CreateSnapshot,omitempty"` + ResourcesData map[string]interface{} `json:"data,omitempty"` } // ResourceActions - Retrieves the resources that were provisioned as a result of a given request. diff --git a/utils/utilities.go b/utils/utilities.go index d9235abc..b14a4e3e 100644 --- a/utils/utilities.go +++ b/utils/utilities.go @@ -3,6 +3,7 @@ package utils import ( "bytes" "encoding/json" + "fmt" "reflect" "strconv" "strings" @@ -116,3 +117,46 @@ func AddValueToRequestTemplate(templateInterface map[string]interface{}, field s //Return updated map interface type return templateInterface } + +// Flatten takes a generic map of maps and flattens the properties via a dot seperator. +func Flatten(m map[string]interface{}) map[string]interface{} { + o := make(map[string]interface{}) + for k, v := range m { + switch child := v.(type) { + case map[string]interface{}: + nm := Flatten(child) + for nk, nv := range nm { + o[k+"."+nk] = nv + } + default: + o[k] = v + } + } + return o +} + +// FlattenJSON takes a generic map of maps (representing nested json data) and flattens the properties via a do seperator. +func FlattenJSON(jsonMap map[string]interface{}, key string) map[string]interface{} { + viewData := make(map[string]interface{}) + + value := jsonMap[key] + if value == nil { + value = "" + } + + if reflect.TypeOf(value).String() == "[]interface {}" { + for _, data := range value.([]interface{}) { + if reflect.TypeOf(data).String() == "map[string]interface {}" { + res := Flatten(data.(map[string]interface{})) + for nestedKey := range res { + viewData[fmt.Sprintf("%s.%s", key, nestedKey)] = fmt.Sprintf("%v", res[nestedKey]) + } + } else { + viewData[key] = fmt.Sprintf("%v", data) + } + } + } else { + viewData[key] = fmt.Sprintf("%v", value) + } + return viewData +} diff --git a/utils/utilities_test.go b/utils/utilities_test.go new file mode 100644 index 00000000..47786379 --- /dev/null +++ b/utils/utilities_test.go @@ -0,0 +1,45 @@ +package utils + +import ( + "testing" +) + +func TestFlatten(t *testing.T) { + inside := make(map[string]interface{}) + inside["outside"] = "valid" + outside := make(map[string]interface{}) + outside["test"] = inside + actual := Flatten(outside) + + expected := make(map[string]interface{}) + expected["test.outside"] = "valid" + + for k := range actual { + if actual[k] != expected[k] { + t.Fatalf("Expected %s, got %s at key %s", expected, actual, k) + } + } +} + +func TestFlattenComplex(t *testing.T) { + deep := make(map[string]interface{}) + deep["outside"] = "valid" + + inside := make(map[string]interface{}) + inside["outside"] = "valid" + inside["deep"] = deep + + outside := make(map[string]interface{}) + outside["test"] = inside + actual := Flatten(outside) + + expected := make(map[string]interface{}) + expected["test.outside"] = "valid" + expected["test.deep.outside"] = "valid" + + for k := range actual { + if actual[k] != expected[k] { + t.Fatalf("Expected %s, got %s at key %s", expected, actual, k) + } + } +} diff --git a/vra7/resource_vra7_deployment.go b/vra7/resource_vra7_deployment.go index 23cc54e4..3b0a6029 100644 --- a/vra7/resource_vra7_deployment.go +++ b/vra7/resource_vra7_deployment.go @@ -105,6 +105,15 @@ func resourceVra7Deployment() *schema.Resource { Computed: true, Elem: schema.TypeString, }, + "resource_views_data": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeMap, + Elem: schema.TypeString, + }, + Description: "The response data located along side the resource view API calls", + Computed: true, + }, }, } } @@ -347,27 +356,19 @@ func resourceVra7DeploymentRead(d *schema.ResourceData, meta interface{}) error } resourceDataMap := make(map[string]map[string]interface{}) + var resourceViewsData []map[string]interface{} for _, resource := range requestResourceView.Content { - if resource.ResourceType == sdk.InfrastructureVirtual { - resourceData := resource.ResourcesData - log.Info("The resource data map of the resource %v is: \n%v", resourceData.Component, resource.ResourcesData) - dataVals := make(map[string]interface{}) - resourceDataMap[resourceData.Component] = dataVals - dataVals[sdk.MachineCPU] = resourceData.CPU - dataVals[sdk.MachineStorage] = resourceData.Storage - dataVals[sdk.IPAddress] = resourceData.IPAddress - dataVals[sdk.MachineMemory] = resourceData.Memory - dataVals[sdk.MachineName] = resourceData.MachineName - dataVals[sdk.MachineGuestOs] = resourceData.MachineGuestOperatingSystem - dataVals[sdk.MachineBpName] = resourceData.MachineBlueprintName - dataVals[sdk.MachineType] = resourceData.MachineType - dataVals[sdk.MachineReservationName] = resourceData.MachineReservationName - dataVals[sdk.MachineInterfaceType] = resourceData.MachineInterfaceType - dataVals[sdk.MachineID] = resourceData.MachineID - dataVals[sdk.MachineGroupName] = resourceData.MachineGroupName - dataVals[sdk.MachineDestructionDate] = resourceData.MachineDestructionDate + viewData := make(map[string]interface{}) + for key := range resource.ResourcesData { + viewData[key] = utils.FlattenJSON(resource.ResourcesData, key) } + resourceViewsData = append(resourceViewsData, utils.Flatten(viewData)) + } + setDataError := d.Set("resource_views_data", resourceViewsData) + if setDataError != nil { + return fmt.Errorf(setDataError.Error()) } + resourceConfiguration, _ := d.Get("resource_configuration").(map[string]interface{}) resourceConfiguration, changed := utils.UpdateResourceConfigurationMap(resourceConfiguration, resourceDataMap) @@ -378,6 +379,7 @@ func resourceVra7DeploymentRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf(setError.Error()) } } + return nil }