|
| 1 | +/* |
| 2 | + * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. |
| 3 | + */ |
| 4 | + |
| 5 | +package govcd |
| 6 | + |
| 7 | +import ( |
| 8 | + "fmt" |
| 9 | + "net/url" |
| 10 | + |
| 11 | + "github.com/vmware/go-vcloud-director/v2/types/v56" |
| 12 | +) |
| 13 | + |
| 14 | +// IpSpace provides structured approach to allocating public and private IP addresses by preventing |
| 15 | +// the use of overlapping IP addresses across organizations and organization VDCs. |
| 16 | +// |
| 17 | +// An IP space consists of a set of defined non-overlapping IP ranges and small CIDR blocks that are |
| 18 | +// reserved and used during the consumption aspect of the IP space life cycle. An IP space can be |
| 19 | +// either IPv4 or IPv6, but not both. |
| 20 | +// |
| 21 | +// Every IP space has an internal scope and an external scope. The internal scope of an IP space is |
| 22 | +// a list of CIDR notations that defines the exact span of IP addresses in which all ranges and |
| 23 | +// blocks must be contained in. The external scope defines the total span of IP addresses to which |
| 24 | +// the IP space has access, for example the internet or a WAN. |
| 25 | +type IpSpace struct { |
| 26 | + IpSpace *types.IpSpace |
| 27 | + vcdClient *VCDClient |
| 28 | +} |
| 29 | + |
| 30 | +// CreateIpSpace creates IP Space with desired configuration |
| 31 | +func (vcdClient *VCDClient) CreateIpSpace(ipSpaceConfig *types.IpSpace) (*IpSpace, error) { |
| 32 | + client := vcdClient.Client |
| 33 | + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces |
| 34 | + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) |
| 35 | + if err != nil { |
| 36 | + return nil, err |
| 37 | + } |
| 38 | + |
| 39 | + urlRef, err := client.OpenApiBuildEndpoint(endpoint) |
| 40 | + if err != nil { |
| 41 | + return nil, err |
| 42 | + } |
| 43 | + |
| 44 | + result := &IpSpace{ |
| 45 | + IpSpace: &types.IpSpace{}, |
| 46 | + vcdClient: vcdClient, |
| 47 | + } |
| 48 | + |
| 49 | + err = client.OpenApiPostItem(apiVersion, urlRef, nil, ipSpaceConfig, result.IpSpace, nil) |
| 50 | + if err != nil { |
| 51 | + return nil, err |
| 52 | + } |
| 53 | + |
| 54 | + return result, nil |
| 55 | +} |
| 56 | + |
| 57 | +// GetAllIpSpaceSummaries retrieve summaries of all IP Spaces with an optional filter |
| 58 | +// Note. There is no API endpoint to get multiple IP Spaces with their full definitions. Only |
| 59 | +// "summaries" endpoint exists, but it does not include all fields. To retrieve complete structure |
| 60 | +// one can use `GetIpSpaceById` or `GetIpSpaceByName` |
| 61 | +func (vcdClient *VCDClient) GetAllIpSpaceSummaries(queryParameters url.Values) ([]*IpSpace, error) { |
| 62 | + client := vcdClient.Client |
| 63 | + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceSummaries |
| 64 | + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) |
| 65 | + if err != nil { |
| 66 | + return nil, err |
| 67 | + } |
| 68 | + |
| 69 | + urlRef, err := client.OpenApiBuildEndpoint(endpoint) |
| 70 | + if err != nil { |
| 71 | + return nil, err |
| 72 | + } |
| 73 | + |
| 74 | + typeResponses := []*types.IpSpace{{}} |
| 75 | + err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil) |
| 76 | + if err != nil { |
| 77 | + return nil, err |
| 78 | + } |
| 79 | + |
| 80 | + // Wrap all typeResponses into IpSpace types with client |
| 81 | + results := make([]*IpSpace, len(typeResponses)) |
| 82 | + for sliceIndex := range typeResponses { |
| 83 | + results[sliceIndex] = &IpSpace{ |
| 84 | + IpSpace: typeResponses[sliceIndex], |
| 85 | + vcdClient: vcdClient, |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + return results, nil |
| 90 | +} |
| 91 | + |
| 92 | +// GetIpSpaceById retrieves IP Space with a given ID |
| 93 | +func (vcdClient *VCDClient) GetIpSpaceById(id string) (*IpSpace, error) { |
| 94 | + if id == "" { |
| 95 | + return nil, fmt.Errorf("IP Space lookup requires ID") |
| 96 | + } |
| 97 | + |
| 98 | + client := vcdClient.Client |
| 99 | + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces |
| 100 | + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) |
| 101 | + if err != nil { |
| 102 | + return nil, err |
| 103 | + } |
| 104 | + |
| 105 | + urlRef, err := client.OpenApiBuildEndpoint(endpoint, id) |
| 106 | + if err != nil { |
| 107 | + return nil, err |
| 108 | + } |
| 109 | + |
| 110 | + response := &IpSpace{ |
| 111 | + vcdClient: vcdClient, |
| 112 | + IpSpace: &types.IpSpace{}, |
| 113 | + } |
| 114 | + |
| 115 | + err = client.OpenApiGetItem(apiVersion, urlRef, nil, response.IpSpace, nil) |
| 116 | + if err != nil { |
| 117 | + return nil, err |
| 118 | + } |
| 119 | + |
| 120 | + return response, nil |
| 121 | +} |
| 122 | + |
| 123 | +// GetIpSpaceByName retrieves IP Space with a given name |
| 124 | +// Note. It will return an error if multiple IP Spaces exist with the same name |
| 125 | +func (vcdClient *VCDClient) GetIpSpaceByName(name string) (*IpSpace, error) { |
| 126 | + if name == "" { |
| 127 | + return nil, fmt.Errorf("IP Space lookup requires name") |
| 128 | + } |
| 129 | + |
| 130 | + queryParameters := url.Values{} |
| 131 | + queryParameters.Add("filter", "name=="+name) |
| 132 | + |
| 133 | + filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters) |
| 134 | + if err != nil { |
| 135 | + return nil, fmt.Errorf("error getting IP Spaces: %s", err) |
| 136 | + } |
| 137 | + |
| 138 | + singleIpSpace, err := oneOrError("name", name, filteredIpSpaces) |
| 139 | + if err != nil { |
| 140 | + return nil, err |
| 141 | + } |
| 142 | + |
| 143 | + return vcdClient.GetIpSpaceById(singleIpSpace.IpSpace.ID) |
| 144 | +} |
| 145 | + |
| 146 | +// GetIpSpaceByNameAndOrgId retrieves IP Space with a given name in a particular Org |
| 147 | +// Note. Only PRIVATE IP spaces belong to Orgs |
| 148 | +func (vcdClient *VCDClient) GetIpSpaceByNameAndOrgId(name, orgId string) (*IpSpace, error) { |
| 149 | + if name == "" || orgId == "" { |
| 150 | + return nil, fmt.Errorf("IP Space lookup requires name and Org ID") |
| 151 | + } |
| 152 | + |
| 153 | + queryParameters := url.Values{} |
| 154 | + queryParameters.Add("filter", "name=="+name) |
| 155 | + queryParameters = queryParameterFilterAnd("orgRef.id=="+orgId, queryParameters) |
| 156 | + |
| 157 | + filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters) |
| 158 | + if err != nil { |
| 159 | + return nil, fmt.Errorf("error getting IP Spaces: %s", err) |
| 160 | + } |
| 161 | + |
| 162 | + singleIpSpace, err := oneOrError("name", name, filteredIpSpaces) |
| 163 | + if err != nil { |
| 164 | + return nil, fmt.Errorf("error ") |
| 165 | + } |
| 166 | + |
| 167 | + return vcdClient.GetIpSpaceById(singleIpSpace.IpSpace.ID) |
| 168 | +} |
| 169 | + |
| 170 | +// Update updates IP Space with new config |
| 171 | +func (ipSpace *IpSpace) Update(ipSpaceConfig *types.IpSpace) (*IpSpace, error) { |
| 172 | + client := ipSpace.vcdClient.Client |
| 173 | + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces |
| 174 | + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) |
| 175 | + if err != nil { |
| 176 | + return nil, err |
| 177 | + } |
| 178 | + |
| 179 | + ipSpaceConfig.ID = ipSpace.IpSpace.ID |
| 180 | + urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpaceConfig.ID) |
| 181 | + if err != nil { |
| 182 | + return nil, err |
| 183 | + } |
| 184 | + |
| 185 | + returnIpSpace := &IpSpace{ |
| 186 | + IpSpace: &types.IpSpace{}, |
| 187 | + vcdClient: ipSpace.vcdClient, |
| 188 | + } |
| 189 | + |
| 190 | + err = client.OpenApiPutItem(apiVersion, urlRef, nil, ipSpaceConfig, returnIpSpace.IpSpace, nil) |
| 191 | + if err != nil { |
| 192 | + return nil, fmt.Errorf("error updating IP Space: %s", err) |
| 193 | + } |
| 194 | + |
| 195 | + return returnIpSpace, nil |
| 196 | + |
| 197 | +} |
| 198 | + |
| 199 | +// Delete deletes IP Space |
| 200 | +func (ipSpace *IpSpace) Delete() error { |
| 201 | + if ipSpace == nil || ipSpace.IpSpace == nil || ipSpace.IpSpace.ID == "" { |
| 202 | + return fmt.Errorf("IP Space must have ID") |
| 203 | + } |
| 204 | + |
| 205 | + client := ipSpace.vcdClient.Client |
| 206 | + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces |
| 207 | + apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) |
| 208 | + if err != nil { |
| 209 | + return err |
| 210 | + } |
| 211 | + |
| 212 | + urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpace.IpSpace.ID) |
| 213 | + if err != nil { |
| 214 | + return err |
| 215 | + } |
| 216 | + |
| 217 | + err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil) |
| 218 | + if err != nil { |
| 219 | + return err |
| 220 | + } |
| 221 | + |
| 222 | + if err != nil { |
| 223 | + return fmt.Errorf("error deleting IP space: %s", err) |
| 224 | + } |
| 225 | + |
| 226 | + return nil |
| 227 | +} |
0 commit comments