From 6585559bf760a9b344e2e5c2ecb368f2ec0cc81a Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Mon, 15 Jul 2019 15:39:07 +0300 Subject: [PATCH 1/3] Add missing file Signed-off-by: Vaidotas Bauzys --- .../go-vcloud-director/v2/govcd/lbapprule.go | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 vendor/github.com/vmware/go-vcloud-director/v2/govcd/lbapprule.go diff --git a/vendor/github.com/vmware/go-vcloud-director/v2/govcd/lbapprule.go b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/lbapprule.go new file mode 100644 index 000000000..ca0cafae2 --- /dev/null +++ b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/lbapprule.go @@ -0,0 +1,216 @@ +/* + * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "fmt" + "net/http" + + "github.com/vmware/go-vcloud-director/v2/types/v56" +) + +// CreateLBAppRule creates a load balancer application rule based on mandatory fields. It is a +// synchronous operation. It returns created object with all fields (including ID) populated or an error. +func (eGW *EdgeGateway) CreateLBAppRule(lbAppRuleConfig *types.LBAppRule) (*types.LBAppRule, error) { + if err := validateCreateLBAppRule(lbAppRuleConfig); err != nil { + return nil, err + } + + httpPath, err := eGW.buildProxiedEdgeEndpointURL(types.LBAppRulePath) + if err != nil { + return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) + } + // We expect to get http.StatusCreated or if not an error of type types.NSXError + resp, err := eGW.client.ExecuteRequestWithCustomError(httpPath, http.MethodPost, types.AnyXMLMime, + "error creating load balancer application rule: %s", lbAppRuleConfig, &types.NSXError{}) + if err != nil { + return nil, err + } + + // Location header should look similar to: + // [/network/edges/edge-3/loadbalancer/config/applicationrules/applicationRule-4] + lbAppRuleId, err := extractNSXObjectIDFromPath(resp.Header.Get("Location")) + if err != nil { + return nil, err + } + + readAppRule, err := eGW.ReadLBAppRule(&types.LBAppRule{ID: lbAppRuleId}) + if err != nil { + return nil, fmt.Errorf("unable to retrieve application rule with ID (%s) after creation: %s", + readAppRule.ID, err) + } + return readAppRule, nil +} + +// ReadLBAppRule is able to find the types.LBAppRule type by Name and/or ID. +// If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found +// name do not match. +func (eGW *EdgeGateway) ReadLBAppRule(lbAppRuleConfig *types.LBAppRule) (*types.LBAppRule, error) { + if err := validateReadLBAppRule(lbAppRuleConfig); err != nil { + return nil, err + } + + httpPath, err := eGW.buildProxiedEdgeEndpointURL(types.LBAppRulePath) + if err != nil { + return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) + } + + // Anonymous struct to unwrap response + lbAppRuleResponse := &struct { + LbAppRules []*types.LBAppRule `xml:"applicationRule"` + }{} + + // This query returns all application rules as the API does not have filtering options + _, err = eGW.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime, + "unable to read load balancer application rule: %s", nil, lbAppRuleResponse) + if err != nil { + return nil, err + } + + // Search for application rule by ID or by Name + for _, rule := range lbAppRuleResponse.LbAppRules { + // If ID was specified for lookup - look for the same ID + if lbAppRuleConfig.ID != "" && rule.ID == lbAppRuleConfig.ID { + return rule, nil + } + + // If Name was specified for lookup - look for the same Name + if lbAppRuleConfig.Name != "" && rule.Name == lbAppRuleConfig.Name { + // We found it by name. Let's verify if search ID was specified and it matches the lookup object + if lbAppRuleConfig.ID != "" && rule.ID != lbAppRuleConfig.ID { + return nil, fmt.Errorf("load balancer application rule was found by name (%s)"+ + ", but its ID (%s) does not match specified ID (%s)", + rule.Name, rule.ID, lbAppRuleConfig.ID) + } + return rule, nil + } + } + + return nil, ErrorEntityNotFound +} + +// ReadLBAppRuleById wraps ReadLBAppRule and needs only an ID for lookup +func (eGW *EdgeGateway) ReadLBAppRuleByID(id string) (*types.LBAppRule, error) { + return eGW.ReadLBAppRule(&types.LBAppRule{ID: id}) +} + +// ReadLBAppRuleByName wraps ReadLBAppRule and needs only a Name for lookup +func (eGW *EdgeGateway) ReadLBAppRuleByName(name string) (*types.LBAppRule, error) { + return eGW.ReadLBAppRule(&types.LBAppRule{Name: name}) +} + +// UpdateLBAppRule updates types.LBAppRule with all fields. At least name or ID must be specified. +// If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found +// name do not match. +func (eGW *EdgeGateway) UpdateLBAppRule(lbAppRuleConfig *types.LBAppRule) (*types.LBAppRule, error) { + err := validateUpdateLBAppRule(lbAppRuleConfig) + if err != nil { + return nil, err + } + + lbAppRuleConfig.ID, err = eGW.getLBAppRuleIDByNameID(lbAppRuleConfig.Name, lbAppRuleConfig.ID) + if err != nil { + return nil, fmt.Errorf("cannot update load balancer application rule: %s", err) + } + + httpPath, err := eGW.buildProxiedEdgeEndpointURL(types.LBAppRulePath + lbAppRuleConfig.ID) + if err != nil { + return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) + } + + // Result should be 204, if not we expect an error of type types.NSXError + _, err = eGW.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime, + "error while updating load balancer application rule : %s", lbAppRuleConfig, &types.NSXError{}) + if err != nil { + return nil, err + } + + readAppRule, err := eGW.ReadLBAppRule(&types.LBAppRule{ID: lbAppRuleConfig.ID}) + if err != nil { + return nil, fmt.Errorf("unable to retrieve application rule with ID (%s) after update: %s", + readAppRule.ID, err) + } + return readAppRule, nil +} + +// DeleteLBAppRule is able to delete the types.LBAppRule type by Name and/or ID. +// If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found +// name do not match. +func (eGW *EdgeGateway) DeleteLBAppRule(lbAppRuleConfig *types.LBAppRule) error { + err := validateDeleteLBAppRule(lbAppRuleConfig) + if err != nil { + return err + } + + lbAppRuleConfig.ID, err = eGW.getLBAppRuleIDByNameID(lbAppRuleConfig.Name, lbAppRuleConfig.ID) + if err != nil { + return fmt.Errorf("cannot update load balancer application rule: %s", err) + } + + httpPath, err := eGW.buildProxiedEdgeEndpointURL(types.LBAppRulePath + lbAppRuleConfig.ID) + if err != nil { + return fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) + } + + return eGW.client.ExecuteRequestWithoutResponse(httpPath, http.MethodDelete, "application/xml", + "unable to delete application rule: %s", nil) +} + +// DeleteLBAppRuleById wraps DeleteLBAppRule and requires only ID for deletion +func (eGW *EdgeGateway) DeleteLBAppRuleByID(id string) error { + return eGW.DeleteLBAppRule(&types.LBAppRule{ID: id}) +} + +// DeleteLBAppRuleByName wraps DeleteLBAppRule and requires only Name for deletion +func (eGW *EdgeGateway) DeleteLBAppRuleByName(name string) error { + return eGW.DeleteLBAppRule(&types.LBAppRule{Name: name}) +} + +func validateCreateLBAppRule(lbAppRuleConfig *types.LBAppRule) error { + if lbAppRuleConfig.Name == "" { + return fmt.Errorf("load balancer application rule Name cannot be empty") + } + + return nil +} + +func validateReadLBAppRule(lbAppRuleConfig *types.LBAppRule) error { + if lbAppRuleConfig.ID == "" && lbAppRuleConfig.Name == "" { + return fmt.Errorf("to read load balancer application rule at least one of `ID`, `Name`" + + " fields must be specified") + } + + return nil +} + +func validateUpdateLBAppRule(lbAppRuleConfig *types.LBAppRule) error { + // Update and create have the same requirements for now + return validateCreateLBAppRule(lbAppRuleConfig) +} + +func validateDeleteLBAppRule(lbAppRuleConfig *types.LBAppRule) error { + // Read and delete have the same requirements for now + return validateReadLBAppRule(lbAppRuleConfig) +} + +// getLBAppRuleIDByNameID checks if at least name or ID is set and returns the ID. +// If the ID is specified - it passes through the ID. If only name was specified +// it will lookup the object by name and return the ID. +func (eGW *EdgeGateway) getLBAppRuleIDByNameID(name, id string) (string, error) { + if name == "" && id == "" { + return "", fmt.Errorf("at least Name or ID must be specific to find load balancer "+ + "application rule got name (%s) ID (%s)", name, id) + } + if id != "" { + return id, nil + } + + // if only name was specified, ID must be found, because only ID can be used in request path + readlbAppRule, err := eGW.ReadLBAppRuleByName(name) + if err != nil { + return "", fmt.Errorf("unable to find load balancer application rule by name: %s", err) + } + return readlbAppRule.ID, nil +} From 3b5a908eb1680559c11da897ff290072bc153231 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Fri, 15 Nov 2019 09:04:55 +0200 Subject: [PATCH 2/3] bump govcd version Signed-off-by: Vaidotas Bauzys --- go.mod | 2 +- go.sum | 4 +- .../go-vcloud-director/v2/govcd/api_vcd.go | 2 +- .../go-vcloud-director/v2/govcd/system.go | 2 +- .../go-vcloud-director/v2/types/v56/types.go | 63 +++++++++++-------- vendor/modules.txt | 2 +- 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index b4967c6be..ce840e7bb 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.13 require ( github.com/hashicorp/terraform-plugin-sdk v1.0.0 - github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.5 + github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.6 ) diff --git a/go.sum b/go.sum index 0eff6f268..dcd506f7a 100644 --- a/go.sum +++ b/go.sum @@ -187,8 +187,8 @@ github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.5 h1:hQDzS94JgM2E36jxetpcGzeRJBK3M9ergjej9wPBDhk= -github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.5/go.mod h1:VqfkCixIzRmj4EzF2yFJKB+aKDW6GkXlLbFh5xZ+qqs= +github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.6 h1:7OCR9Qj0KSu9li9s2oXeW0HF8oGtrukdGoHGXboBykw= +github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.6/go.mod h1:VqfkCixIzRmj4EzF2yFJKB+aKDW6GkXlLbFh5xZ+qqs= github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= diff --git a/vendor/github.com/vmware/go-vcloud-director/v2/govcd/api_vcd.go b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/api_vcd.go index 04b48f2c4..752c0b6e6 100644 --- a/vendor/github.com/vmware/go-vcloud-director/v2/govcd/api_vcd.go +++ b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/api_vcd.go @@ -92,7 +92,7 @@ func NewVCDClient(vcdEndpoint url.URL, insecure bool, options ...VCDClientOption // Setting defaults vcdClient := &VCDClient{ Client: Client{ - APIVersion: "27.0", // supported by vCD 8.20, 9.0, 9.1, 9.5, 9.7 + APIVersion: "29.0", // supported by vCD 9.0, 9.1, 9.5, 9.7, 10.0 VCDHREF: vcdEndpoint, Http: http.Client{ Transport: &http.Transport{ diff --git a/vendor/github.com/vmware/go-vcloud-director/v2/govcd/system.go b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/system.go index d106986fe..578de301a 100644 --- a/vendor/github.com/vmware/go-vcloud-director/v2/govcd/system.go +++ b/vendor/github.com/vmware/go-vcloud-director/v2/govcd/system.go @@ -132,7 +132,7 @@ func CreateEdgeGatewayAsync(vcdClient *VCDClient, egwc EdgeGatewayCreation) (Tas HaEnabled: egwc.HAEnabled, GatewayBackingConfig: egwc.BackingConfiguration, AdvancedNetworkingEnabled: egwc.AdvancedNetworkingEnabled, - DistributedRoutingEnabled: distributed, + DistributedRoutingEnabled: &distributed, GatewayInterfaces: &types.GatewayInterfaces{ GatewayInterface: []*types.GatewayInterface{}, }, diff --git a/vendor/github.com/vmware/go-vcloud-director/v2/types/v56/types.go b/vendor/github.com/vmware/go-vcloud-director/v2/types/v56/types.go index aa434921c..ba33b07b0 100644 --- a/vendor/github.com/vmware/go-vcloud-director/v2/types/v56/types.go +++ b/vendor/github.com/vmware/go-vcloud-director/v2/types/v56/types.go @@ -211,6 +211,7 @@ type NetworkConfiguration struct { RetainNetInfoAcrossDeployments bool `xml:"RetainNetInfoAcrossDeployments,omitempty"` Features *NetworkFeatures `xml:"Features,omitempty"` GuestVlanAllowed *bool `xml:"GuestVlanAllowed,omitempty"` + DistributedInterface *bool `xml:"DistributedInterface,omitempty"` // TODO: Not Implemented // RouterInfo RouterInfo `xml:"RouterInfo,omitempty"` // SyslogServerSettings SyslogServerSettings `xml:"SyslogServerSettings,omitempty"` @@ -1134,6 +1135,7 @@ type VMGeneralParams struct { Name string `xml:"Name,omitempty"` // Name of VM Description string `xml:"Description,omitempty"` // VM description NeedsCustomization bool `xml:"NeedsCustomization,omitempty"` // True if this VM needs guest customization + RegenerateBiosUuid bool `xml:"RegenerateBiosUuid,omitempty"` // True if BIOS UUID of the virtual machine should be regenerated so that it is unique, and not the same as the source virtual machine's BIOS UUID. } // VApp represents a vApp @@ -1572,7 +1574,7 @@ type GatewayConfiguration struct { EdgeGatewayServiceConfiguration *GatewayFeatures `xml:"EdgeGatewayServiceConfiguration,omitempty"` // Represents Gateway Features. HaEnabled bool `xml:"HaEnabled,omitempty"` // True if this gateway is highly available. (Requires two vShield edge VMs.) AdvancedNetworkingEnabled bool `xml:"AdvancedNetworkingEnabled,omitempty"` // True if the gateway uses advanced networking - DistributedRoutingEnabled bool `xml:"DistributedRoutingEnabled,omitempty"` // True if gateway is attached to a Distributed Logical Router + DistributedRoutingEnabled *bool `xml:"DistributedRoutingEnabled,omitempty"` // True if gateway is attached to a Distributed Logical Router UseDefaultRouteForDNSRelay bool `xml:"UseDefaultRouteForDnsRelay,omitempty"` // True if the default gateway on the external network selected for default route should be used as the DNS relay. } @@ -2240,31 +2242,40 @@ type QueryResultEdgeGatewayRecordType struct { // QueryResultVMRecordType represents a VM record as query result. type QueryResultVMRecordType struct { // Attributes - HREF string `xml:"href,attr,omitempty"` // The URI of the entity. - Name string `xml:"name,attr,omitempty"` // VM name. - Deployed bool `xml:"isDeployed,attr,omitempty"` // True if the virtual machine is deployed. - Status string `xml:"status,attr,omitempty"` - Busy bool `xml:"isBusy,attr,omitempty"` - Deleted bool `xml:"isDeleted,attr,omitempty"` - MaintenanceMode bool `xml:"isInMaintenanceMode,attr,omitempty"` - Published bool `xml:"isPublished,attr,omitempty"` - VAppTemplate bool `xml:"isVAppTemplate,attr,omitempty"` - VdcEnabled bool `xml:"isVdcEnabled,attr,omitempty"` - VdcHREF string `xml:"vdc,attr,omitempty"` - VAppParentHREF string `xml:"container,attr,omitempty"` - VAppParentName string `xml:"containerName,attr,omitempty"` - HardwareVersion int `xml:"hardwareVersion,attr,omitempty"` - HighestSupportedVersion int `xml:"pvdcHighestSupportedHardwareVersion,attr,omitempty"` - VmToolsVersion string `xml:"vmToolsVersion,attr,omitempty"` - GuestOS string `xml:"guestOs,attr,omitempty"` - MemoryMB int `xml:"memoryMB,attr,omitempty"` - Cpus int `xml:"numberOfCpus,attr,omitempty"` - StorageProfileName string `xml:"storageProfileName,attr,omitempty"` - NetworkName string `xml:"networkName,attr,omitempty"` - TaskHREF string `xml:"task,attr,omitempty"` - TaskStatusName string `xml:"taskStatusName,attr,omitempty"` - TaskDetails string `xml:"taskDetails,attr,omitempty"` - TaskStatus string `xml:"TaskStatus,attr,omitempty"` + HREF string `xml:"href,attr,omitempty"` // The URI of the entity. + ID string `xml:"id,attr,omitempty"` + Name string `xml:"name,attr,omitempty"` // VM name. + Type string `xml:"type,attr,omitempty"` // Contains the type of the resource. + ContainerName string `xml:"containerName,attr,omitempty"` // The name of the vApp or vApp template that contains this VM. + ContainerID string `xml:"container,attr,omitempty"` // The ID of the vApp or vApp template that contains this VM. + OwnerName string `xml:"ownerName,attr,omitempty"` + Owner string `xml:"owner,attr,omitempty"` + VdcHREF string `xml:"vdc,attr,omitempty"` + VAppTemplate bool `xml:"isVAppTemplate,attr,omitempty"` + Deleted bool `xml:"isDeleted,attr,omitempty"` + GuestOS string `xml:"guestOs,attr,omitempty"` + Cpus int `xml:"numberOfCpus,attr,omitempty"` + MemoryMB int `xml:"memoryMB,attr,omitempty"` + Status string `xml:"status,attr,omitempty"` + NetworkName string `xml:"networkName,attr,omitempty"` + NetworkHref string `xml:"network,attr,omitempty"` + IpAddress string `xml:"ipAddress,attr,omitempty"` // If configured, the IP Address of the VM on the primary network, otherwise empty. + Busy bool `xml:"isBusy,attr,omitempty"` + Deployed bool `xml:"isDeployed,attr,omitempty"` // True if the virtual machine is deployed. + Published bool `xml:"isPublished,attr,omitempty"` + CatalogName string `xml:"catalogName,attr,omitempty"` + HardwareVersion int `xml:"hardwareVersion,attr,omitempty"` + VmToolsStatus string `xml:"vmToolsStatus,attr,omitempty"` + MaintenanceMode bool `xml:"isInMaintenanceMode,attr,omitempty"` + AutoNature bool `xml:"isAutoNature,attr,omitempty"` // True if the parent vApp is a managed vApp + StorageProfileName string `xml:"storageProfileName,attr,omitempty"` + GcStatus string `xml:"gcStatus,attr,omitempty"` // GC status of this VM. + AutoUndeployDate string `xml:"autoUndeployDate,attr,omitempty"` + AutoDeleteDate string `xml:"autoDeleteDate,attr,omitempty"` + AutoUndeployNotified bool `xml:"isAutoUndeployNotified,attr,omitempty"` + AutoDeleteNotified bool `xml:"isAutoDeleteNotified,attr,omitempty"` + Link []*Link `xml:"Link,omitempty"` + MetaData *Metadata `xml:"Metadata,omitempty"` } // QueryResultVAppRecordType represents a VM record as query result. diff --git a/vendor/modules.txt b/vendor/modules.txt index 29f1f326a..2e78610a1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -212,7 +212,7 @@ github.com/ulikunitz/xz/lzma # github.com/vmihailenco/msgpack v3.3.3+incompatible github.com/vmihailenco/msgpack github.com/vmihailenco/msgpack/codes -# github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.5 +# github.com/vmware/go-vcloud-director/v2 v2.5.0-alpha.6 github.com/vmware/go-vcloud-director/v2/govcd github.com/vmware/go-vcloud-director/v2/types/v56 github.com/vmware/go-vcloud-director/v2/util From 937c14480f270664ad0abb6d4d2bc64474f260b4 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Fri, 15 Nov 2019 09:06:49 +0200 Subject: [PATCH 3/3] update change log Signed-off-by: Vaidotas Bauzys --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c68f62e..146176b8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ IMPROVEMENTS: field to export default edge gateway IP address - [GH-389] * Add `token` to the `vcd` provider for the ability of connecting with an authorization token - [GH-280] * Add command `make token` to create an authorization token from testing credentials +* Increment vCD API version used from 27.0 to 29.0 [GH-396] BUG FIXES: