From 5b74c497f17381c892d2e6f5284738e8d53f69fe Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 06:44:38 +0200 Subject: [PATCH 01/21] WIP Signed-off-by: Dainius Serplis --- govcd/openapi_endpoints.go | 1 + govcd/tm_ip_space.go | 116 +++++++++++++++++++++++++++++++++++++ govcd/tm_ip_space_test.go | 16 +++++ types/v56/constants.go | 1 + types/v56/tm.go | 4 ++ 5 files changed, 138 insertions(+) create mode 100644 govcd/tm_ip_space.go create mode 100644 govcd/tm_ip_space_test.go diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 019e3a1d0..2224a82c8 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -163,6 +163,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVcf + types.OpenApiEndpointRegions: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointSupervisors: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointSupervisorZones: "40.0", + types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces: "40.0", } // endpointElevatedApiVersions endpoint elevated API versions diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go new file mode 100644 index 000000000..91d58e5cd --- /dev/null +++ b/govcd/tm_ip_space.go @@ -0,0 +1,116 @@ +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v3/types/v56" +) + +const labelTmIpSpace = "TM IP Space" + +type TmIpSpace struct { + TmIpSpace *types.TmIpSpace + vcdClient *VCDClient +} + +// wrap is a hidden helper that facilitates the usage of a generic CRUD function +// +//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck +func (g TmIpSpace) wrap(inner *types.TmIpSpace) *TmIpSpace { + g.TmIpSpace = inner + return &g +} + +func (vcdClient *VCDClient) CreateTmIpSpace(config *types.TmIpSpace) (*TmIpSpace, error) { + c := crudConfig{ + entityLabel: labelTmIpSpace, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, + } + outerType := TmIpSpace{vcdClient: vcdClient} + return createOuterEntity(&vcdClient.Client, outerType, c, config) +} + +func (vcdClient *VCDClient) GetAllTmIpSpaces(queryParameters url.Values) ([]*TmIpSpace, error) { + c := crudConfig{ + entityLabel: labelTmIpSpace, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, + queryParameters: queryParameters, + } + + outerType := TmIpSpace{vcdClient: vcdClient} + return getAllOuterEntities[TmIpSpace, types.TmIpSpace](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmIpSpaceByName(name string) (*TmIpSpace, error) { + if name == "" { + return nil, fmt.Errorf("%s lookup requires name", labelTmIpSpace) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + + filteredEntities, err := vcdClient.GetAllTmIpSpaces(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmIpSpaceById(singleEntity.TmIpSpace.ID) +} + +func (vcdClient *VCDClient) GetTmIpSpaceById(id string) (*TmIpSpace, error) { + c := crudConfig{ + entityLabel: labelTmIpSpace, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, + endpointParams: []string{id}, + } + + outerType := TmIpSpace{vcdClient: vcdClient} + return getOuterEntity[TmIpSpace, types.TmIpSpace](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmIpSpaceByNameAndOrgId(name, orgId string) (*TmIpSpace, error) { + if name == "" || orgId == "" { + return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmIpSpace) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) + + filteredEntities, err := vcdClient.GetAllTmIpSpaces(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmIpSpaceById(singleEntity.TmIpSpace.ID) +} + +func (o *TmIpSpace) Update(TmIpSpaceConfig *types.IpSpace) (*IpSpace, error) { + c := crudConfig{ + entityLabel: labelTmIpSpace, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, + endpointParams: []string{o.TmIpSpace.ID}, + } + outerType := IpSpace{vcdClient: o.vcdClient} + return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmIpSpaceConfig) +} + +func (o *TmIpSpace) Delete() error { + c := crudConfig{ + entityLabel: labelTmIpSpace, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, + endpointParams: []string{o.TmIpSpace.ID}, + } + return deleteEntityById(&o.vcdClient.Client, c) +} diff --git a/govcd/tm_ip_space_test.go b/govcd/tm_ip_space_test.go new file mode 100644 index 000000000..7e55ebfd9 --- /dev/null +++ b/govcd/tm_ip_space_test.go @@ -0,0 +1,16 @@ +//go:build tm || functional || ALL + +/* + * Copyright 2024 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + . "gopkg.in/check.v1" +) + +// Test_ContentLibraryProvider tests CRUD operations for a Content Library with the Provider user +func (vcd *TestVCD) Test_TmIpSpace(check *C) { + +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 563cebbd8..98569098b 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -526,6 +526,7 @@ const ( OpenApiEndpointRegions = "regions/" OpenApiEndpointSupervisors = "supervisors/" OpenApiEndpointSupervisorZones = "supervisorZones/" + OpenApiEndpointTmIpSpaces = "ipSpaces/" ) // Header keys to run operations in tenant context diff --git a/types/v56/tm.go b/types/v56/tm.go index 3a2db72c0..b047c7375 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -178,3 +178,7 @@ type SupervisorZone struct { // Region contains a reference to parent region Region *OpenApiReference `json:"region"` } + +type TmIpSpace struct { + ID string +} From 89eb35a9020c39b00454dca5b61ed47e37a9a417 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 07:30:55 +0200 Subject: [PATCH 02/21] WIP Signed-off-by: Dainius Serplis --- govcd/openapi_endpoints.go | 1 + govcd/tm_provider_gateway.go | 138 ++++++++++++++++++++++++++++++ govcd/tm_provider_gateway_test.go | 16 ++++ govcd/tm_tier0_gateway.go | 97 +++++++++++++++++++++ types/v56/constants.go | 2 + types/v56/tm.go | 8 ++ 6 files changed, 262 insertions(+) create mode 100644 govcd/tm_provider_gateway.go create mode 100644 govcd/tm_provider_gateway_test.go create mode 100644 govcd/tm_tier0_gateway.go diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 2224a82c8..66915f3e2 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -164,6 +164,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVcf + types.OpenApiEndpointSupervisors: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointSupervisorZones: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces: "40.0", + types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways: "40.0", } // endpointElevatedApiVersions endpoint elevated API versions diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go new file mode 100644 index 000000000..51a405947 --- /dev/null +++ b/govcd/tm_provider_gateway.go @@ -0,0 +1,138 @@ +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v3/types/v56" +) + +// This is a template of how a "standard" outer entity implementation can be done when using generic +// functions. It might not cover all scenarios, but is a skeleton for quicker bootstraping of a new +// entity. +// +// "Search and replace the following entries" +// +// TmProviderGateway - outer type (e.g. IpSpace2) +// This should be a non existing new type to create in 'govcd' package +// +// types.TmProviderGateway - inner type (e.g. types.IpSpace) +// This should be an already existing inner type in `types` package +// +// TM Provider Gateway - constant name for entity label (the lower case prefix 'label' prefix is hardcoded) +// The 'label' prefix is hardcoded in the example so that we have autocompletion working for all labelXXXX. (e.g. IpSpace2) +// +// TM Provider Gateway - text for entity label (e.g. Ip Space 2) +// This will be the entity label (used for logging purposes in generic functions) +// +// types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways (e.g. types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces) +// An OpenAPI endpoint that is defined in `endpointMinApiVersions` map and in `constants.go` +// NOTE. While this example REPLACES ALL ENDPOINTS to be THE SAME, in reality they can be DIFFERENT + +const labelTmProviderGateway = "TM Provider Gateway" + +type TmProviderGateway struct { + TmProviderGateway *types.TmProviderGateway + vcdClient *VCDClient +} + +// wrap is a hidden helper that facilitates the usage of a generic CRUD function +// +//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck +func (g TmProviderGateway) wrap(inner *types.TmProviderGateway) *TmProviderGateway { + g.TmProviderGateway = inner + return &g +} + +func (vcdClient *VCDClient) CreateTmProviderGateway(config *types.TmProviderGateway) (*TmProviderGateway, error) { + c := crudConfig{ + entityLabel: labelTmProviderGateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + } + outerType := TmProviderGateway{vcdClient: vcdClient} + return createOuterEntity(&vcdClient.Client, outerType, c, config) +} + +func (vcdClient *VCDClient) GetAllTmProviderGateways(queryParameters url.Values) ([]*TmProviderGateway, error) { + c := crudConfig{ + entityLabel: labelTmProviderGateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + queryParameters: queryParameters, + } + + outerType := TmProviderGateway{vcdClient: vcdClient} + return getAllOuterEntities[TmProviderGateway, types.TmProviderGateway](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmProviderGatewayByName(name string) (*TmProviderGateway, error) { + if name == "" { + return nil, fmt.Errorf("%s lookup requires name", labelTmProviderGateway) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + + filteredEntities, err := vcdClient.GetAllTmProviderGateways(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) +} + +func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGateway, error) { + c := crudConfig{ + entityLabel: labelTmProviderGateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + endpointParams: []string{id}, + } + + outerType := TmProviderGateway{vcdClient: vcdClient} + return getOuterEntity[TmProviderGateway, types.TmProviderGateway](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId string) (*TmProviderGateway, error) { + if name == "" || orgId == "" { + return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmProviderGateway) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) + + filteredEntities, err := vcdClient.GetAllTmProviderGateways(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) +} + +func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.IpSpace) (*IpSpace, error) { + c := crudConfig{ + entityLabel: labelTmProviderGateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + endpointParams: []string{o.TmProviderGateway.ID}, + } + outerType := IpSpace{vcdClient: o.vcdClient} + return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmProviderGatewayConfig) +} + +func (o *TmProviderGateway) Delete() error { + c := crudConfig{ + entityLabel: labelTmProviderGateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + endpointParams: []string{o.TmProviderGateway.ID}, + } + return deleteEntityById(&o.vcdClient.Client, c) +} diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go new file mode 100644 index 000000000..91870b867 --- /dev/null +++ b/govcd/tm_provider_gateway_test.go @@ -0,0 +1,16 @@ +//go:build tm || functional || ALL + +/* + * Copyright 2024 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + . "gopkg.in/check.v1" +) + +// Test_ContentLibraryProvider tests CRUD operations for a Content Library with the Provider user +func (vcd *TestVCD) Test_TmProviderGateway(check *C) { + +} diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go new file mode 100644 index 000000000..4e9c9d6d1 --- /dev/null +++ b/govcd/tm_tier0_gateway.go @@ -0,0 +1,97 @@ +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v3/types/v56" +) + +const labelTmTier0Gateway = "TM Tier0 Gateway" + +type TmTier0Gateway struct { + TmTier0Gateway *types.TmTier0Gateway + vcdClient *VCDClient +} + +// wrap is a hidden helper that facilitates the usage of a generic CRUD function +// +//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck +func (g TmTier0Gateway) wrap(inner *types.TmTier0Gateway) *TmTier0Gateway { + g.TmTier0Gateway = inner + return &g +} + +func (vcdClient *VCDClient) CreateTmTier0Gateway(config *types.TmTier0Gateway) (*TmTier0Gateway, error) { + c := crudConfig{ + entityLabel: labelTmTier0Gateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, + } + outerType := TmTier0Gateway{vcdClient: vcdClient} + return createOuterEntity(&vcdClient.Client, outerType, c, config) +} + +func (vcdClient *VCDClient) GetAllTmTier0Gateways(queryParameters url.Values) ([]*TmTier0Gateway, error) { + c := crudConfig{ + entityLabel: labelTmTier0Gateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, + queryParameters: queryParameters, + } + + outerType := TmTier0Gateway{vcdClient: vcdClient} + return getAllOuterEntities[TmTier0Gateway, types.TmTier0Gateway](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmTier0GatewayByName(name string) (*TmTier0Gateway, error) { + if name == "" { + return nil, fmt.Errorf("%s lookup requires name", labelTmTier0Gateway) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + + filteredEntities, err := vcdClient.GetAllTmTier0Gateways(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmTier0GatewayById(singleEntity.TmTier0Gateway.ID) +} + +func (vcdClient *VCDClient) GetTmTier0GatewayById(id string) (*TmTier0Gateway, error) { + c := crudConfig{ + entityLabel: labelTmTier0Gateway, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, + endpointParams: []string{id}, + } + + outerType := TmTier0Gateway{vcdClient: vcdClient} + return getOuterEntity[TmTier0Gateway, types.TmTier0Gateway](&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmTier0GatewayByNameAndOrgId(name, orgId string) (*TmTier0Gateway, error) { + if name == "" || orgId == "" { + return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmTier0Gateway) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) + + filteredEntities, err := vcdClient.GetAllTmTier0Gateways(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + + return vcdClient.GetTmTier0GatewayById(singleEntity.TmTier0Gateway.ID) +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 98569098b..516a6a523 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -527,6 +527,8 @@ const ( OpenApiEndpointSupervisors = "supervisors/" OpenApiEndpointSupervisorZones = "supervisorZones/" OpenApiEndpointTmIpSpaces = "ipSpaces/" + OpenApiEndpointTmProviderGateways = "providerGateways/" + OpenApiEndpointTmTier0Gateways = "TBD/" ) // Header keys to run operations in tenant context diff --git a/types/v56/tm.go b/types/v56/tm.go index b047c7375..488f82bbd 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -182,3 +182,11 @@ type SupervisorZone struct { type TmIpSpace struct { ID string } + +type TmProviderGateway struct { + ID string +} + +type TmTier0Gateway struct { + ID string +} From 4b7d115711f32bb33a313c839379f7708453352c Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 11:36:00 +0200 Subject: [PATCH 03/21] WIP2 Signed-off-by: Dainius Serplis --- govcd/tm_ip_space.go | 4 +-- types/v56/tm.go | 62 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go index 91d58e5cd..d74078275 100644 --- a/govcd/tm_ip_space.go +++ b/govcd/tm_ip_space.go @@ -96,13 +96,13 @@ func (vcdClient *VCDClient) GetTmIpSpaceByNameAndOrgId(name, orgId string) (*TmI return vcdClient.GetTmIpSpaceById(singleEntity.TmIpSpace.ID) } -func (o *TmIpSpace) Update(TmIpSpaceConfig *types.IpSpace) (*IpSpace, error) { +func (o *TmIpSpace) Update(TmIpSpaceConfig *types.TmIpSpace) (*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces, endpointParams: []string{o.TmIpSpace.ID}, } - outerType := IpSpace{vcdClient: o.vcdClient} + outerType := TmIpSpace{vcdClient: o.vcdClient} return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmIpSpaceConfig) } diff --git a/types/v56/tm.go b/types/v56/tm.go index b047c7375..98443800b 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -179,6 +179,66 @@ type SupervisorZone struct { Region *OpenApiReference `json:"region"` } +// TmIpSpace provider configuration of mainly the external (or Inbound) IP Prefixes that specifies +// the accessible external networks from the data center type TmIpSpace struct { - ID string + ID string `json:"id,omitempty"` + // Name of the IP Space + Name string `json:"name"` + // Description of the IP Space + Description string `json:"description,omitempty"` + // RegionRef is the region that this IP Space belongs in. Only Provider Gateways in the same Region can be + // associated with this IP Space. This field cannot be updated + RegionRef OpenApiReference `json:"regionRef"` + + // Default IP quota that applies to all the organizations the Ip Space is assigned to + DefaultQuota TmIpSpaceDefaultQuota `json:"defaultQuota,omitempty"` + + // ExternalScopeCidr defines the total span of IP addresses to which the IP space has access. + // This typically defines the span of IP addresses outside the bounds of a Data Center. For the + // internet, this may be 0.0.0.0/0. For a WAN, this could be 10.0.0.0/8. + ExternalScopeCidr string `json:"externalScopeCidr,omitempty"` + // InternalScopeCidrBlocks defines the span of IP addresses used within a Data Center. For new + // CIDR value not in the existing list, a new IP Block will be created. For existing CIDR value, + // the IP Block's name can be updated. If an existing CIDR value is removed from the list, the + // the IP Block is removed from the IP Space. + InternalScopeCidrBlocks []TmIpSpaceInternalScopeCidrBlocks `json:"internalScopeCidrBlocks,omitempty"` + + // Represents current status of the networking entity. Possible values are: + // * PENDING - Desired entity configuration has been received by system and is pending realization. + // * CONFIGURING - The system is in process of realizing the entity. + // * REALIZED - The entity is successfully realized in the system. + // * REALIZATION_FAILED - There are some issues and the system is not able to realize the entity. + // * UNKNOWN - Current state of entity is unknown. + Status string `json:"status,omitempty"` +} + +// IP Space quota defines the maximum number of IPv4 IPs and CIDRs that can be allocated and used by +// the IP Space across all its Internal Scopes +type TmIpSpaceDefaultQuota struct { + // The maximum number of CIDRs with size maxSubnetSize or less, that can be allocated from all + // the Internal Scopes of the IP Space. A '-1' value means no cap on the number of the CIDRs + // used + MaxCidrCount int `json:"maxCidrCount,omitempty"` + // The maximum number of single floating IP addresses that can be allocated and used from all + // the Internal Scopes of the IP Space. A '-1' value means no cap on the number of floating IP + // Addresses + MaxIPCount int `json:"maxIpCount,omitempty"` + // The maximum size of the subnets, represented as a prefix length. The CIDRs that are allocated + // from the Internal Scopes of the IP Space must be smaller or equal to the specified size. For + // example, for a maxSubnetSize of 24, CIDRs with prefix length of 24, 28 or 30 can be + // allocated + MaxSubnetSize int `json:"maxSubnetSize,omitempty"` +} + +// An IP Block represents a named CIDR that is backed by a network provider +type TmIpSpaceInternalScopeCidrBlocks struct { + // Unique backing ID of the IP Block. This is not a Tenant Manager URN. This field is read-only and is ignored on create/update + ID string `json:"id,omitempty"` + // The name of the IP Block. If not set, a random name will be generated that will be prefixed + // with the name of the IP Space. This property is updatable if there's an existing IP Block + // with the CIDR value + Name string `json:"name,omitempty"` + // The CIDR that represents this IP Block. This property is not updatable + Cidr string `json:"cidr,omitempty"` } From ae1253f37fe61d4839793caaccd87ee6ad004e6e Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 16:28:50 +0200 Subject: [PATCH 04/21] WIP3 Signed-off-by: Dainius Serplis --- govcd/tm_common_test.go | 35 ++++++++++++++++-- govcd/tm_ip_space.go | 12 +++---- govcd/tm_ip_space_test.go | 74 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/govcd/tm_common_test.go b/govcd/tm_common_test.go index 24acdefac..bb5381499 100644 --- a/govcd/tm_common_test.go +++ b/govcd/tm_common_test.go @@ -7,9 +7,11 @@ package govcd import ( + "net/url" + "time" + "github.com/vmware/go-vcloud-director/v3/types/v56" . "gopkg.in/check.v1" - "net/url" ) // getOrCreateVCenter will check configuration file and create vCenter if @@ -29,7 +31,7 @@ func getOrCreateVCenter(vcd *TestVCD, check *C) (*VCenter, func()) { check.Skip("vCenter is not configured and configuration is not allowed in config file") return nil, nil } - + printVerbose("# Will create vCenter %s\n", vcd.config.Tm.VcenterUrl) vcCfg := &types.VSphereVirtualCenter{ Name: check.TestName() + "-vc", Username: vcd.config.Tm.VcenterUsername, @@ -43,6 +45,7 @@ func getOrCreateVCenter(vcd *TestVCD, check *C) (*VCenter, func()) { trustedCert, err := vcd.client.AutoTrustCertificate(url) check.Assert(err, IsNil) if trustedCert != nil { + printVerbose("# Certificate for vCenter is trusted %s\n", trustedCert.TrustedCertificate.ID) AddToCleanupListOpenApi(trustedCert.TrustedCertificate.ID, check.TestName()+"trusted-cert", types.OpenApiPathVersion1_0_0+types.OpenApiEndpointTrustedCertificates+trustedCert.TrustedCertificate.ID) } @@ -51,6 +54,8 @@ func getOrCreateVCenter(vcd *TestVCD, check *C) (*VCenter, func()) { check.Assert(vc, NotNil) PrependToCleanupList(vcCfg.Name, "OpenApiEntityVcenter", check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointVirtualCenters+vc.VSphereVCenter.VcId) + printVerbose("# Sleeping after vCenter creation\n") + time.Sleep(1 * time.Minute) // TODO: TM: Reevaluate need for sleep // Refresh connected vCenter to be sure that all artifacts are loaded printVerbose("# Refreshing vCenter %s\n", vc.VSphereVCenter.Url) err = vc.Refresh() @@ -60,12 +65,15 @@ func getOrCreateVCenter(vcd *TestVCD, check *C) (*VCenter, func()) { err = vc.RefreshStorageProfiles() check.Assert(err, IsNil) + printVerbose("# Sleeping after vCenter refreshes\n") + time.Sleep(1 * time.Minute) // TODO: TM: Reevaluate need for sleep vCenterCreated := true return vc, func() { if !vCenterCreated { return } + printVerbose("# Disabling and deleting vCenter %s\n", vcd.config.Tm.VcenterUrl) err = vc.Disable() check.Assert(err, IsNil) err = vc.Delete() @@ -91,6 +99,7 @@ func getOrCreateNsxtManager(vcd *TestVCD, check *C) (*NsxtManagerOpenApi, func() return nil, nil } + printVerbose("# Will create NSX-T Manager %s\n", vcd.config.Tm.NsxtManagerUrl) nsxtCfg := &types.NsxtManagerOpenApi{ Name: check.TestName(), Username: vcd.config.Tm.NsxtManagerUsername, @@ -103,6 +112,7 @@ func getOrCreateNsxtManager(vcd *TestVCD, check *C) (*NsxtManagerOpenApi, func() trustedCert, err := vcd.client.AutoTrustCertificate(url) check.Assert(err, IsNil) if trustedCert != nil { + printVerbose("# Certificate for NSX-T Manager is trusted %s\n", trustedCert.TrustedCertificate.ID) AddToCleanupListOpenApi(trustedCert.TrustedCertificate.ID, check.TestName()+"trusted-cert", types.OpenApiPathVersion1_0_0+types.OpenApiEndpointTrustedCertificates+trustedCert.TrustedCertificate.ID) } nsxtManager, err = vcd.client.CreateNsxtManagerOpenApi(nsxtCfg) @@ -115,6 +125,7 @@ func getOrCreateNsxtManager(vcd *TestVCD, check *C) (*NsxtManagerOpenApi, func() if !nsxtManagerCreated { return } + printVerbose("# Deleting NSX-T Manager %s\n", nsxtManager.NsxtManagerOpenApi.Name) err = nsxtManager.Delete() check.Assert(err, IsNil) } @@ -160,12 +171,32 @@ func getOrCreateRegion(vcd *TestVCD, nsxtManager *NsxtManagerOpenApi, supervisor check.Assert(region, NotNil) regionCreated := true AddToCleanupListOpenApi(region.Region.ID, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointRegions+region.Region.ID) + check.Assert(region.Region.Status, Equals, "READY") // Region must be READY to be operational return region, func() { if !regionCreated { return } + printVerbose("# Deleting Region %s\n", region.Region.Name) err = region.Delete() check.Assert(err, IsNil) } } + +func createOrg(vcd *TestVCD, check *C, canManageOrgs bool) (*TmOrg, func()) { + cfg := &types.TmOrg{ + Name: check.TestName(), + DisplayName: check.TestName(), + CanManageOrgs: canManageOrgs, + } + tmOrg, err := vcd.client.CreateTmOrg(cfg) + check.Assert(err, IsNil) + check.Assert(tmOrg, NotNil) + + PrependToCleanupListOpenApi(tmOrg.TmOrg.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointOrgs+tmOrg.TmOrg.ID) + + return tmOrg, func() { + err = tmOrg.Delete() + check.Assert(err, IsNil) + } +} diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go index d74078275..fcaadf4db 100644 --- a/govcd/tm_ip_space.go +++ b/govcd/tm_ip_space.go @@ -39,7 +39,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaces(queryParameters url.Values) ([]*TmI } outerType := TmIpSpace{vcdClient: vcdClient} - return getAllOuterEntities[TmIpSpace, types.TmIpSpace](&vcdClient.Client, outerType, c) + return getAllOuterEntities(&vcdClient.Client, outerType, c) } func (vcdClient *VCDClient) GetTmIpSpaceByName(name string) (*TmIpSpace, error) { @@ -71,17 +71,17 @@ func (vcdClient *VCDClient) GetTmIpSpaceById(id string) (*TmIpSpace, error) { } outerType := TmIpSpace{vcdClient: vcdClient} - return getOuterEntity[TmIpSpace, types.TmIpSpace](&vcdClient.Client, outerType, c) + return getOuterEntity(&vcdClient.Client, outerType, c) } -func (vcdClient *VCDClient) GetTmIpSpaceByNameAndOrgId(name, orgId string) (*TmIpSpace, error) { - if name == "" || orgId == "" { - return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmIpSpace) +func (vcdClient *VCDClient) GetTmIpSpaceByNameAndRegionId(name, regionId string) (*TmIpSpace, error) { + if name == "" || regionId == "" { + return nil, fmt.Errorf("%s lookup requires name and Region ID", labelTmIpSpace) } queryParams := url.Values{} queryParams.Add("filter", "name=="+name) - queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) + queryParams = queryParameterFilterAnd("regionRef.id=="+regionId, queryParams) filteredEntities, err := vcdClient.GetAllTmIpSpaces(queryParams) if err != nil { diff --git a/govcd/tm_ip_space_test.go b/govcd/tm_ip_space_test.go index 7e55ebfd9..e81466e23 100644 --- a/govcd/tm_ip_space_test.go +++ b/govcd/tm_ip_space_test.go @@ -7,10 +7,82 @@ package govcd import ( + "github.com/vmware/go-vcloud-director/v3/types/v56" . "gopkg.in/check.v1" ) -// Test_ContentLibraryProvider tests CRUD operations for a Content Library with the Provider user func (vcd *TestVCD) Test_TmIpSpace(check *C) { + skipNonTm(vcd, check) + sysadminOnly(vcd, check) + vc, vcCleanup := getOrCreateVCenter(vcd, check) + defer vcCleanup() + nsxtManager, nsxtManagerCleanup := getOrCreateNsxtManager(vcd, check) + defer nsxtManagerCleanup() + supervisor, err := vc.GetSupervisorByName(vcd.config.Tm.VcenterSupervisor) + check.Assert(err, IsNil) + region, regionCleanup := getOrCreateRegion(vcd, nsxtManager, supervisor, check) + defer regionCleanup() + + ipSpaceType := &types.TmIpSpace{ + Name: check.TestName(), + RegionRef: types.OpenApiReference{ID: region.Region.ID}, + Description: check.TestName(), + DefaultQuota: types.TmIpSpaceDefaultQuota{ + MaxCidrCount: 3, + MaxIPCount: -1, + MaxSubnetSize: 24, + }, + ExternalScopeCidr: "12.12.0.0/30", + InternalScopeCidrBlocks: []types.TmIpSpaceInternalScopeCidrBlocks{ + { + Cidr: "10.0.0.0/24", + }, + }, + } + + createdIpSpace, err := vcd.client.CreateTmIpSpace(ipSpaceType) + check.Assert(err, IsNil) + check.Assert(createdIpSpace, NotNil) + // Add to cleanup list + PrependToCleanupListOpenApi(createdIpSpace.TmIpSpace.ID, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointTmIpSpaces+createdIpSpace.TmIpSpace.ID) + defer func() { + err = createdIpSpace.Delete() + check.Assert(err, IsNil) + }() + + // Get TM VDC By Name + byName, err := vcd.client.GetTmIpSpaceByName(ipSpaceType.Name) + check.Assert(err, IsNil) + check.Assert(byName.TmIpSpace, DeepEquals, createdIpSpace.TmIpSpace) + + // Get TM VDC By Id + byId, err := vcd.client.GetTmIpSpaceById(createdIpSpace.TmIpSpace.ID) + check.Assert(err, IsNil) + check.Assert(byId.TmIpSpace, DeepEquals, createdIpSpace.TmIpSpace) + + // Get By Name and Org ID + byNameAndOrgId, err := vcd.client.GetTmIpSpaceByNameAndRegionId(createdIpSpace.TmIpSpace.Name, region.Region.ID) + check.Assert(err, IsNil) + check.Assert(byNameAndOrgId.TmIpSpace, DeepEquals, createdIpSpace.TmIpSpace) + + // Get By Name and Org ID in non existent Region + byNameAndInvalidOrgId, err := vcd.client.GetTmIpSpaceByNameAndRegionId(createdIpSpace.TmIpSpace.Name, "urn:vcloud:region:a93c9db9-0000-0000-0000-a8f7eeda85f9") + check.Assert(err, NotNil) + check.Assert(byNameAndInvalidOrgId, IsNil) + + // Not Found tests + byNameInvalid, err := vcd.client.GetTmIpSpaceByName("fake-name") + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(byNameInvalid, IsNil) + + byIdInvalid, err := vcd.client.GetTmIpSpaceById("urn:vcloud:ipSpace:5344b964-0000-0000-0000-d554913db643") + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(byIdInvalid, IsNil) + + // Update + createdIpSpace.TmIpSpace.Name = check.TestName() + "-update" + updatedVdc, err := createdIpSpace.Update(createdIpSpace.TmIpSpace) + check.Assert(err, IsNil) + check.Assert(updatedVdc.TmIpSpace, DeepEquals, createdIpSpace.TmIpSpace) } From f28970596dc7b6a816bcd81bf341ee5a22c13842 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 16:35:44 +0200 Subject: [PATCH 05/21] Changelog + remove unused test function Signed-off-by: Dainius Serplis --- .changes/v3.0.0/718-features.md | 2 +- .changes/v3.0.0/724-features.md | 4 ++++ govcd/tm_common_test.go | 18 ------------------ 3 files changed, 5 insertions(+), 19 deletions(-) create mode 100644 .changes/v3.0.0/724-features.md diff --git a/.changes/v3.0.0/718-features.md b/.changes/v3.0.0/718-features.md index 838ae77df..7960970f9 100644 --- a/.changes/v3.0.0/718-features.md +++ b/.changes/v3.0.0/718-features.md @@ -4,7 +4,7 @@ [GH-718] * Added `VCenter.RefreshStorageProfiles` to refresh storage profiles available in vCenter server [GH-718] -* Added `Region` and `types.Region` to structure for OpenAPI management of Regions with methods +* Added `Region` and `types.Region` structures for OpenAPI management of Regions with methods `VCDClient.CreateRegion`, `VCDClient.GetAllRegions`, `VCDClient.GetRegionByName`, `VCDClient.GetRegionById`, `Region.Update`, `Region.Delete` [GH-718] * Added `Supervisor` and `types.Supervisor` structure for reading available Supervisors diff --git a/.changes/v3.0.0/724-features.md b/.changes/v3.0.0/724-features.md new file mode 100644 index 000000000..db7a7ce1e --- /dev/null +++ b/.changes/v3.0.0/724-features.md @@ -0,0 +1,4 @@ +* Added `TmIpSpace` and `types.TmIpSpace` structures for OpenAPI management of TM IP Spaces with + methods `VCDClient.CreateTmIpSpace`, `VCDClient.GetAllTmIpSpaces`, `VCDClient.GetTmIpSpaceByName`, + `VCDClient.GetTmIpSpaceById`, `VCDClient.GetTmIpSpaceByNameAndRegionId`, `TmIpSpace.Update`, + `TmIpSpace.Delete` [GH-724] diff --git a/govcd/tm_common_test.go b/govcd/tm_common_test.go index bb5381499..2ce5c4731 100644 --- a/govcd/tm_common_test.go +++ b/govcd/tm_common_test.go @@ -182,21 +182,3 @@ func getOrCreateRegion(vcd *TestVCD, nsxtManager *NsxtManagerOpenApi, supervisor check.Assert(err, IsNil) } } - -func createOrg(vcd *TestVCD, check *C, canManageOrgs bool) (*TmOrg, func()) { - cfg := &types.TmOrg{ - Name: check.TestName(), - DisplayName: check.TestName(), - CanManageOrgs: canManageOrgs, - } - tmOrg, err := vcd.client.CreateTmOrg(cfg) - check.Assert(err, IsNil) - check.Assert(tmOrg, NotNil) - - PrependToCleanupListOpenApi(tmOrg.TmOrg.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointOrgs+tmOrg.TmOrg.ID) - - return tmOrg, func() { - err = tmOrg.Delete() - check.Assert(err, IsNil) - } -} From da5d96b1bf7ebbf4b6f1a9be2fb7fec4ef5fcac4 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 2 Dec 2024 16:44:37 +0200 Subject: [PATCH 06/21] Docs Signed-off-by: Dainius Serplis --- govcd/tm_ip_space.go | 9 +++++++++ types/v56/tm.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go index fcaadf4db..079c41530 100644 --- a/govcd/tm_ip_space.go +++ b/govcd/tm_ip_space.go @@ -9,6 +9,8 @@ import ( const labelTmIpSpace = "TM IP Space" +// TmIpSpace provides configuration of mainly the external (or Inbound) IP Prefixes that specifies +// the accessible external networks from the data center type TmIpSpace struct { TmIpSpace *types.TmIpSpace vcdClient *VCDClient @@ -22,6 +24,7 @@ func (g TmIpSpace) wrap(inner *types.TmIpSpace) *TmIpSpace { return &g } +// CreateTmIpSpace with a given configuration func (vcdClient *VCDClient) CreateTmIpSpace(config *types.TmIpSpace) (*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, @@ -31,6 +34,7 @@ func (vcdClient *VCDClient) CreateTmIpSpace(config *types.TmIpSpace) (*TmIpSpace return createOuterEntity(&vcdClient.Client, outerType, c, config) } +// GetAllTmIpSpaces fetches all TM IP Spaces with an optional query filter func (vcdClient *VCDClient) GetAllTmIpSpaces(queryParameters url.Values) ([]*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, @@ -42,6 +46,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaces(queryParameters url.Values) ([]*TmI return getAllOuterEntities(&vcdClient.Client, outerType, c) } +// GetTmIpSpaceByName retrieves TM IP Spaces with a given name func (vcdClient *VCDClient) GetTmIpSpaceByName(name string) (*TmIpSpace, error) { if name == "" { return nil, fmt.Errorf("%s lookup requires name", labelTmIpSpace) @@ -63,6 +68,7 @@ func (vcdClient *VCDClient) GetTmIpSpaceByName(name string) (*TmIpSpace, error) return vcdClient.GetTmIpSpaceById(singleEntity.TmIpSpace.ID) } +// GetTmIpSpaceById retrieves an exact IP Space with a given ID func (vcdClient *VCDClient) GetTmIpSpaceById(id string) (*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, @@ -74,6 +80,7 @@ func (vcdClient *VCDClient) GetTmIpSpaceById(id string) (*TmIpSpace, error) { return getOuterEntity(&vcdClient.Client, outerType, c) } +// GetTmIpSpaceByNameAndRegionId retrieves TM IP Spaces with a given name in a provided Region func (vcdClient *VCDClient) GetTmIpSpaceByNameAndRegionId(name, regionId string) (*TmIpSpace, error) { if name == "" || regionId == "" { return nil, fmt.Errorf("%s lookup requires name and Region ID", labelTmIpSpace) @@ -96,6 +103,7 @@ func (vcdClient *VCDClient) GetTmIpSpaceByNameAndRegionId(name, regionId string) return vcdClient.GetTmIpSpaceById(singleEntity.TmIpSpace.ID) } +// Update TM IP Space func (o *TmIpSpace) Update(TmIpSpaceConfig *types.TmIpSpace) (*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, @@ -106,6 +114,7 @@ func (o *TmIpSpace) Update(TmIpSpaceConfig *types.TmIpSpace) (*TmIpSpace, error) return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmIpSpaceConfig) } +// Delete TM IP Space func (o *TmIpSpace) Delete() error { c := crudConfig{ entityLabel: labelTmIpSpace, diff --git a/types/v56/tm.go b/types/v56/tm.go index 98443800b..aa12dcde5 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -179,7 +179,7 @@ type SupervisorZone struct { Region *OpenApiReference `json:"region"` } -// TmIpSpace provider configuration of mainly the external (or Inbound) IP Prefixes that specifies +// TmIpSpace provides configuration of mainly the external (or Inbound) IP Prefixes that specifies // the accessible external networks from the data center type TmIpSpace struct { ID string `json:"id,omitempty"` From 501025ff041108ecbfa2845aa216b268abbfb771 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 06:59:53 +0200 Subject: [PATCH 07/21] Self review docs 2 Signed-off-by: Dainius Serplis --- govcd/tm_ip_space.go | 2 +- types/v56/tm.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go index 079c41530..9efe30c2e 100644 --- a/govcd/tm_ip_space.go +++ b/govcd/tm_ip_space.go @@ -9,7 +9,7 @@ import ( const labelTmIpSpace = "TM IP Space" -// TmIpSpace provides configuration of mainly the external (or Inbound) IP Prefixes that specifies +// TmIpSpace provides configuration of mainly the external IP Prefixes that specifies // the accessible external networks from the data center type TmIpSpace struct { TmIpSpace *types.TmIpSpace diff --git a/types/v56/tm.go b/types/v56/tm.go index aa12dcde5..5b9278f51 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -179,7 +179,7 @@ type SupervisorZone struct { Region *OpenApiReference `json:"region"` } -// TmIpSpace provides configuration of mainly the external (or Inbound) IP Prefixes that specifies +// TmIpSpace provides configuration of mainly the external IP Prefixes that specifies // the accessible external networks from the data center type TmIpSpace struct { ID string `json:"id,omitempty"` @@ -190,10 +190,8 @@ type TmIpSpace struct { // RegionRef is the region that this IP Space belongs in. Only Provider Gateways in the same Region can be // associated with this IP Space. This field cannot be updated RegionRef OpenApiReference `json:"regionRef"` - // Default IP quota that applies to all the organizations the Ip Space is assigned to DefaultQuota TmIpSpaceDefaultQuota `json:"defaultQuota,omitempty"` - // ExternalScopeCidr defines the total span of IP addresses to which the IP space has access. // This typically defines the span of IP addresses outside the bounds of a Data Center. For the // internet, this may be 0.0.0.0/0. For a WAN, this could be 10.0.0.0/8. @@ -203,7 +201,6 @@ type TmIpSpace struct { // the IP Block's name can be updated. If an existing CIDR value is removed from the list, the // the IP Block is removed from the IP Space. InternalScopeCidrBlocks []TmIpSpaceInternalScopeCidrBlocks `json:"internalScopeCidrBlocks,omitempty"` - // Represents current status of the networking entity. Possible values are: // * PENDING - Desired entity configuration has been received by system and is pending realization. // * CONFIGURING - The system is in process of realizing the entity. From 56130c8b66f07a6851dc457b847899f6f8946b9c Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 07:46:28 +0200 Subject: [PATCH 08/21] Stabilize Signed-off-by: Dainius Serplis --- govcd/tm_provider_gateway.go | 4 ++-- govcd/tm_tier0_gateway.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index 51a405947..79096d5ce 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -118,13 +118,13 @@ func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId strin return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) } -func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.IpSpace) (*IpSpace, error) { +func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.TmProviderGateway) (*TmProviderGateway, error) { c := crudConfig{ entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, endpointParams: []string{o.TmProviderGateway.ID}, } - outerType := IpSpace{vcdClient: o.vcdClient} + outerType := TmProviderGateway{vcdClient: o.vcdClient} return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmProviderGatewayConfig) } diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go index 4e9c9d6d1..01ab7592d 100644 --- a/govcd/tm_tier0_gateway.go +++ b/govcd/tm_tier0_gateway.go @@ -39,7 +39,7 @@ func (vcdClient *VCDClient) GetAllTmTier0Gateways(queryParameters url.Values) ([ } outerType := TmTier0Gateway{vcdClient: vcdClient} - return getAllOuterEntities[TmTier0Gateway, types.TmTier0Gateway](&vcdClient.Client, outerType, c) + return getAllOuterEntities(&vcdClient.Client, outerType, c) } func (vcdClient *VCDClient) GetTmTier0GatewayByName(name string) (*TmTier0Gateway, error) { @@ -71,7 +71,7 @@ func (vcdClient *VCDClient) GetTmTier0GatewayById(id string) (*TmTier0Gateway, e } outerType := TmTier0Gateway{vcdClient: vcdClient} - return getOuterEntity[TmTier0Gateway, types.TmTier0Gateway](&vcdClient.Client, outerType, c) + return getOuterEntity(&vcdClient.Client, outerType, c) } func (vcdClient *VCDClient) GetTmTier0GatewayByNameAndOrgId(name, orgId string) (*TmTier0Gateway, error) { From 34f261d2418a20acd8357b4212e65c282e853b97 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 12:48:39 +0200 Subject: [PATCH 09/21] WIP? Signed-off-by: Dainius Serplis --- govcd/api_vcd_test.go | 2 + govcd/openapi_endpoints.go | 3 + govcd/tm_provider_gateway.go | 2 +- govcd/tm_provider_gateway_test.go | 28 ++++++++- govcd/tm_tier0_gateway.go | 94 ++++++++++++++----------------- types/v56/constants.go | 1 - types/v56/tm.go | 6 +- 7 files changed, 79 insertions(+), 57 deletions(-) diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index db6f1ea5b..f4bb9fab5 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -158,6 +158,8 @@ type TestConfig struct { NsxtManagerUsername string `yaml:"nsxtManagerUsername"` NsxtManagerPassword string `yaml:"nsxtManagerPassword"` NsxtManagerUrl string `yaml:"nsxtManagerUrl"` + + NsxtTier0Gateway string `yaml:"nsxtTier0Gateway"` } `yaml:"tm,omitempty"` VCD struct { Org string `yaml:"org"` diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 66915f3e2..8e983b150 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -254,6 +254,9 @@ var endpointElevatedApiVersions = map[string][]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs: { "40.0", // TM Orgs }, + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers: { + "40.0", // TM Tier 0 Gateways + }, } // checkOpenApiEndpointCompatibility checks if VCD version (to which the client is connected) is sufficient to work with diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index 79096d5ce..c4471db4e 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -61,7 +61,7 @@ func (vcdClient *VCDClient) GetAllTmProviderGateways(queryParameters url.Values) } outerType := TmProviderGateway{vcdClient: vcdClient} - return getAllOuterEntities[TmProviderGateway, types.TmProviderGateway](&vcdClient.Client, outerType, c) + return getAllOuterEntities(&vcdClient.Client, outerType, c) } func (vcdClient *VCDClient) GetTmProviderGatewayByName(name string) (*TmProviderGateway, error) { diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index 91870b867..ce6205aeb 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -10,7 +10,33 @@ import ( . "gopkg.in/check.v1" ) -// Test_ContentLibraryProvider tests CRUD operations for a Content Library with the Provider user func (vcd *TestVCD) Test_TmProviderGateway(check *C) { + skipNonTm(vcd, check) + sysadminOnly(vcd, check) + + vc, vcCleanup := getOrCreateVCenter(vcd, check) + defer vcCleanup() + nsxtManager, nsxtManagerCleanup := getOrCreateNsxtManager(vcd, check) + defer nsxtManagerCleanup() + supervisor, err := vc.GetSupervisorByName(vcd.config.Tm.VcenterSupervisor) + check.Assert(err, IsNil) + region, regionCleanup := getOrCreateRegion(vcd, nsxtManager, supervisor, check) + defer regionCleanup() + + // Performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests + allT0sWithContextFilter, err := vcd.client.GetAllTmTier0GatewaysWithContext(region.Region.ID, true) + check.Assert(err, IsNil) + check.Assert(len(allT0sWithContextFilter) > 0, Equals, true) + + t0ByNameInRegion, err := vcd.client.GetTmTier0GatewayWithContextByName(vcd.config.Tm.NsxtTier0Gateway, region.Region.ID, false) + check.Assert(err, IsNil) + check.Assert(t0ByNameInRegion, NotNil) + check.Assert(t0ByNameInRegion.TmTier0Gateway.DisplayName, Equals, vcd.config.Tm.NsxtTier0Gateway) + + t0ByNameInNsxtManager, err := vcd.client.GetTmTier0GatewayWithContextByName(vcd.config.Tm.NsxtTier0Gateway, nsxtManager.NsxtManagerOpenApi.ID, false) + check.Assert(err, IsNil) + check.Assert(t0ByNameInNsxtManager, NotNil) + check.Assert(t0ByNameInNsxtManager.TmTier0Gateway.DisplayName, Equals, vcd.config.Tm.NsxtTier0Gateway) + // End of performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests } diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go index 01ab7592d..9a0cac27d 100644 --- a/govcd/tm_tier0_gateway.go +++ b/govcd/tm_tier0_gateway.go @@ -7,6 +7,10 @@ import ( "github.com/vmware/go-vcloud-director/v3/types/v56" ) +// Sample query +// https://vcfa.10.162.145.191.vcfd.broadcom.net/tm/cloudapi/1.0.0/nsxTResources/importableTier0Routers +// ?page=1&pageSize=128&filterEncoded=true&filter=(alreadyImported==false;_context==urn:vcloud:region:7544b246-84c6-40ad-8c3b-beed9fe145cd)&links=true + const labelTmTier0Gateway = "TM Tier0 Gateway" type TmTier0Gateway struct { @@ -22,76 +26,60 @@ func (g TmTier0Gateway) wrap(inner *types.TmTier0Gateway) *TmTier0Gateway { return &g } -func (vcdClient *VCDClient) CreateTmTier0Gateway(config *types.TmTier0Gateway) (*TmTier0Gateway, error) { - c := crudConfig{ - entityLabel: labelTmTier0Gateway, - endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, - } - outerType := TmTier0Gateway{vcdClient: vcdClient} - return createOuterEntity(&vcdClient.Client, outerType, c, config) -} - -func (vcdClient *VCDClient) GetAllTmTier0Gateways(queryParameters url.Values) ([]*TmTier0Gateway, error) { - c := crudConfig{ - entityLabel: labelTmTier0Gateway, - endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, - queryParameters: queryParameters, +func (vcdClient *VCDClient) GetAllTmTier0GatewaysWithContext(contextEntity string, listImported bool) ([]*TmTier0Gateway, error) { + if contextEntity == "" { + return nil, fmt.Errorf("empty region provided") } + queryParams := copyOrNewUrlValues(nil) + queryParams = queryParameterFilterAnd(fmt.Sprintf("_context==%s", contextEntity), queryParams) + queryParams = queryParameterFilterAnd(fmt.Sprintf("alreadyImported==%t", listImported), queryParams) - outerType := TmTier0Gateway{vcdClient: vcdClient} - return getAllOuterEntities(&vcdClient.Client, outerType, c) + return vcdClient.getAllTmTier0Gateways(queryParams) } -func (vcdClient *VCDClient) GetTmTier0GatewayByName(name string) (*TmTier0Gateway, error) { - if name == "" { - return nil, fmt.Errorf("%s lookup requires name", labelTmTier0Gateway) +func (vcdClient *VCDClient) GetTmTier0GatewayWithContextByName(displayName, contextEntity string, listImported bool) (*TmTier0Gateway, error) { + if contextEntity == "" { + return nil, fmt.Errorf("empty region provided") + } + if displayName == "" { + return nil, fmt.Errorf("empty name provided") } - queryParams := url.Values{} - queryParams.Add("filter", "name=="+name) + queryParams := copyOrNewUrlValues(nil) + queryParams = queryParameterFilterAnd(fmt.Sprintf("_context==%s", contextEntity), queryParams) + queryParams = queryParameterFilterAnd(fmt.Sprintf("alreadyImported==%t", listImported), queryParams) - filteredEntities, err := vcdClient.GetAllTmTier0Gateways(queryParams) + allT0s, err := vcdClient.getAllTmTier0Gateways(queryParams) if err != nil { return nil, err } - singleEntity, err := oneOrError("name", name, filteredEntities) - if err != nil { - return nil, err + var foundValue *TmTier0Gateway + for _, v := range allT0s { + if v.TmTier0Gateway.DisplayName == displayName { + if foundValue != nil { + return nil, fmt.Errorf("found more than one %s by Name '%s'", labelTmTier0Gateway, displayName) + } + foundValue = v + } } - return vcdClient.GetTmTier0GatewayById(singleEntity.TmTier0Gateway.ID) -} - -func (vcdClient *VCDClient) GetTmTier0GatewayById(id string) (*TmTier0Gateway, error) { - c := crudConfig{ - entityLabel: labelTmTier0Gateway, - endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmTier0Gateways, - endpointParams: []string{id}, + if foundValue == nil { + return nil, fmt.Errorf("no %s found by Name '%s'", labelTmTier0Gateway, displayName) } - outerType := TmTier0Gateway{vcdClient: vcdClient} - return getOuterEntity(&vcdClient.Client, outerType, c) + return foundValue, nil } -func (vcdClient *VCDClient) GetTmTier0GatewayByNameAndOrgId(name, orgId string) (*TmTier0Gateway, error) { - if name == "" || orgId == "" { - return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmTier0Gateway) - } - - queryParams := url.Values{} - queryParams.Add("filter", "name=="+name) - queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) - - filteredEntities, err := vcdClient.GetAllTmTier0Gateways(queryParams) - if err != nil { - return nil, err - } - - singleEntity, err := oneOrError("name", name, filteredEntities) - if err != nil { - return nil, err +// getAllTmTier0Gateways is kept private as one receives 0 entries when querying without filters, +// but it is useful construct in higher level functions +func (vcdClient *VCDClient) getAllTmTier0Gateways(queryParameters url.Values) ([]*TmTier0Gateway, error) { + c := crudConfig{ + entityLabel: labelTmTier0Gateway, + endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers, + queryParameters: queryParameters, } - return vcdClient.GetTmTier0GatewayById(singleEntity.TmTier0Gateway.ID) + outerType := TmTier0Gateway{vcdClient: vcdClient} + return getAllOuterEntities(&vcdClient.Client, outerType, c) } diff --git a/types/v56/constants.go b/types/v56/constants.go index 516a6a523..d05ada4b1 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -528,7 +528,6 @@ const ( OpenApiEndpointSupervisorZones = "supervisorZones/" OpenApiEndpointTmIpSpaces = "ipSpaces/" OpenApiEndpointTmProviderGateways = "providerGateways/" - OpenApiEndpointTmTier0Gateways = "TBD/" ) // Header keys to run operations in tenant context diff --git a/types/v56/tm.go b/types/v56/tm.go index e7350f648..944443d17 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -245,5 +245,9 @@ type TmProviderGateway struct { } type TmTier0Gateway struct { - ID string + ID string `json:"id"` + Description string `json:"description"` + DisplayName string `json:"displayName"` + ParentTier0ID string `json:"parentTier0Id"` + AlreadyImported bool `json:"alreadyImported"` } From 462cde9084b8ffda5f24923e2e9bb7021b82cbd3 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 15:46:00 +0200 Subject: [PATCH 10/21] WIP4 Signed-off-by: Dainius Serplis --- govcd/tm_common_test.go | 30 +++++++++++++++++++++++ govcd/tm_provider_gateway_test.go | 40 +++++++++++++++++++++++++++++++ types/v56/tm.go | 15 ++++++++---- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/govcd/tm_common_test.go b/govcd/tm_common_test.go index 2ce5c4731..49dbfebfd 100644 --- a/govcd/tm_common_test.go +++ b/govcd/tm_common_test.go @@ -182,3 +182,33 @@ func getOrCreateRegion(vcd *TestVCD, nsxtManager *NsxtManagerOpenApi, supervisor check.Assert(err, IsNil) } } + +func createTmIpSpace(vcd *TestVCD, region *Region, check *C) (*TmIpSpace, func()) { + ipSpaceType := &types.TmIpSpace{ + Name: check.TestName(), + RegionRef: types.OpenApiReference{ID: region.Region.ID}, + Description: check.TestName(), + DefaultQuota: types.TmIpSpaceDefaultQuota{ + MaxCidrCount: 3, + MaxIPCount: -1, + MaxSubnetSize: 24, + }, + ExternalScopeCidr: "12.12.0.0/30", + InternalScopeCidrBlocks: []types.TmIpSpaceInternalScopeCidrBlocks{ + { + Cidr: "10.0.0.0/24", + }, + }, + } + + ipSpace, err := vcd.client.CreateTmIpSpace(ipSpaceType) + check.Assert(err, IsNil) + check.Assert(ipSpace, NotNil) + AddToCleanupListOpenApi(ipSpace.TmIpSpace.ID, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointTmIpSpaces+ipSpace.TmIpSpace.ID) + + return ipSpace, func() { + printVerbose("# Deleting IP Space %s\n", ipSpace.TmIpSpace.Name) + err = ipSpace.Delete() + check.Assert(err, IsNil) + } +} diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index ce6205aeb..4f09c346e 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -7,6 +7,7 @@ package govcd import ( + "github.com/vmware/go-vcloud-director/v3/types/v56" . "gopkg.in/check.v1" ) @@ -23,6 +24,9 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { region, regionCleanup := getOrCreateRegion(vcd, nsxtManager, supervisor, check) defer regionCleanup() + ipSpace, ipSpaceCleanup := createTmIpSpace(vcd, region, check) + defer ipSpaceCleanup() + // Performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests allT0sWithContextFilter, err := vcd.client.GetAllTmTier0GatewaysWithContext(region.Region.ID, true) check.Assert(err, IsNil) @@ -39,4 +43,40 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { check.Assert(t0ByNameInNsxtManager.TmTier0Gateway.DisplayName, Equals, vcd.config.Tm.NsxtTier0Gateway) // End of performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests + // Provider Gateway + + t := &types.TmProviderGateway{ + Name: check.TestName(), + Description: check.TestName(), + BackingType: "NSX_TIER0", + BackingRef: &types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, + RegionRef: &types.OpenApiReference{ID: region.Region.ID}, + IPSpaceRefs: []*types.OpenApiReference{{ + ID: ipSpace.TmIpSpace.ID, + }}, + } + + createdProviderGateway, err := vcd.client.CreateTmProviderGateway(t) + } + +// { +// "name": "test-provider-gw", +// "description": "", +// "orgRef": null, +// "backingRef": { +// "id": "37273049-ecda-4974-baf6-5c107f30a969", +// "name": "vcfcons-mgt-vc03-Tier0" +// }, +// "backingType": "NSX_TIER0", +// "regionRef": { +// "id": "urn:vcloud:region:7544b246-84c6-40ad-8c3b-beed9fe145cd", +// "name": "Terraform demo Region" +// }, +// "ipSpaceRefs": [ +// { +// "id": "urn:vcloud:ipSpace:feb3d26d-08e7-4e3f-90cc-f54f13a45697", +// "name": "demo-ip-space" +// } +// ] +// } diff --git a/types/v56/tm.go b/types/v56/tm.go index 944443d17..c9752002f 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -240,10 +240,6 @@ type TmIpSpaceInternalScopeCidrBlocks struct { Cidr string `json:"cidr,omitempty"` } -type TmProviderGateway struct { - ID string -} - type TmTier0Gateway struct { ID string `json:"id"` Description string `json:"description"` @@ -251,3 +247,14 @@ type TmTier0Gateway struct { ParentTier0ID string `json:"parentTier0Id"` AlreadyImported bool `json:"alreadyImported"` } + +type TmProviderGateway struct { + ID string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + OrgRef *OpenApiReference `json:"orgRef,omitempty"` + BackingRef *OpenApiReference `json:"backingRef,omitempty"` + BackingType string `json:"backingType,omitempty"` + RegionRef *OpenApiReference `json:"regionRef,omitempty"` + IPSpaceRefs []*OpenApiReference `json:"ipSpaceRefs,omitempty"` +} From daac0d1e20137e0b7cf9c38a01333802e750b89d Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 15:47:13 +0200 Subject: [PATCH 11/21] Address comment Signed-off-by: Dainius Serplis --- govcd/tm_ip_space.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/tm_ip_space.go b/govcd/tm_ip_space.go index 9efe30c2e..b7f48d81a 100644 --- a/govcd/tm_ip_space.go +++ b/govcd/tm_ip_space.go @@ -24,7 +24,7 @@ func (g TmIpSpace) wrap(inner *types.TmIpSpace) *TmIpSpace { return &g } -// CreateTmIpSpace with a given configuration +// CreateTmIpSpace creates a TM IP Space with a given configuration func (vcdClient *VCDClient) CreateTmIpSpace(config *types.TmIpSpace) (*TmIpSpace, error) { c := crudConfig{ entityLabel: labelTmIpSpace, From bdd97df2d1bf2939dd1abc8411ae8e9222916785 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 3 Dec 2024 16:12:45 +0200 Subject: [PATCH 12/21] WIP6 Signed-off-by: Dainius Serplis --- govcd/tm_provider_gateway_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index 4f09c346e..f2b0f82a7 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -56,7 +56,8 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { }}, } - createdProviderGateway, err := vcd.client.CreateTmProviderGateway(t) + _, err = vcd.client.CreateTmProviderGateway(t) + panic(err) } From 8b98a628a20006de99e88a00c3a91b7559e3a96b Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Wed, 4 Dec 2024 10:21:43 +0200 Subject: [PATCH 13/21] Remove workaround for CLI upload and patch changelog Signed-off-by: Dainius Serplis --- .changes/v3.0.0/717-features.md | 2 +- govcd/tm_content_library_item.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changes/v3.0.0/717-features.md b/.changes/v3.0.0/717-features.md index e031bb2c5..44f15f201 100644 --- a/.changes/v3.0.0/717-features.md +++ b/.changes/v3.0.0/717-features.md @@ -1,4 +1,4 @@ * Added `ContentLibraryItem` and `types.ContentLibraryItem` structures to manage Content Library Items with methods `ContentLibrary.CreateContentLibraryItem`, `ContentLibrary.GetAllContentLibraryItems`, `ContentLibrary.GetContentLibraryItemByName`, `ContentLibrary.GetContentLibraryItemById`, `ContentLibraryItem.Update`, - `ContentLibraryItem.Delete`, `VCDClient.GetContentLibraryItemById` [GH-717] + `ContentLibraryItem.Delete`, `VCDClient.GetContentLibraryItemById` [GH-717, GH-724] diff --git a/govcd/tm_content_library_item.go b/govcd/tm_content_library_item.go index 115622402..878dfe3a4 100644 --- a/govcd/tm_content_library_item.go +++ b/govcd/tm_content_library_item.go @@ -235,7 +235,7 @@ func uploadContentLibraryItemFile(name string, cli *ContentLibraryItem, filesToU }() ud := uploadDetails{ - uploadLink: strings.ReplaceAll(fileToUpload.TransferUrl, "/transfer", "/tm/transfer"), // TODO: TM: Workaround, the link is missing /tm in path, so it gives 404 as-is + uploadLink: fileToUpload.TransferUrl, uploadedBytes: 0, fileSizeToUpload: fileToUpload.ExpectedSizeBytes, uploadPieceSize: args.UploadPieceSize, From 08e00d08f355194f49d62d39ef868bc2e464ae4b Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Wed, 4 Dec 2024 16:05:36 +0200 Subject: [PATCH 14/21] Adjust types Signed-off-by: Dainius Serplis --- govcd/tm_provider_gateway.go | 22 ---------------------- govcd/tm_provider_gateway_test.go | 27 +++------------------------ govcd/tm_tier0_gateway.go | 4 ---- types/v56/tm.go | 16 ++++++++-------- 4 files changed, 11 insertions(+), 58 deletions(-) diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index c4471db4e..66b8a4590 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -7,28 +7,6 @@ import ( "github.com/vmware/go-vcloud-director/v3/types/v56" ) -// This is a template of how a "standard" outer entity implementation can be done when using generic -// functions. It might not cover all scenarios, but is a skeleton for quicker bootstraping of a new -// entity. -// -// "Search and replace the following entries" -// -// TmProviderGateway - outer type (e.g. IpSpace2) -// This should be a non existing new type to create in 'govcd' package -// -// types.TmProviderGateway - inner type (e.g. types.IpSpace) -// This should be an already existing inner type in `types` package -// -// TM Provider Gateway - constant name for entity label (the lower case prefix 'label' prefix is hardcoded) -// The 'label' prefix is hardcoded in the example so that we have autocompletion working for all labelXXXX. (e.g. IpSpace2) -// -// TM Provider Gateway - text for entity label (e.g. Ip Space 2) -// This will be the entity label (used for logging purposes in generic functions) -// -// types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways (e.g. types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces) -// An OpenAPI endpoint that is defined in `endpointMinApiVersions` map and in `constants.go` -// NOTE. While this example REPLACES ALL ENDPOINTS to be THE SAME, in reality they can be DIFFERENT - const labelTmProviderGateway = "TM Provider Gateway" type TmProviderGateway struct { diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index f2b0f82a7..e0ac6e78d 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -49,9 +49,9 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { Name: check.TestName(), Description: check.TestName(), BackingType: "NSX_TIER0", - BackingRef: &types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, - RegionRef: &types.OpenApiReference{ID: region.Region.ID}, - IPSpaceRefs: []*types.OpenApiReference{{ + BackingRef: types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, + RegionRef: types.OpenApiReference{ID: region.Region.ID}, + IPSpaceRefs: []types.OpenApiReference{{ ID: ipSpace.TmIpSpace.ID, }}, } @@ -60,24 +60,3 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { panic(err) } - -// { -// "name": "test-provider-gw", -// "description": "", -// "orgRef": null, -// "backingRef": { -// "id": "37273049-ecda-4974-baf6-5c107f30a969", -// "name": "vcfcons-mgt-vc03-Tier0" -// }, -// "backingType": "NSX_TIER0", -// "regionRef": { -// "id": "urn:vcloud:region:7544b246-84c6-40ad-8c3b-beed9fe145cd", -// "name": "Terraform demo Region" -// }, -// "ipSpaceRefs": [ -// { -// "id": "urn:vcloud:ipSpace:feb3d26d-08e7-4e3f-90cc-f54f13a45697", -// "name": "demo-ip-space" -// } -// ] -// } diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go index 9a0cac27d..8bbdc2009 100644 --- a/govcd/tm_tier0_gateway.go +++ b/govcd/tm_tier0_gateway.go @@ -7,10 +7,6 @@ import ( "github.com/vmware/go-vcloud-director/v3/types/v56" ) -// Sample query -// https://vcfa.10.162.145.191.vcfd.broadcom.net/tm/cloudapi/1.0.0/nsxTResources/importableTier0Routers -// ?page=1&pageSize=128&filterEncoded=true&filter=(alreadyImported==false;_context==urn:vcloud:region:7544b246-84c6-40ad-8c3b-beed9fe145cd)&links=true - const labelTmTier0Gateway = "TM Tier0 Gateway" type TmTier0Gateway struct { diff --git a/types/v56/tm.go b/types/v56/tm.go index 991adf6f0..e5105f6ed 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -362,12 +362,12 @@ type TmTier0Gateway struct { } type TmProviderGateway struct { - ID string `json:"id,omitempty"` - Name string `json:"name"` - Description string `json:"description,omitempty"` - OrgRef *OpenApiReference `json:"orgRef,omitempty"` - BackingRef *OpenApiReference `json:"backingRef,omitempty"` - BackingType string `json:"backingType,omitempty"` - RegionRef *OpenApiReference `json:"regionRef,omitempty"` - IPSpaceRefs []*OpenApiReference `json:"ipSpaceRefs,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + OrgRef *OpenApiReference `json:"orgRef,omitempty"` + BackingRef OpenApiReference `json:"backingRef,omitempty"` + BackingType string `json:"backingType,omitempty"` + RegionRef OpenApiReference `json:"regionRef,omitempty"` + IPSpaceRefs []OpenApiReference `json:"ipSpaceRefs,omitempty"` } From 79ecfc34f82ad4ca454a21a91444500cc7b80b3f Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 9 Dec 2024 09:15:22 +0200 Subject: [PATCH 15/21] WIP Signed-off-by: Dainius Serplis --- govcd/openapi_endpoints.go | 1 + govcd/tm_ip_space_associations.go | 85 +++++++++++++++++++++++++++++++ govcd/tm_provider_gateway.go | 2 +- govcd/tm_provider_gateway_test.go | 45 ++++++++++++++-- types/v56/constants.go | 1 + types/v56/tm.go | 22 ++++++++ 6 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 govcd/tm_ip_space_associations.go diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index dd2bddebd..42526db70 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -169,6 +169,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVcf + types.OpenApiEndpointTmVdcs: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaces: "40.0", types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways: "40.0", + types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations: "40.0", } // endpointElevatedApiVersions endpoint elevated API versions diff --git a/govcd/tm_ip_space_associations.go b/govcd/tm_ip_space_associations.go new file mode 100644 index 000000000..31e67cde9 --- /dev/null +++ b/govcd/tm_ip_space_associations.go @@ -0,0 +1,85 @@ +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v3/types/v56" +) + +const labelTmIpSpaceAssociation = "TM IP Space Association" + +type TmIpSpaceAssociation struct { + TmIpSpaceAssociation *types.TmIpSpaceAssociation + vcdClient *VCDClient +} + +// wrap is a hidden helper that facilitates the usage of a generic CRUD function +// +//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck +func (g TmIpSpaceAssociation) wrap(inner *types.TmIpSpaceAssociation) *TmIpSpaceAssociation { + g.TmIpSpaceAssociation = inner + return &g +} + +func (vcdClient *VCDClient) CreateTmIpSpaceAssociation(config *types.TmIpSpaceAssociation) (*TmIpSpaceAssociation, error) { + c := crudConfig{ + entityLabel: labelTmIpSpaceAssociation, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, + } + outerType := TmIpSpaceAssociation{vcdClient: vcdClient} + return createOuterEntity(&vcdClient.Client, outerType, c, config) +} + +func (vcdClient *VCDClient) GetAllTmIpSpaceAssociations(queryParameters url.Values) ([]*TmIpSpaceAssociation, error) { + c := crudConfig{ + entityLabel: labelTmIpSpaceAssociation, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, + queryParameters: queryParameters, + } + + outerType := TmIpSpaceAssociation{vcdClient: vcdClient} + return getAllOuterEntities(&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetTmIpSpaceAssociationById(id string) (*TmIpSpaceAssociation, error) { + c := crudConfig{ + entityLabel: labelTmIpSpaceAssociation, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, + endpointParams: []string{id}, + } + + outerType := TmIpSpaceAssociation{vcdClient: vcdClient} + return getOuterEntity(&vcdClient.Client, outerType, c) +} + +func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(providerGatewayId string) ([]*TmProviderGateway, error) { + if providerGatewayId == "" { + return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) + } + + queryParams := url.Values{} + queryParams = queryParameterFilterAnd("providerGatewayRef.id=="+providerGatewayId, queryParams) + + return vcdClient.GetAllTmProviderGateways(queryParams) +} + +func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpaceId string) ([]*TmProviderGateway, error) { + if ipSpaceId == "" { + return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) + } + + queryParams := url.Values{} + queryParams = queryParameterFilterAnd("ipSpaceRef.id=="+ipSpaceId, queryParams) + + return vcdClient.GetAllTmProviderGateways(queryParams) +} + +func (o *TmIpSpaceAssociation) Delete() error { + c := crudConfig{ + entityLabel: labelTmIpSpaceAssociation, + endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, + endpointParams: []string{o.TmIpSpaceAssociation.ID}, + } + return deleteEntityById(&o.vcdClient.Client, c) +} diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index 66b8a4590..30ce6f552 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -71,7 +71,7 @@ func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGate } outerType := TmProviderGateway{vcdClient: vcdClient} - return getOuterEntity[TmProviderGateway, types.TmProviderGateway](&vcdClient.Client, outerType, c) + return getOuterEntity(&vcdClient.Client, outerType, c) } func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId string) (*TmProviderGateway, error) { diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index e0ac6e78d..27e7e2f88 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -48,7 +48,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { t := &types.TmProviderGateway{ Name: check.TestName(), Description: check.TestName(), - BackingType: "NSX_TIER0", + BackingType: "NSX_TIER0", // TODO TODO - does it support T0 VRF? BackingRef: types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, RegionRef: types.OpenApiReference{ID: region.Region.ID}, IPSpaceRefs: []types.OpenApiReference{{ @@ -56,7 +56,46 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { }}, } - _, err = vcd.client.CreateTmProviderGateway(t) - panic(err) + createdTmProviderGateway, err := vcd.client.CreateTmProviderGateway(t) + check.Assert(err, IsNil) + AddToCleanupListOpenApi(createdTmProviderGateway.TmProviderGateway.Name, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointTmProviderGateways+createdTmProviderGateway.TmProviderGateway.ID) + defer func() { + err = createdTmProviderGateway.Delete() + check.Assert(err, IsNil) + }() + + // Get TM VDC By Name + byName, err := vcd.client.GetTmProviderGatewayByName(t.Name) + check.Assert(err, IsNil) + check.Assert(byName.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) + + // Get TM VDC By Id + byId, err := vcd.client.GetTmProviderGatewayById(createdTmProviderGateway.TmProviderGateway.ID) + check.Assert(err, IsNil) + check.Assert(byId.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) + + // Not Found tests + byNameInvalid, err := vcd.client.GetTmProviderGatewayByName("fake-name") + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(byNameInvalid, IsNil) + + byIdInvalid, err := vcd.client.GetTmProviderGatewayById("urn:vcloud:providerGateway:5344b964-0000-0000-0000-d554913db643") + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(byIdInvalid, IsNil) + + // Update (IPSpaceRefs can only be managed using 'TmIpSpaceAssociation' after initial creation) + createdTmProviderGateway.TmProviderGateway.Name = check.TestName() + "-update" + updatedVdc, err := createdTmProviderGateway.Update(createdTmProviderGateway.TmProviderGateway) + check.Assert(err, IsNil) + check.Assert(updatedVdc.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) + + // IP Space Association management testing + associationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) + check.Assert(err, IsNil) + check.Assert(len(associationByProviderGateway) == 1, Equals, true) + + associationByIpSpace, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace.TmIpSpace.ID) + check.Assert(err, IsNil) + check.Assert(len(associationByIpSpace) == 1, Equals, true) } diff --git a/types/v56/constants.go b/types/v56/constants.go index 4d404645b..bb10f9af5 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -532,6 +532,7 @@ const ( OpenApiEndpointTmVdcs = "virtualDatacenters/" OpenApiEndpointTmIpSpaces = "ipSpaces/" OpenApiEndpointTmProviderGateways = "providerGateways/" + OpenApiEndpointTmIpSpaceAssociations = "ipSpaceAssociations/" ) // Header keys to run operations in tenant context diff --git a/types/v56/tm.go b/types/v56/tm.go index e5105f6ed..1377edc82 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -370,4 +370,26 @@ type TmProviderGateway struct { BackingType string `json:"backingType,omitempty"` RegionRef OpenApiReference `json:"regionRef,omitempty"` IPSpaceRefs []OpenApiReference `json:"ipSpaceRefs,omitempty"` + // Represents current status of the networking entity. Possible values are: + // * PENDING - Desired entity configuration has been received by system and is pending realization. + // * CONFIGURING - The system is in process of realizing the entity. + // * REALIZED - The entity is successfully realized in the system. + // * REALIZATION_FAILED - There are some issues and the system is not able to realize the entity. + // * UNKNOWN - Current state of entity is unknown. + Status string `json:"status,omitempty"` +} + +type TmIpSpaceAssociation struct { + ID string `json:"id,omitempty"` + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + IPSpaceRef *OpenApiReference `json:"ipSpaceRef,omitempty"` + ProviderGatewayRef *OpenApiReference `json:"providerGatewayRef,omitempty"` + // Represents current status of the networking entity. Possible values are: + // * PENDING - Desired entity configuration has been received by system and is pending realization. + // * CONFIGURING - The system is in process of realizing the entity. + // * REALIZED - The entity is successfully realized in the system. + // * REALIZATION_FAILED - There are some issues and the system is not able to realize the entity. + // * UNKNOWN - Current state of entity is unknown. + Status string `json:"status,omitempty"` } From fd522bdf5699481f9590337ff46d0dbe22c15416 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Mon, 9 Dec 2024 15:13:07 +0200 Subject: [PATCH 16/21] WIP Signed-off-by: Dainius Serplis --- govcd/tm_common_test.go | 9 ++--- govcd/tm_ip_space_associations.go | 9 +++-- govcd/tm_provider_gateway.go | 5 +++ govcd/tm_provider_gateway_test.go | 57 +++++++++++++++++++++++++++---- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/govcd/tm_common_test.go b/govcd/tm_common_test.go index c017f0d71..431e60c4a 100644 --- a/govcd/tm_common_test.go +++ b/govcd/tm_common_test.go @@ -7,6 +7,7 @@ package govcd import ( + "fmt" "net/url" "time" @@ -236,9 +237,9 @@ func createOrg(vcd *TestVCD, check *C, canManageOrgs bool) (*TmOrg, func()) { } } -func createTmIpSpace(vcd *TestVCD, region *Region, check *C) (*TmIpSpace, func()) { +func createTmIpSpace(vcd *TestVCD, region *Region, check *C, nameSuffix, octet3 string) (*TmIpSpace, func()) { ipSpaceType := &types.TmIpSpace{ - Name: check.TestName(), + Name: check.TestName() + "-" + nameSuffix, RegionRef: types.OpenApiReference{ID: region.Region.ID}, Description: check.TestName(), DefaultQuota: types.TmIpSpaceDefaultQuota{ @@ -246,10 +247,10 @@ func createTmIpSpace(vcd *TestVCD, region *Region, check *C) (*TmIpSpace, func() MaxIPCount: -1, MaxSubnetSize: 24, }, - ExternalScopeCidr: "12.12.0.0/30", + ExternalScopeCidr: fmt.Sprintf("12.12.%s.0/30", octet3), InternalScopeCidrBlocks: []types.TmIpSpaceInternalScopeCidrBlocks{ { - Cidr: "10.0.0.0/24", + Cidr: fmt.Sprintf("10.0.%s.0/24", octet3), }, }, } diff --git a/govcd/tm_ip_space_associations.go b/govcd/tm_ip_space_associations.go index 31e67cde9..abc54d711 100644 --- a/govcd/tm_ip_space_associations.go +++ b/govcd/tm_ip_space_associations.go @@ -53,7 +53,7 @@ func (vcdClient *VCDClient) GetTmIpSpaceAssociationById(id string) (*TmIpSpaceAs return getOuterEntity(&vcdClient.Client, outerType, c) } -func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(providerGatewayId string) ([]*TmProviderGateway, error) { +func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(providerGatewayId string) ([]*TmIpSpaceAssociation, error) { if providerGatewayId == "" { return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) } @@ -61,18 +61,17 @@ func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(provi queryParams := url.Values{} queryParams = queryParameterFilterAnd("providerGatewayRef.id=="+providerGatewayId, queryParams) - return vcdClient.GetAllTmProviderGateways(queryParams) + return vcdClient.GetAllTmIpSpaceAssociations(queryParams) } -func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpaceId string) ([]*TmProviderGateway, error) { +func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpaceId string) ([]*TmIpSpaceAssociation, error) { if ipSpaceId == "" { return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) } queryParams := url.Values{} queryParams = queryParameterFilterAnd("ipSpaceRef.id=="+ipSpaceId, queryParams) - - return vcdClient.GetAllTmProviderGateways(queryParams) + return vcdClient.GetAllTmIpSpaceAssociations(queryParams) } func (o *TmIpSpaceAssociation) Delete() error { diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index 30ce6f552..b142cf131 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -9,6 +9,11 @@ import ( const labelTmProviderGateway = "TM Provider Gateway" +// TmProviderGateway manages Provider Gateway creation and configuration. +// +// NOTE. While creation of Provider Gateway requires at least one IP Space (`TmIpSpace`) reference, +// they are not being returned by API after creation. One must use `TmIpSpaceAssociation` for +// managing IP Space associations with Provider gateways after the initial creation is done. type TmProviderGateway struct { TmProviderGateway *types.TmProviderGateway vcdClient *VCDClient diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index 27e7e2f88..914873c31 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -24,8 +24,11 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { region, regionCleanup := getOrCreateRegion(vcd, nsxtManager, supervisor, check) defer regionCleanup() - ipSpace, ipSpaceCleanup := createTmIpSpace(vcd, region, check) - defer ipSpaceCleanup() + ipSpace1, ipSpaceCleanup1 := createTmIpSpace(vcd, region, check, "1", "0") + defer ipSpaceCleanup1() + + ipSpace2, ipSpaceCleanup2 := createTmIpSpace(vcd, region, check, "2", "1") + defer ipSpaceCleanup2() // Performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests allT0sWithContextFilter, err := vcd.client.GetAllTmTier0GatewaysWithContext(region.Region.ID, true) @@ -44,7 +47,6 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { // End of performing TM Tier 0 Gateway lookups to save time on prerequisites in separate tests // Provider Gateway - t := &types.TmProviderGateway{ Name: check.TestName(), Description: check.TestName(), @@ -52,7 +54,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { BackingRef: types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, RegionRef: types.OpenApiReference{ID: region.Region.ID}, IPSpaceRefs: []types.OpenApiReference{{ - ID: ipSpace.TmIpSpace.ID, + ID: ipSpace1.TmIpSpace.ID, }}, } @@ -90,12 +92,55 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { check.Assert(updatedVdc.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) // IP Space Association management testing + + // Retrieve existing associationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) check.Assert(err, IsNil) check.Assert(len(associationByProviderGateway) == 1, Equals, true) - associationByIpSpace, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace.TmIpSpace.ID) + associationByIpSpace1, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace1.TmIpSpace.ID) + check.Assert(err, IsNil) + check.Assert(len(associationByIpSpace1) == 1, Equals, true) + + // Attempt to find an association that does not exist + associationByIpSpace2, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace2.TmIpSpace.ID) + check.Assert(err, IsNil) + check.Assert(associationByIpSpace2, NotNil) + + // Create new IP Space Association + ipSpaceAssociationCfg := &types.TmIpSpaceAssociation{ + Name: "one", + IPSpaceRef: &types.OpenApiReference{ID: ipSpace2.TmIpSpace.ID}, + ProviderGatewayRef: &types.OpenApiReference{ID: createdTmProviderGateway.TmProviderGateway.ID}, + } + newAssociation, err := vcd.client.CreateTmIpSpaceAssociation(ipSpaceAssociationCfg) + check.Assert(err, IsNil) + AddToCleanupListOpenApi(newAssociation.TmIpSpaceAssociation.Name, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointTmIpSpaceAssociations+newAssociation.TmIpSpaceAssociation.ID) + defer func() { + err = newAssociation.Delete() + check.Assert(err, IsNil) + }() + + // Check new association numbers in Provider Gateway + updatedAssociationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) + check.Assert(err, IsNil) + check.Assert(len(updatedAssociationByProviderGateway) == 2, Equals, true) + + newAssociationByIpSpace2, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace2.TmIpSpace.ID) check.Assert(err, IsNil) - check.Assert(len(associationByIpSpace) == 1, Equals, true) + check.Assert(len(newAssociationByIpSpace2) == 1, Equals, true) + // Get Association by ID + associationById, err := vcd.client.GetTmIpSpaceAssociationById(newAssociationByIpSpace2[0].TmIpSpaceAssociation.ID) + check.Assert(err, IsNil) + check.Assert(associationById.TmIpSpaceAssociation, DeepEquals, newAssociationByIpSpace2[0].TmIpSpaceAssociation) + + // Delete Association + err = newAssociationByIpSpace2[0].Delete() + check.Assert(err, IsNil) + + // Double check Gateway Association count (should remain 1 again) + postDeleteAssociationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) + check.Assert(err, IsNil) + check.Assert(len(postDeleteAssociationByProviderGateway) == 1, Equals, true) } From 56f0630c06ae2c4759d0b8ee83a3eda3c5ee80d2 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Tue, 10 Dec 2024 11:56:07 +0200 Subject: [PATCH 17/21] Self review Signed-off-by: Dainius Serplis --- govcd/api_vcd_test.go | 3 +-- govcd/tm_ip_space_associations.go | 10 +++++++++ govcd/tm_provider_gateway.go | 31 ++++++++++++++++++++++++++- govcd/tm_provider_gateway_test.go | 13 ++++++------ govcd/tm_tier0_gateway.go | 1 + types/v56/tm.go | 35 ++++++++++++++++++++----------- 6 files changed, 72 insertions(+), 21 deletions(-) diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index d58189eb0..c82451c6d 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -160,8 +160,7 @@ type TestConfig struct { NsxtManagerUsername string `yaml:"nsxtManagerUsername"` NsxtManagerPassword string `yaml:"nsxtManagerPassword"` NsxtManagerUrl string `yaml:"nsxtManagerUrl"` - - NsxtTier0Gateway string `yaml:"nsxtTier0Gateway"` + NsxtTier0Gateway string `yaml:"nsxtTier0Gateway"` } `yaml:"tm,omitempty"` VCD struct { Org string `yaml:"org"` diff --git a/govcd/tm_ip_space_associations.go b/govcd/tm_ip_space_associations.go index abc54d711..2a9816119 100644 --- a/govcd/tm_ip_space_associations.go +++ b/govcd/tm_ip_space_associations.go @@ -9,6 +9,9 @@ import ( const labelTmIpSpaceAssociation = "TM IP Space Association" +// TmIpSpaceAssociation manages associations between Provider Gateways and IP Spaces. Each +// association results in a separate entity. The first association is created automatically when +// a Provider Gateway (`TmProviderGateway`) is created. type TmIpSpaceAssociation struct { TmIpSpaceAssociation *types.TmIpSpaceAssociation vcdClient *VCDClient @@ -22,6 +25,7 @@ func (g TmIpSpaceAssociation) wrap(inner *types.TmIpSpaceAssociation) *TmIpSpace return &g } +// Creates TM IP Space Association with Provider Gateway func (vcdClient *VCDClient) CreateTmIpSpaceAssociation(config *types.TmIpSpaceAssociation) (*TmIpSpaceAssociation, error) { c := crudConfig{ entityLabel: labelTmIpSpaceAssociation, @@ -31,6 +35,7 @@ func (vcdClient *VCDClient) CreateTmIpSpaceAssociation(config *types.TmIpSpaceAs return createOuterEntity(&vcdClient.Client, outerType, c, config) } +// GetAllTmIpSpaceAssociations retrieves all TM IP Space and Provider Gateway associations func (vcdClient *VCDClient) GetAllTmIpSpaceAssociations(queryParameters url.Values) ([]*TmIpSpaceAssociation, error) { c := crudConfig{ entityLabel: labelTmIpSpaceAssociation, @@ -42,6 +47,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaceAssociations(queryParameters url.Valu return getAllOuterEntities(&vcdClient.Client, outerType, c) } +// GetTmIpSpaceAssociationById retrieves a single IP Spaces and Provider Gateway association by ID func (vcdClient *VCDClient) GetTmIpSpaceAssociationById(id string) (*TmIpSpaceAssociation, error) { c := crudConfig{ entityLabel: labelTmIpSpaceAssociation, @@ -53,6 +59,8 @@ func (vcdClient *VCDClient) GetTmIpSpaceAssociationById(id string) (*TmIpSpaceAs return getOuterEntity(&vcdClient.Client, outerType, c) } +// GetAllTmIpSpaceAssociationsByProviderGatewayId retrieves all IP Space associations to a +// particulat Provider Gateway func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(providerGatewayId string) ([]*TmIpSpaceAssociation, error) { if providerGatewayId == "" { return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) @@ -64,6 +72,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByProviderGatewayId(provi return vcdClient.GetAllTmIpSpaceAssociations(queryParams) } +// GetAllTmIpSpaceAssociationsByIpSpaceId retrieves all associations for a given IP Space ID func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpaceId string) ([]*TmIpSpaceAssociation, error) { if ipSpaceId == "" { return nil, fmt.Errorf("%s lookup requires %s ID", labelTmIpSpaceAssociation, labelTmProviderGateway) @@ -74,6 +83,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpaceId str return vcdClient.GetAllTmIpSpaceAssociations(queryParams) } +// Delete the association func (o *TmIpSpaceAssociation) Delete() error { c := crudConfig{ entityLabel: labelTmIpSpaceAssociation, diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index b142cf131..dfd8bd04e 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -27,6 +27,7 @@ func (g TmProviderGateway) wrap(inner *types.TmProviderGateway) *TmProviderGatew return &g } +// Creates TM Provider Gateway with provided configuration func (vcdClient *VCDClient) CreateTmProviderGateway(config *types.TmProviderGateway) (*TmProviderGateway, error) { c := crudConfig{ entityLabel: labelTmProviderGateway, @@ -36,6 +37,7 @@ func (vcdClient *VCDClient) CreateTmProviderGateway(config *types.TmProviderGate return createOuterEntity(&vcdClient.Client, outerType, c, config) } +// GetAllTmProviderGateways retrieves all Provider Gateways with optional filter func (vcdClient *VCDClient) GetAllTmProviderGateways(queryParameters url.Values) ([]*TmProviderGateway, error) { c := crudConfig{ entityLabel: labelTmProviderGateway, @@ -47,6 +49,7 @@ func (vcdClient *VCDClient) GetAllTmProviderGateways(queryParameters url.Values) return getAllOuterEntities(&vcdClient.Client, outerType, c) } +// GetTmProviderGatewayByName retrieves Provider Gateway by Name func (vcdClient *VCDClient) GetTmProviderGatewayByName(name string) (*TmProviderGateway, error) { if name == "" { return nil, fmt.Errorf("%s lookup requires name", labelTmProviderGateway) @@ -68,6 +71,7 @@ func (vcdClient *VCDClient) GetTmProviderGatewayByName(name string) (*TmProvider return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) } +// GetTmProviderGatewayById retrieves a given Provider Gateway by ID func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGateway, error) { c := crudConfig{ entityLabel: labelTmProviderGateway, @@ -79,7 +83,7 @@ func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGate return getOuterEntity(&vcdClient.Client, outerType, c) } -func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId string) (*TmProviderGateway, error) { +/* func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId string) (*TmProviderGateway, error) { if name == "" || orgId == "" { return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmProviderGateway) } @@ -98,9 +102,33 @@ func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId strin return nil, err } + return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) +} */ + +// GetTmProviderGatewayByNameAndRegionId retrieves Provider Gateway by name in a given Region +func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndRegionId(name, regionId string) (*TmProviderGateway, error) { + if name == "" || regionId == "" { + return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmProviderGateway) + } + + queryParams := url.Values{} + queryParams.Add("filter", "name=="+name) + queryParams = queryParameterFilterAnd("regionRef.id=="+regionId, queryParams) + + filteredEntities, err := vcdClient.GetAllTmProviderGateways(queryParams) + if err != nil { + return nil, err + } + + singleEntity, err := oneOrError("name", name, filteredEntities) + if err != nil { + return nil, err + } + return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) } +// Update existing Provider Gateway func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.TmProviderGateway) (*TmProviderGateway, error) { c := crudConfig{ entityLabel: labelTmProviderGateway, @@ -111,6 +139,7 @@ func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.TmProviderGate return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmProviderGatewayConfig) } +// Delete Provider Gateway func (o *TmProviderGateway) Delete() error { c := crudConfig{ entityLabel: labelTmProviderGateway, diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index 914873c31..765042f62 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -66,12 +66,17 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { check.Assert(err, IsNil) }() - // Get TM VDC By Name + // Get TM Provider Gateway By Name byName, err := vcd.client.GetTmProviderGatewayByName(t.Name) check.Assert(err, IsNil) check.Assert(byName.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) - // Get TM VDC By Id + // Get TM Provider Gateway By Name and Region ID + byNameAndRegionId, err := vcd.client.GetTmProviderGatewayByNameAndRegionId(t.Name, region.Region.ID) + check.Assert(err, IsNil) + check.Assert(byNameAndRegionId.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) + + // Get TM Provider Gateway By Id byId, err := vcd.client.GetTmProviderGatewayById(createdTmProviderGateway.TmProviderGateway.ID) check.Assert(err, IsNil) check.Assert(byId.TmProviderGateway, DeepEquals, createdTmProviderGateway.TmProviderGateway) @@ -116,10 +121,6 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { newAssociation, err := vcd.client.CreateTmIpSpaceAssociation(ipSpaceAssociationCfg) check.Assert(err, IsNil) AddToCleanupListOpenApi(newAssociation.TmIpSpaceAssociation.Name, check.TestName(), types.OpenApiPathVcf+types.OpenApiEndpointTmIpSpaceAssociations+newAssociation.TmIpSpaceAssociation.ID) - defer func() { - err = newAssociation.Delete() - check.Assert(err, IsNil) - }() // Check new association numbers in Provider Gateway updatedAssociationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go index 8bbdc2009..e0aad8081 100644 --- a/govcd/tm_tier0_gateway.go +++ b/govcd/tm_tier0_gateway.go @@ -9,6 +9,7 @@ import ( const labelTmTier0Gateway = "TM Tier0 Gateway" +// TmTier0Gateway is a structure for reading TM Tier0 Gateways that originate from NSX-T type TmTier0Gateway struct { TmTier0Gateway *types.TmTier0Gateway vcdClient *VCDClient diff --git a/types/v56/tm.go b/types/v56/tm.go index 1377edc82..9b01fc33b 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -353,22 +353,32 @@ type TmIpSpaceInternalScopeCidrBlocks struct { Cidr string `json:"cidr,omitempty"` } +// TmTier0Gateway represents NSX-T Tier-0 Gateway that are available for consumption in TM type TmTier0Gateway struct { - ID string `json:"id"` - Description string `json:"description"` - DisplayName string `json:"displayName"` - ParentTier0ID string `json:"parentTier0Id"` - AlreadyImported bool `json:"alreadyImported"` + ID string `json:"id"` + Description string `json:"description"` + DisplayName string `json:"displayName"` + // ParentTier0ID in case this is a Tier 0 Gateway VRF + ParentTier0ID string `json:"parentTier0Id"` + // AlreadyImported displays if the Tier 0 Gateway is already consumed by TM + AlreadyImported bool `json:"alreadyImported"` } +// TmProviderGateway reflects a TM Provider Gateway that is a mapping of type TmProviderGateway struct { - ID string `json:"id,omitempty"` - Name string `json:"name"` - Description string `json:"description,omitempty"` - OrgRef *OpenApiReference `json:"orgRef,omitempty"` - BackingRef OpenApiReference `json:"backingRef,omitempty"` - BackingType string `json:"backingType,omitempty"` - RegionRef OpenApiReference `json:"regionRef,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + // OrgRef contains a reference to Org + OrgRef *OpenApiReference `json:"orgRef,omitempty"` + BackingRef OpenApiReference `json:"backingRef,omitempty"` + // BackingType - NSX_TIER0 + BackingType string `json:"backingType,omitempty"` + // RegionRef contains Region reference + RegionRef OpenApiReference `json:"regionRef,omitempty"` + // IPSpaceRefs - a list of IP Space references to create associations with. + // NOTE. It is used _only_ for creation. Reading will return it empty, and update will not work + // - one must use `TmIpSpaceAssociation` to update IP Space associations with Provider Gateway IPSpaceRefs []OpenApiReference `json:"ipSpaceRefs,omitempty"` // Represents current status of the networking entity. Possible values are: // * PENDING - Desired entity configuration has been received by system and is pending realization. @@ -379,6 +389,7 @@ type TmProviderGateway struct { Status string `json:"status,omitempty"` } +// TmIpSpaceAssociation manages IP Space and Provider Gateway associations type TmIpSpaceAssociation struct { ID string `json:"id,omitempty"` Description string `json:"description,omitempty"` From 970662ef45e1df0129b7a8b8da3be0fc403e0495 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Fri, 13 Dec 2024 09:22:16 +0200 Subject: [PATCH 18/21] Changelog and cleanup Signed-off-by: Dainius Serplis --- .changes/v3.0.0/725-features.md | 14 ++++++++++++++ govcd/tm_provider_gateway.go | 22 ---------------------- 2 files changed, 14 insertions(+), 22 deletions(-) create mode 100644 .changes/v3.0.0/725-features.md diff --git a/.changes/v3.0.0/725-features.md b/.changes/v3.0.0/725-features.md new file mode 100644 index 000000000..72a51857b --- /dev/null +++ b/.changes/v3.0.0/725-features.md @@ -0,0 +1,14 @@ +* Added `TmProviderGateway` and `types.TmProviderGateway` structures and methods + `VCDClient.CreateTmProviderGateway`, `VCDClient.GetAllTmProviderGateways`, + `VCDClient.GetTmProviderGatewayByName`, `VCDClient.GetTmProviderGatewayById`, + `VCDClient.GetTmProviderGatewayByNameAndRegionId`, `TmProviderGateway.Update`, + `TmProviderGateway.Delete` to manage Provider Gateways [GH-725] +* Added `TmTier0Gateway` and `types.TmTier0Gateway` structures consumption and methods + `VCDClient.GetAllTmTier0GatewaysWithContext`, `VCDClient.GetTmTier0GatewayWithContextByName` to + read Tier 0 Gateways that are available for TM consumption [GH-725] +* Added `TmIpSpaceAssociation` and `types.TmIpSpaceAssociation` structures and methods + `VCDClient.CreateTmIpSpaceAssociation`, `VCDClient.GetAllTmIpSpaceAssociations`, + `VCDClient.GetTmIpSpaceAssociationById`, + `VCDClient.GetAllTmIpSpaceAssociationsByProviderGatewayId`, + `VCDClient.GetAllTmIpSpaceAssociationsByIpSpaceId`, `TmIpSpaceAssociation.Delete` to manage IP + Space associations with Provider Gateways [GH-725] diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index dfd8bd04e..b39726ba3 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -83,28 +83,6 @@ func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGate return getOuterEntity(&vcdClient.Client, outerType, c) } -/* func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndOrgId(name, orgId string) (*TmProviderGateway, error) { - if name == "" || orgId == "" { - return nil, fmt.Errorf("%s lookup requires name and Org ID", labelTmProviderGateway) - } - - queryParams := url.Values{} - queryParams.Add("filter", "name=="+name) - queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams) - - filteredEntities, err := vcdClient.GetAllTmProviderGateways(queryParams) - if err != nil { - return nil, err - } - - singleEntity, err := oneOrError("name", name, filteredEntities) - if err != nil { - return nil, err - } - - return vcdClient.GetTmProviderGatewayById(singleEntity.TmProviderGateway.ID) -} */ - // GetTmProviderGatewayByNameAndRegionId retrieves Provider Gateway by name in a given Region func (vcdClient *VCDClient) GetTmProviderGatewayByNameAndRegionId(name, regionId string) (*TmProviderGateway, error) { if name == "" || regionId == "" { From 618b9f59d43fbf99afb82f1e9484320cd4ee0c6a Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Fri, 13 Dec 2024 10:37:52 +0200 Subject: [PATCH 19/21] Self review Signed-off-by: Dainius Serplis --- .changes/v3.0.0/725-features.md | 2 +- govcd/tm_ip_space_associations.go | 4 ++-- govcd/tm_provider_gateway.go | 2 +- govcd/tm_provider_gateway_test.go | 7 ++++--- types/v56/tm.go | 15 +++++++++------ 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.changes/v3.0.0/725-features.md b/.changes/v3.0.0/725-features.md index 72a51857b..9349cee6a 100644 --- a/.changes/v3.0.0/725-features.md +++ b/.changes/v3.0.0/725-features.md @@ -3,7 +3,7 @@ `VCDClient.GetTmProviderGatewayByName`, `VCDClient.GetTmProviderGatewayById`, `VCDClient.GetTmProviderGatewayByNameAndRegionId`, `TmProviderGateway.Update`, `TmProviderGateway.Delete` to manage Provider Gateways [GH-725] -* Added `TmTier0Gateway` and `types.TmTier0Gateway` structures consumption and methods +* Added `TmTier0Gateway` and `types.TmTier0Gateway` structures and methods `VCDClient.GetAllTmTier0GatewaysWithContext`, `VCDClient.GetTmTier0GatewayWithContextByName` to read Tier 0 Gateways that are available for TM consumption [GH-725] * Added `TmIpSpaceAssociation` and `types.TmIpSpaceAssociation` structures and methods diff --git a/govcd/tm_ip_space_associations.go b/govcd/tm_ip_space_associations.go index 2a9816119..fed5cb92b 100644 --- a/govcd/tm_ip_space_associations.go +++ b/govcd/tm_ip_space_associations.go @@ -10,8 +10,8 @@ import ( const labelTmIpSpaceAssociation = "TM IP Space Association" // TmIpSpaceAssociation manages associations between Provider Gateways and IP Spaces. Each -// association results in a separate entity. The first association is created automatically when -// a Provider Gateway (`TmProviderGateway`) is created. +// association results in a separate entity. There is no update option. The first association is +// created automatically when a Provider Gateway (`TmProviderGateway`) is created. type TmIpSpaceAssociation struct { TmIpSpaceAssociation *types.TmIpSpaceAssociation vcdClient *VCDClient diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index b39726ba3..e8258b9dd 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -13,7 +13,7 @@ const labelTmProviderGateway = "TM Provider Gateway" // // NOTE. While creation of Provider Gateway requires at least one IP Space (`TmIpSpace`) reference, // they are not being returned by API after creation. One must use `TmIpSpaceAssociation` for -// managing IP Space associations with Provider gateways after the initial creation is done. +// managing IP Space associations with Provider gateways after their initial creation is done. type TmProviderGateway struct { TmProviderGateway *types.TmProviderGateway vcdClient *VCDClient diff --git a/govcd/tm_provider_gateway_test.go b/govcd/tm_provider_gateway_test.go index 765042f62..762555def 100644 --- a/govcd/tm_provider_gateway_test.go +++ b/govcd/tm_provider_gateway_test.go @@ -50,7 +50,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { t := &types.TmProviderGateway{ Name: check.TestName(), Description: check.TestName(), - BackingType: "NSX_TIER0", // TODO TODO - does it support T0 VRF? + BackingType: "NSX_TIER0", BackingRef: types.OpenApiReference{ID: t0ByNameInRegion.TmTier0Gateway.ID}, RegionRef: types.OpenApiReference{ID: region.Region.ID}, IPSpaceRefs: []types.OpenApiReference{{ @@ -98,7 +98,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { // IP Space Association management testing - // Retrieve existing + // Retrieve existing association (the one that was created during Provider Gateway creation) associationByProviderGateway, err := vcd.client.GetAllTmIpSpaceAssociationsByProviderGatewayId(createdTmProviderGateway.TmProviderGateway.ID) check.Assert(err, IsNil) check.Assert(len(associationByProviderGateway) == 1, Equals, true) @@ -107,7 +107,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { check.Assert(err, IsNil) check.Assert(len(associationByIpSpace1) == 1, Equals, true) - // Attempt to find an association that does not exist + // Attempt to find an association that does not yet exist associationByIpSpace2, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace2.TmIpSpace.ID) check.Assert(err, IsNil) check.Assert(associationByIpSpace2, NotNil) @@ -127,6 +127,7 @@ func (vcd *TestVCD) Test_TmProviderGateway(check *C) { check.Assert(err, IsNil) check.Assert(len(updatedAssociationByProviderGateway) == 2, Equals, true) + // Check association by IP Space newAssociationByIpSpace2, err := vcd.client.GetAllTmIpSpaceAssociationsByIpSpaceId(ipSpace2.TmIpSpace.ID) check.Assert(err, IsNil) check.Assert(len(newAssociationByIpSpace2) == 1, Equals, true) diff --git a/types/v56/tm.go b/types/v56/tm.go index 9b01fc33b..b57a6110e 100644 --- a/types/v56/tm.go +++ b/types/v56/tm.go @@ -364,7 +364,7 @@ type TmTier0Gateway struct { AlreadyImported bool `json:"alreadyImported"` } -// TmProviderGateway reflects a TM Provider Gateway that is a mapping of +// TmProviderGateway reflects a TM Provider Gateway type TmProviderGateway struct { ID string `json:"id,omitempty"` Name string `json:"name"` @@ -391,11 +391,14 @@ type TmProviderGateway struct { // TmIpSpaceAssociation manages IP Space and Provider Gateway associations type TmIpSpaceAssociation struct { - ID string `json:"id,omitempty"` - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - IPSpaceRef *OpenApiReference `json:"ipSpaceRef,omitempty"` - ProviderGatewayRef *OpenApiReference `json:"providerGatewayRef,omitempty"` + ID string `json:"id,omitempty"` + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + // IPSpaceRef must contain an IP Space reference that will be associated with Provider Gateway + IPSpaceRef *OpenApiReference `json:"ipSpaceRef"` + // ProviderGatewayRef must contain a Provider Gateway reference that will be association with an + // IP Space + ProviderGatewayRef *OpenApiReference `json:"providerGatewayRef"` // Represents current status of the networking entity. Possible values are: // * PENDING - Desired entity configuration has been received by system and is pending realization. // * CONFIGURING - The system is in process of realizing the entity. From 1ea35c27f16a1155ae1cde9160cc5a650b7656be Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Fri, 13 Dec 2024 15:25:03 +0200 Subject: [PATCH 20/21] Add 'requiresTm: true' flags Signed-off-by: Dainius Serplis --- govcd/tm_ip_space_associations.go | 4 ++++ govcd/tm_provider_gateway.go | 5 +++++ govcd/tm_tier0_gateway.go | 1 + 3 files changed, 10 insertions(+) diff --git a/govcd/tm_ip_space_associations.go b/govcd/tm_ip_space_associations.go index fed5cb92b..f0869dc72 100644 --- a/govcd/tm_ip_space_associations.go +++ b/govcd/tm_ip_space_associations.go @@ -30,6 +30,7 @@ func (vcdClient *VCDClient) CreateTmIpSpaceAssociation(config *types.TmIpSpaceAs c := crudConfig{ entityLabel: labelTmIpSpaceAssociation, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, + requiresTm: true, } outerType := TmIpSpaceAssociation{vcdClient: vcdClient} return createOuterEntity(&vcdClient.Client, outerType, c, config) @@ -41,6 +42,7 @@ func (vcdClient *VCDClient) GetAllTmIpSpaceAssociations(queryParameters url.Valu entityLabel: labelTmIpSpaceAssociation, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, queryParameters: queryParameters, + requiresTm: true, } outerType := TmIpSpaceAssociation{vcdClient: vcdClient} @@ -53,6 +55,7 @@ func (vcdClient *VCDClient) GetTmIpSpaceAssociationById(id string) (*TmIpSpaceAs entityLabel: labelTmIpSpaceAssociation, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, endpointParams: []string{id}, + requiresTm: true, } outerType := TmIpSpaceAssociation{vcdClient: vcdClient} @@ -89,6 +92,7 @@ func (o *TmIpSpaceAssociation) Delete() error { entityLabel: labelTmIpSpaceAssociation, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmIpSpaceAssociations, endpointParams: []string{o.TmIpSpaceAssociation.ID}, + requiresTm: true, } return deleteEntityById(&o.vcdClient.Client, c) } diff --git a/govcd/tm_provider_gateway.go b/govcd/tm_provider_gateway.go index e8258b9dd..fbad83d86 100644 --- a/govcd/tm_provider_gateway.go +++ b/govcd/tm_provider_gateway.go @@ -32,6 +32,7 @@ func (vcdClient *VCDClient) CreateTmProviderGateway(config *types.TmProviderGate c := crudConfig{ entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, + requiresTm: true, } outerType := TmProviderGateway{vcdClient: vcdClient} return createOuterEntity(&vcdClient.Client, outerType, c, config) @@ -43,6 +44,7 @@ func (vcdClient *VCDClient) GetAllTmProviderGateways(queryParameters url.Values) entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, queryParameters: queryParameters, + requiresTm: true, } outerType := TmProviderGateway{vcdClient: vcdClient} @@ -77,6 +79,7 @@ func (vcdClient *VCDClient) GetTmProviderGatewayById(id string) (*TmProviderGate entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, endpointParams: []string{id}, + requiresTm: true, } outerType := TmProviderGateway{vcdClient: vcdClient} @@ -112,6 +115,7 @@ func (o *TmProviderGateway) Update(TmProviderGatewayConfig *types.TmProviderGate entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, endpointParams: []string{o.TmProviderGateway.ID}, + requiresTm: true, } outerType := TmProviderGateway{vcdClient: o.vcdClient} return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmProviderGatewayConfig) @@ -123,6 +127,7 @@ func (o *TmProviderGateway) Delete() error { entityLabel: labelTmProviderGateway, endpoint: types.OpenApiPathVcf + types.OpenApiEndpointTmProviderGateways, endpointParams: []string{o.TmProviderGateway.ID}, + requiresTm: true, } return deleteEntityById(&o.vcdClient.Client, c) } diff --git a/govcd/tm_tier0_gateway.go b/govcd/tm_tier0_gateway.go index e0aad8081..bbe2f4369 100644 --- a/govcd/tm_tier0_gateway.go +++ b/govcd/tm_tier0_gateway.go @@ -75,6 +75,7 @@ func (vcdClient *VCDClient) getAllTmTier0Gateways(queryParameters url.Values) ([ entityLabel: labelTmTier0Gateway, endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers, queryParameters: queryParameters, + requiresTm: true, } outerType := TmTier0Gateway{vcdClient: vcdClient} From 16185d405f971116db35286f8b8c3f2401d49215 Mon Sep 17 00:00:00 2001 From: Dainius Serplis Date: Thu, 19 Dec 2024 11:33:27 +0200 Subject: [PATCH 21/21] Improve govcd/sample_govcd_test_config.yaml Signed-off-by: Dainius Serplis --- govcd/sample_govcd_test_config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index cf8344f82..3c2cfd307 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -315,3 +315,4 @@ tm: nsxtManagerUsername: username for NSX-T Manager nsxtManagerPassword: password for NSX-T Manager nsxtManagerUrl: https://HOST + nsxtTier0Gateway: tier0gateway