From b08ab123ecc333db9dd4658f21568587eefddfb3 Mon Sep 17 00:00:00 2001 From: Dainius Date: Tue, 20 Jun 2023 10:17:06 +0300 Subject: [PATCH] IP Spaces CRUD (#578) --- .changes/v2.21.0/578-features.md | 3 + govcd/ip_space.go | 227 +++++++++++++++++++++++++++++++ govcd/ip_space_test.go | 227 +++++++++++++++++++++++++++++++ govcd/nsxt_edgegateway.go | 8 +- govcd/openapi_endpoints.go | 4 + types/v56/constants.go | 10 ++ types/v56/ip_space.go | 202 +++++++++++++++++++++++++++ 7 files changed, 677 insertions(+), 4 deletions(-) create mode 100644 .changes/v2.21.0/578-features.md create mode 100644 govcd/ip_space.go create mode 100644 govcd/ip_space_test.go create mode 100644 types/v56/ip_space.go diff --git a/.changes/v2.21.0/578-features.md b/.changes/v2.21.0/578-features.md new file mode 100644 index 000000000..945464900 --- /dev/null +++ b/.changes/v2.21.0/578-features.md @@ -0,0 +1,3 @@ +* Added IP Space CRUD support via `IpSpace` and `types.IpSpace` and `VCDClient.CreateIpSpace`, + `VCDClient.GetAllIpSpaceSummaries`, `VCDClient.GetIpSpaceById`, `VCDClient.GetIpSpaceByName`, + `VCDClient.GetIpSpaceByNameAndOrgId`, `IpSpace.Update`, `IpSpace.Delete` [GH-578] diff --git a/govcd/ip_space.go b/govcd/ip_space.go new file mode 100644 index 000000000..b74134c60 --- /dev/null +++ b/govcd/ip_space.go @@ -0,0 +1,227 @@ +/* + * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v2/types/v56" +) + +// IpSpace provides structured approach to allocating public and private IP addresses by preventing +// the use of overlapping IP addresses across organizations and organization VDCs. +// +// An IP space consists of a set of defined non-overlapping IP ranges and small CIDR blocks that are +// reserved and used during the consumption aspect of the IP space life cycle. An IP space can be +// either IPv4 or IPv6, but not both. +// +// Every IP space has an internal scope and an external scope. The internal scope of an IP space is +// a list of CIDR notations that defines the exact span of IP addresses in which all ranges and +// blocks must be contained in. The external scope defines the total span of IP addresses to which +// the IP space has access, for example the internet or a WAN. +type IpSpace struct { + IpSpace *types.IpSpace + vcdClient *VCDClient +} + +// CreateIpSpace creates IP Space with desired configuration +func (vcdClient *VCDClient) CreateIpSpace(ipSpaceConfig *types.IpSpace) (*IpSpace, error) { + client := vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + result := &IpSpace{ + IpSpace: &types.IpSpace{}, + vcdClient: vcdClient, + } + + err = client.OpenApiPostItem(apiVersion, urlRef, nil, ipSpaceConfig, result.IpSpace, nil) + if err != nil { + return nil, err + } + + return result, nil +} + +// GetAllIpSpaceSummaries retrieve summaries of all IP Spaces with an optional filter +// Note. There is no API endpoint to get multiple IP Spaces with their full definitions. Only +// "summaries" endpoint exists, but it does not include all fields. To retrieve complete structure +// one can use `GetIpSpaceById` or `GetIpSpaceByName` +func (vcdClient *VCDClient) GetAllIpSpaceSummaries(queryParameters url.Values) ([]*IpSpace, error) { + client := vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceSummaries + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + typeResponses := []*types.IpSpace{{}} + err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil) + if err != nil { + return nil, err + } + + // Wrap all typeResponses into IpSpace types with client + results := make([]*IpSpace, len(typeResponses)) + for sliceIndex := range typeResponses { + results[sliceIndex] = &IpSpace{ + IpSpace: typeResponses[sliceIndex], + vcdClient: vcdClient, + } + } + + return results, nil +} + +// GetIpSpaceById retrieves IP Space with a given ID +func (vcdClient *VCDClient) GetIpSpaceById(id string) (*IpSpace, error) { + if id == "" { + return nil, fmt.Errorf("IP Space lookup requires ID") + } + + client := vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint, id) + if err != nil { + return nil, err + } + + response := &IpSpace{ + vcdClient: vcdClient, + IpSpace: &types.IpSpace{}, + } + + err = client.OpenApiGetItem(apiVersion, urlRef, nil, response.IpSpace, nil) + if err != nil { + return nil, err + } + + return response, nil +} + +// GetIpSpaceByName retrieves IP Space with a given name +// Note. It will return an error if multiple IP Spaces exist with the same name +func (vcdClient *VCDClient) GetIpSpaceByName(name string) (*IpSpace, error) { + if name == "" { + return nil, fmt.Errorf("IP Space lookup requires name") + } + + queryParameters := url.Values{} + queryParameters.Add("filter", "name=="+name) + + filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters) + if err != nil { + return nil, fmt.Errorf("error getting IP Spaces: %s", err) + } + + singleIpSpace, err := oneOrError("name", name, filteredIpSpaces) + if err != nil { + return nil, err + } + + return vcdClient.GetIpSpaceById(singleIpSpace.IpSpace.ID) +} + +// GetIpSpaceByNameAndOrgId retrieves IP Space with a given name in a particular Org +// Note. Only PRIVATE IP spaces belong to Orgs +func (vcdClient *VCDClient) GetIpSpaceByNameAndOrgId(name, orgId string) (*IpSpace, error) { + if name == "" || orgId == "" { + return nil, fmt.Errorf("IP Space lookup requires name and Org ID") + } + + queryParameters := url.Values{} + queryParameters.Add("filter", "name=="+name) + queryParameters = queryParameterFilterAnd("orgRef.id=="+orgId, queryParameters) + + filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters) + if err != nil { + return nil, fmt.Errorf("error getting IP Spaces: %s", err) + } + + singleIpSpace, err := oneOrError("name", name, filteredIpSpaces) + if err != nil { + return nil, fmt.Errorf("error ") + } + + return vcdClient.GetIpSpaceById(singleIpSpace.IpSpace.ID) +} + +// Update updates IP Space with new config +func (ipSpace *IpSpace) Update(ipSpaceConfig *types.IpSpace) (*IpSpace, error) { + client := ipSpace.vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + ipSpaceConfig.ID = ipSpace.IpSpace.ID + urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpaceConfig.ID) + if err != nil { + return nil, err + } + + returnIpSpace := &IpSpace{ + IpSpace: &types.IpSpace{}, + vcdClient: ipSpace.vcdClient, + } + + err = client.OpenApiPutItem(apiVersion, urlRef, nil, ipSpaceConfig, returnIpSpace.IpSpace, nil) + if err != nil { + return nil, fmt.Errorf("error updating IP Space: %s", err) + } + + return returnIpSpace, nil + +} + +// Delete deletes IP Space +func (ipSpace *IpSpace) Delete() error { + if ipSpace == nil || ipSpace.IpSpace == nil || ipSpace.IpSpace.ID == "" { + return fmt.Errorf("IP Space must have ID") + } + + client := ipSpace.vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpace.IpSpace.ID) + if err != nil { + return err + } + + err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil) + if err != nil { + return err + } + + if err != nil { + return fmt.Errorf("error deleting IP space: %s", err) + } + + return nil +} diff --git a/govcd/ip_space_test.go b/govcd/ip_space_test.go new file mode 100644 index 000000000..8b4738311 --- /dev/null +++ b/govcd/ip_space_test.go @@ -0,0 +1,227 @@ +//go:build network || nsxt || functional || openapi || ALL + +package govcd + +import ( + "fmt" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_IpSpacePublic(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointIpSpaces) + + ipSpaceConfig := &types.IpSpace{ + Name: check.TestName(), + IPSpaceInternalScope: []string{"22.0.0.0/24"}, + IPSpaceExternalScope: "200.0.0.1/24", + Type: types.IpSpacePublic, + RouteAdvertisementEnabled: false, + IPSpacePrefixes: []types.IPSpacePrefixes{ + { + DefaultQuotaForPrefixLength: -1, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.200", + PrefixLength: 31, + TotalPrefixCount: 3, + }, + }, + }, + { + DefaultQuotaForPrefixLength: 2, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.100", + PrefixLength: 30, + TotalPrefixCount: 3, + }, + }, + }, + }, + IPSpaceRanges: types.IPSpaceRanges{ + DefaultFloatingIPQuota: 3, + IPRanges: []types.IpSpaceRangeValues{ + { + StartIPAddress: "22.0.0.10", + EndIPAddress: "22.0.0.30", + }, + { + StartIPAddress: "22.0.0.32", + EndIPAddress: "22.0.0.34", + }, + }, + }, + } + + ipSpaceChecks(vcd, check, ipSpaceConfig) +} + +func (vcd *TestVCD) Test_IpSpaceShared(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointIpSpaces) + + ipSpaceConfig := &types.IpSpace{ + Name: check.TestName(), + IPSpaceInternalScope: []string{"22.0.0.1/24"}, + IPSpaceExternalScope: "200.0.0.1/24", + Type: types.IpSpaceShared, + RouteAdvertisementEnabled: false, + IPSpacePrefixes: []types.IPSpacePrefixes{ + { + DefaultQuotaForPrefixLength: -1, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.200", + PrefixLength: 31, + TotalPrefixCount: 3, + }, + }, + }, + { + DefaultQuotaForPrefixLength: 2, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.100", + PrefixLength: 30, + TotalPrefixCount: 3, + }, + }, + }, + }, + IPSpaceRanges: types.IPSpaceRanges{ + DefaultFloatingIPQuota: 3, + IPRanges: []types.IpSpaceRangeValues{ + { + StartIPAddress: "22.0.0.10", + EndIPAddress: "22.0.0.30", + }, + { + StartIPAddress: "22.0.0.32", + EndIPAddress: "22.0.0.34", + }, + }, + }, + } + ipSpaceChecks(vcd, check, ipSpaceConfig) + +} + +func (vcd *TestVCD) Test_IpSpacePrivate(check *C) { + skipNoNsxtConfiguration(vcd, check) + skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointIpSpaces) + + ipSpaceConfig := &types.IpSpace{ + OrgRef: &types.OpenApiReference{ + ID: vcd.org.Org.ID, // Private IP Space requires Org + }, + Name: check.TestName(), + IPSpaceInternalScope: []string{"22.0.0.1/24"}, + IPSpaceExternalScope: "200.0.0.1/24", + Type: types.IpSpacePrivate, + RouteAdvertisementEnabled: false, + IPSpacePrefixes: []types.IPSpacePrefixes{ + { + DefaultQuotaForPrefixLength: -1, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.200", + PrefixLength: 31, + TotalPrefixCount: 3, + }, + }, + }, + { + DefaultQuotaForPrefixLength: 2, + IPPrefixSequence: []types.IPPrefixSequence{ + { + StartingPrefixIPAddress: "22.0.0.100", + PrefixLength: 30, + TotalPrefixCount: 3, + }, + }, + }, + }, + IPSpaceRanges: types.IPSpaceRanges{ + DefaultFloatingIPQuota: 3, + IPRanges: []types.IpSpaceRangeValues{ + { + StartIPAddress: "22.0.0.10", + EndIPAddress: "22.0.0.30", + }, + { + StartIPAddress: "22.0.0.32", + EndIPAddress: "22.0.0.34", + }, + }, + }, + } + + ipSpaceChecks(vcd, check, ipSpaceConfig) +} + +func ipSpaceChecks(vcd *TestVCD, check *C, ipSpaceConfig *types.IpSpace) { + createdIpSpace, err := vcd.client.CreateIpSpace(ipSpaceConfig) + check.Assert(err, IsNil) + check.Assert(createdIpSpace, NotNil) + + openApiEndpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces + createdIpSpace.IpSpace.ID + AddToCleanupListOpenApi(createdIpSpace.IpSpace.Name, check.TestName(), openApiEndpoint) + + // Get by ID + byId, err := vcd.client.GetIpSpaceById(createdIpSpace.IpSpace.ID) + check.Assert(err, IsNil) + check.Assert(byId.IpSpace, DeepEquals, createdIpSpace.IpSpace) + + // Get by Name + byName, err := vcd.client.GetIpSpaceByName(createdIpSpace.IpSpace.Name) + check.Assert(err, IsNil) + check.Assert(byName.IpSpace, DeepEquals, createdIpSpace.IpSpace) + + // Get all and make sure it is found + allIpSpaces, err := vcd.client.GetAllIpSpaceSummaries(nil) + check.Assert(err, IsNil) + check.Assert(len(allIpSpaces) > 0, Equals, true) + var found bool + for i := range allIpSpaces { + if allIpSpaces[i].IpSpace.ID == byId.IpSpace.ID { + found = true + break + } + } + check.Assert(found, Equals, true) + + // If an Org is assigned - attempt to lookup by name and Org ID + if byId.IpSpace.OrgRef != nil && byId.IpSpace.OrgRef.ID != "" { + byNameAndOrgId, err := vcd.client.GetIpSpaceByNameAndOrgId(byId.IpSpace.Name, byId.IpSpace.OrgRef.ID) + check.Assert(err, IsNil) + check.Assert(byNameAndOrgId, NotNil) + check.Assert(byNameAndOrgId.IpSpace, DeepEquals, createdIpSpace.IpSpace) + + } + + // Check an update + ipSpaceConfig.RouteAdvertisementEnabled = true + ipSpaceConfig.IPSpaceInternalScope = append(ipSpaceConfig.IPSpaceInternalScope, "32.0.0.0/24") + + updatedIpSpace, err := createdIpSpace.Update(ipSpaceConfig) + check.Assert(err, IsNil) + check.Assert(updatedIpSpace, NotNil) + check.Assert(len(ipSpaceConfig.IPSpaceInternalScope), Equals, len(updatedIpSpace.IpSpace.IPSpaceInternalScope)) + + err = createdIpSpace.Delete() + check.Assert(err, IsNil) + + // Check that the entity is not found + notFoundById, err := vcd.client.GetIpSpaceById(byId.IpSpace.ID) + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(notFoundById, IsNil) +} diff --git a/govcd/nsxt_edgegateway.go b/govcd/nsxt_edgegateway.go index 1955184b8..f62987d83 100644 --- a/govcd/nsxt_edgegateway.go +++ b/govcd/nsxt_edgegateway.go @@ -207,7 +207,7 @@ func (egw *NsxtEdgeGateway) Update(edgeGatewayConfig *types.OpenAPIEdgeGateway) } endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways - minimumApiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint) + apiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint) if err != nil { return nil, err } @@ -226,7 +226,7 @@ func (egw *NsxtEdgeGateway) Update(edgeGatewayConfig *types.OpenAPIEdgeGateway) client: egw.client, } - err = egw.client.OpenApiPutItem(minimumApiVersion, urlRef, nil, edgeGatewayConfig, returnEgw.EdgeGateway, nil) + err = egw.client.OpenApiPutItem(apiVersion, urlRef, nil, edgeGatewayConfig, returnEgw.EdgeGateway, nil) if err != nil { return nil, fmt.Errorf("error updating Edge Gateway: %s", err) } @@ -241,7 +241,7 @@ func (egw *NsxtEdgeGateway) Delete() error { } endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways - minimumApiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint) + apiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint) if err != nil { return err } @@ -255,7 +255,7 @@ func (egw *NsxtEdgeGateway) Delete() error { return err } - err = egw.client.OpenApiDeleteItem(minimumApiVersion, urlRef, nil, nil) + err = egw.client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil) if err != nil { return fmt.Errorf("error deleting Edge Gateway: %s", err) diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index e23101ba0..72f26a365 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -66,6 +66,10 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeEntitiesTypes: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeEntitiesResolve: "35.0", // VCD 10.2+ + // IP Spaces + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces: "37.1", // VCD 10.4.1+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceSummaries: "37.1", // VCD 10.4.1+ + // NSX-T ALB (Advanced/AVI Load Balancer) support was introduced in 10.2 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbController: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbImportableClouds: "35.0", // VCD 10.2+ diff --git a/types/v56/constants.go b/types/v56/constants.go index 10a7fcb30..9afb1329c 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -406,6 +406,9 @@ const ( OpenApiEndpointRdeEntitiesTypes = "entities/types/" OpenApiEndpointRdeEntitiesResolve = "entities/%s/resolve" + OpenApiEndpointIpSpaces = "ipSpaces/" + OpenApiEndpointIpSpaceSummaries = "ipSpaces/summaries" + // NSX-T ALB related endpoints OpenApiEndpointAlbController = "loadBalancer/controllers/" @@ -622,6 +625,13 @@ const ( OpenApiOrgVdcNetworkBackingTypeNsxt = "NSXT_FLEXIBLE_SEGMENT" ) +// IP Space types +const ( + IpSpaceShared = "SHARED_SERVICES" + IpSpacePublic = "PUBLIC" + IpSpacePrivate = "PRIVATE" +) + // Values used for SAML metadata normalization and validation const ( SamlNamespaceMd = "urn:oasis:names:tc:SAML:2.0:metadata" diff --git a/types/v56/ip_space.go b/types/v56/ip_space.go new file mode 100644 index 000000000..d77901515 --- /dev/null +++ b/types/v56/ip_space.go @@ -0,0 +1,202 @@ +/* + * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package types + +// IpSpace provides structured approach to allocating public and private IP addresses by preventing +// the use of overlapping IP addresses across organizations and organization VDCs. +// +// An IP space consists of a set of defined non-overlapping IP ranges and small CIDR blocks that are +// reserved and used during the consumption aspect of the IP space life cycle. An IP space can be +// either IPv4 or IPv6, but not both. +// +// Every IP space has an internal scope and an external scope. The internal scope of an IP space is +// a list of CIDR notations that defines the exact span of IP addresses in which all ranges and +// blocks must be contained in. The external scope defines the total span of IP addresses to which +// the IP space has access, for example the internet or a WAN. +type IpSpace struct { + ID string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + + // Type is The type of the IP Space. Possible values are: + // * PUBLIC - These can be consumed by multiple organizations. These are created by System + // Administrators only, for managing public IPs. The IP addresses and IP Prefixes from this IP + // space are allocated to specific organizations for consumption. + // * PRIVATE - These can be consumed by only a single organization. All the IPs within this IP + // Space are allocated to the particular organization. + // * SHARED_SERVICES - These are for internal use only. The IP addresses and IP Prefixes from + // this IP space can be consumed by multiple organizations but those IP addresses and IP + // Prefixes will not be not visible to the individual users within the organization. These are + // created by System Administrators only, typically for a service or for management networks. + // + // Note. This project contains convenience constants for defining IP Space + // types`types.IpSpaceShared`, `types.IpSpacePublic`, `types.IpSpacePrivate` + // + // Only SHARED_SERVICES type can be changed to PUBLIC type. No other type changes are allowed. + Type string `json:"type"` + + // The organization this IP Space belongs to. This property is only applicable and is required + // for IP Spaces with type PRIVATE. + OrgRef *OpenApiReference `json:"orgRef,omitempty"` + + // Utilization summary for this IP space. + Utilization IpSpaceUtilization `json:"utilization,omitempty"` + + // List of IP Prefixes. + IPSpacePrefixes []IPSpacePrefixes `json:"ipSpacePrefixes"` + + // List of IP Ranges. These are logically treated as a single block of IPs for allocation purpose. + IPSpaceRanges IPSpaceRanges `json:"ipSpaceRanges"` + + // This defines the exact span of IP addresses in a CIDR format within which all IP Ranges and + // IP Prefixes of this IP Space must be contained. This typically defines the span of IP + // addresses used within this Data Center. + IPSpaceInternalScope []string `json:"ipSpaceInternalScope"` + + // This defines the total span of IP addresses in a CIDR format within which all IP Ranges and + // IP Prefixes of this IP Space must be contained. This is used by the system for creation of + // NAT rules and BGP prefixes. This typically defines the span of IP addresses outside the + // bounds of this Data Center. For the internet this may be 0.0.0.0/0. For a WAN, this could be + // 10.0.0.0/8. + IPSpaceExternalScope string `json:"ipSpaceExternalScope,omitempty"` + + // Whether the route advertisement is enabled for this IP Space or not. If true, the routed Org + // VDC networks which are configured from this IP Space will be advertised from the connected + // Edge Gateway to the Provider Gateway. Route advertisement must be enabled on a particular + // network for it to be advertised. Networks from the PRIVATE IP Spaces will only be advertised + // if the associated Provider Gateway is owned by the Organization. + RouteAdvertisementEnabled bool `json:"routeAdvertisementEnabled"` + + // Status is one of `PENDING`, `CONFIGURING`, `REALIZED`, `REALIZATION_FAILED`, `UNKNOWN` + Status string `json:"status,omitempty"` +} + +type FloatingIPs struct { + // TotalCount holds the number of IP addresses or IP Prefixes defined by the IP Space. If user + // does not own this IP Space, this is the quota that the user's organization is granted. A '-1' + // value means that the user's organization has no cap on the quota (for this case, + // allocatedPercentage is unset) + TotalCount string `json:"totalCount,omitempty"` + // AllocatedCount holds the number of allocated IP addresses or IP Prefixes. + AllocatedCount string `json:"allocatedCount,omitempty"` + // UsedCount holds the number of used IP addresses or IP Prefixes. An allocated IP address or IP + // Prefix is considered used if it is being used in network services such as NAT rule or in Org + // VDC network definition. + UsedCount string `json:"usedCount,omitempty"` + // UnusedCount holds the number of unused IP addresses or IP Prefixes. An IP address or an IP + // Prefix is considered unused if it is allocated but not being used by any network service or + // any Org vDC network definition. + UnusedCount string `json:"unusedCount,omitempty"` + // AllocatedPercentage specifies the percentage of allocated IP addresses or IP Prefixes out of + // all defined IP addresses or IP Prefixes. + AllocatedPercentage float32 `json:"allocatedPercentage,omitempty"` + // UsedPercentage specifies the percentage of used IP addresses or IP Prefixes out of total + // allocated IP addresses or IP Prefixes. + UsedPercentage float32 `json:"usedPercentage,omitempty"` +} + +type PrefixLengthUtilizations struct { + PrefixLength int `json:"prefixLength"` + // TotalCount contains total number of IP Prefixes. If user does not own this IP Space, this is + // the quota that the user's organization is granted. A '-1' value means that the user's + // organization has no cap on the quota. + TotalCount int `json:"totalCount"` + // AllocatedCount contains the number of allocated IP prefixes. + AllocatedCount int `json:"allocatedCount"` +} + +type IPPrefixes struct { + // TotalCount holds the number of IP addresses or IP Prefixes defined by the IP Space. If user + // does not own this IP Space, this is the quota that the user's organization is granted. A '-1' + // value means that the user's organization has no cap on the quota; for this case, + // allocatedPercentage is unset. + TotalCount string `json:"totalCount,omitempty"` + // TAllocatedCount holds the number of allocated IP addresses or IP Prefixes. + AllocatedCount string `json:"allocatedCount,omitempty"` + // UsedCount holds the number of used IP addresses or IP Prefixes. An allocated IP address or IP + // Prefix is considered used if it is being used in network services such as NAT rule or in Org + // VDC network definition. + UsedCount string `json:"usedCount,omitempty"` + // UnusedCount holds the number of unused IP addresses or IP Prefixes. An IP address or an IP + // Prefix is considered unused if it is allocated but not being used by any network service or + // any Org vDC network definition. + UnusedCount string `json:"unusedCount,omitempty"` + // AllocatedPercentage specifies the percentage of allocated IP addresses or IP Prefixes out of + // all defined IP addresses or IP Prefixes. + AllocatedPercentage float32 `json:"allocatedPercentage,omitempty"` + // UsedPercentage specifies the percentage of used IP addresses or IP Prefixes out of total + // allocated IP addresses or IP Prefixes. + UsedPercentage float32 `json:"usedPercentage,omitempty"` + // PrefixLengthUtilizations contains utilization summary grouped by IP Prefix's prefix length. + // This information will only be returned for an individual IP Prefix. + PrefixLengthUtilizations []PrefixLengthUtilizations `json:"prefixLengthUtilizations,omitempty"` +} + +type IpSpaceUtilization struct { + // FloatingIPs holds utilization summary for floating IPs within the IP space. + FloatingIPs FloatingIPs `json:"floatingIPs,omitempty"` + // IPPrefixes holds Utilization summary for IP prefixes within the IP space. + IPPrefixes IPPrefixes `json:"ipPrefixes,omitempty"` +} + +type IPSpaceRanges struct { + IPRanges []IpSpaceRangeValues `json:"ipRanges"` + // This specifies the default number of IPs from the specified ranges which can be consumed by + // each organization using this IP Space. This is typically set for IP Spaces with type PUBLIC + // or SHARED_SERVICES. A Quota of -1 means there is no cap to the number of IP addresses that + // can be allocated. A Quota of 0 means that the IP addresses cannot be allocated. If not + // specified, all PUBLIC or SHARED_SERVICES IP Spaces have a default quota of 1 for Floating IP + // addresses and all PRIVATE IP Spaces have a default quota of -1 for Floating IP addresses. + DefaultFloatingIPQuota int `json:"defaultFloatingIpQuota"` +} + +type IpSpaceRangeValues struct { + ID string `json:"id,omitempty"` + // Starting IP address in the range. + StartIPAddress string `json:"startIpAddress"` + // endIpAddress + EndIPAddress string `json:"endIpAddress"` + + // The number of IP addresses defined by the IP range. + TotalIPCount string `json:"totalIpCount,omitempty"` + // The number of allocated IP addresses. + AllocatedIPCount string `json:"allocatedIpCount,omitempty"` + // allocatedIpPercentage + AllocatedIPPercentage float32 `json:"allocatedIpPercentage,omitempty"` +} + +type IPSpacePrefixes struct { + // IPPrefixSequence A sequence of IP prefixes with same prefix length. All the IP Prefix + // sequences with the same prefix length are treated as one logical unit for allocation purpose. + IPPrefixSequence []IPPrefixSequence `json:"ipPrefixSequence"` + + // This specifies the number of prefixes from the specified sequence which can be consumed by + // each organization using this IP Space. All the IP Prefix sequences with the same prefix + // length are treated as one logical unit for allocation purpose. This is typically set for IP + // Spaces with type PUBLIC or SHARED_SERVICES. A Quota of -1 means there is no cap to the number + // of IP Prefixes that can be allocated. A Quota of 0 means that the IP Prefixes cannot be + // allocated. If not specified, all PUBLIC or SHARED_SERVICES IP Spaces have a default quota of + // 0 for IP Prefixes and all PRIVATE IP Spaces have a default quota of -1 for IP Prefixes. + DefaultQuotaForPrefixLength int `json:"defaultQuotaForPrefixLength"` +} + +type IPPrefixSequence struct { + ID string `json:"id,omitempty"` + // Starting IP address for the IP prefix. Note that if the IP is a host IP and not the network + // definition IP for the specific prefix length, VCD will automatically modify starting IP to + // the network definition's IP for the specified host IP. An example is that for prefix length + // 30, the starting IP of 192.169.0.2 will be automatically modified to 192.169.0.0. 192.169.0.6 + // will be modified to 192.169.0.4. 192.169.0.0/30 and 192.169.0.4/30 are network definition + // CIDRs for host IPs 192.169.0.2 and 192.169.0.6, respectively. + StartingPrefixIPAddress string `json:"startingPrefixIpAddress"` + // The prefix length. + PrefixLength int `json:"prefixLength"` + // The number of prefix blocks defined by this IP prefix. + TotalPrefixCount int `json:"totalPrefixCount"` + // The number of allocated IP prefix blocks. + AllocatedPrefixCount int `json:"allocatedPrefixCount,omitempty"` + // Specifies the percentage of allocated IP prefix blocks out of total specified IP prefix blocks. + AllocatedPrefixPercentage float32 `json:"allocatedPrefixPercentage,omitempty"` +}