github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/ip_space_allocation.go (about) 1 /* 2 * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "net/url" 11 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 ) 14 15 const labelIpSpaceFloatingIpSuggestion = "IP Space floating IP suggestions" 16 17 // IpSpaceIpAllocation handles IP Space IP allocation requests 18 type IpSpaceIpAllocation struct { 19 IpSpaceIpAllocation *types.IpSpaceIpAllocation 20 IpSpaceId string 21 22 client *Client 23 // Org context must be sent with requests 24 parent organization 25 } 26 27 // AllocateIp performs IP Allocation request for a specific Org and returns the result 28 func (ipSpace *IpSpace) AllocateIp(orgId, orgName string, ipAllocationConfig *types.IpSpaceIpAllocationRequest) ([]types.IpSpaceIpAllocationRequestResult, error) { 29 return allocateIpSpaceIp(&ipSpace.vcdClient.Client, orgId, orgName, ipSpace.IpSpace.ID, ipAllocationConfig) 30 } 31 32 // IpSpaceAllocateIp performs IP allocation request for a specific IP Space 33 func (org *Org) IpSpaceAllocateIp(ipSpaceId string, ipAllocationConfig *types.IpSpaceIpAllocationRequest) ([]types.IpSpaceIpAllocationRequestResult, error) { 34 return allocateIpSpaceIp(org.client, org.Org.ID, org.Org.Name, ipSpaceId, ipAllocationConfig) 35 } 36 37 // GetIpSpaceAllocationByTypeAndValue retrieves IP Space allocation by its type and value 38 // allocationType can be 'FLOATING_IP' (types.IpSpaceIpAllocationTypeFloatingIp) or 'IP_PREFIX' 39 // (types.IpSpaceIpAllocationTypeIpPrefix) 40 func (org *Org) GetIpSpaceAllocationByTypeAndValue(ipSpaceId string, allocationType, value string, queryParameters url.Values) (*IpSpaceIpAllocation, error) { 41 queryParams := queryParameterFilterAnd(fmt.Sprintf("value==%s;type==%s", value, allocationType), queryParameters) 42 results, err := getAllIpSpaceAllocations(org.client, ipSpaceId, org, queryParams) 43 if err != nil { 44 return nil, fmt.Errorf("error retrieving IP allocations: %s", err) 45 } 46 47 singleResult, err := oneOrError("value", value, results) 48 if err != nil { 49 return nil, err 50 } 51 52 return singleResult, nil 53 } 54 55 // GetAllIpSpaceAllocations retrieves all IP Allocations for a particular IP Space 56 // allocationType can be 'FLOATING_IP' (types.IpSpaceIpAllocationTypeFloatingIp) or 'IP_PREFIX' 57 // (types.IpSpaceIpAllocationTypeIpPrefix) 58 func (ipSpace *IpSpace) GetAllIpSpaceAllocations(allocationType string, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) { 59 if allocationType == "" { 60 return nil, fmt.Errorf("allocationType is mandatory and must be 'FLOATING_IP' or 'IP_PREFIX'") 61 } 62 63 client := ipSpace.vcdClient.Client 64 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations 65 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 66 if err != nil { 67 return nil, err 68 } 69 70 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpace.IpSpace.ID)) 71 if err != nil { 72 return nil, err 73 } 74 75 queryParams := queryParameterFilterAnd(fmt.Sprintf("type==%s", allocationType), queryParameters) 76 typeResponses := []*types.IpSpaceIpAllocation{{}} 77 err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParams, &typeResponses, nil) 78 if err != nil { 79 return nil, err 80 } 81 82 // Wrap all typeResponses into IpSpaceIpAllocation types with client 83 results := make([]*IpSpaceIpAllocation, len(typeResponses)) 84 for sliceIndex := range typeResponses { 85 results[sliceIndex] = &IpSpaceIpAllocation{ 86 IpSpaceIpAllocation: typeResponses[sliceIndex], 87 client: &client, 88 IpSpaceId: ipSpace.IpSpace.ID, 89 parent: &Org{ 90 Org: &types.Org{ 91 ID: typeResponses[sliceIndex].OrgRef.ID, 92 Name: typeResponses[sliceIndex].OrgRef.Name}, 93 }, 94 } 95 } 96 97 return results, nil 98 } 99 100 // GetIpSpaceAllocationById retrieves IP Allocation in a given IP Space by IDs 101 func (org *Org) GetIpSpaceAllocationById(ipSpaceId, allocationId string) (*IpSpaceIpAllocation, error) { 102 if ipSpaceId == "" || allocationId == "" { 103 return nil, fmt.Errorf("ipSpaceId and allocationId cannot be empty") 104 } 105 client := org.client 106 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations 107 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 108 if err != nil { 109 return nil, err 110 } 111 112 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpaceId), allocationId) 113 if err != nil { 114 return nil, err 115 } 116 117 response := &IpSpaceIpAllocation{ 118 IpSpaceIpAllocation: &types.IpSpaceIpAllocation{}, 119 parent: org, 120 IpSpaceId: ipSpaceId, 121 client: client, 122 } 123 124 err = client.OpenApiGetItem(apiVersion, urlRef, nil, response.IpSpaceIpAllocation, nil) 125 if err != nil { 126 return nil, err 127 } 128 129 return response, nil 130 131 } 132 133 // Update updates IP Allocation with a given configuration 134 func (ipSpaceAllocation *IpSpaceIpAllocation) Update(ipSpaceAllocationConfig *types.IpSpaceIpAllocation) (*IpSpaceIpAllocation, error) { 135 client := ipSpaceAllocation.client 136 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations 137 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 138 if err != nil { 139 return nil, err 140 } 141 142 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpaceAllocation.IpSpaceId), ipSpaceAllocation.IpSpaceIpAllocation.ID) 143 if err != nil { 144 return nil, err 145 } 146 147 returnIpSpaceAllocation := &IpSpaceIpAllocation{ 148 IpSpaceIpAllocation: &types.IpSpaceIpAllocation{}, 149 client: client, 150 parent: ipSpaceAllocation.parent, 151 IpSpaceId: ipSpaceAllocation.IpSpaceId, 152 } 153 154 tenantContext, err := ipSpaceAllocation.getTenantContext() 155 if err != nil { 156 return nil, err 157 } 158 159 err = client.OpenApiPutItem(apiVersion, urlRef, nil, ipSpaceAllocationConfig, returnIpSpaceAllocation.IpSpaceIpAllocation, getTenantContextHeader(tenantContext)) 160 if err != nil { 161 return nil, fmt.Errorf("error updating IP Space IP Allocation: %s", err) 162 } 163 164 return returnIpSpaceAllocation, nil 165 } 166 167 // Delete removes IP Allocation 168 func (ipSpaceAllocation *IpSpaceIpAllocation) Delete() error { 169 if ipSpaceAllocation == nil || ipSpaceAllocation.IpSpaceIpAllocation == nil || ipSpaceAllocation.IpSpaceIpAllocation.ID == "" { 170 return fmt.Errorf("IP Space IP Allocation must have ID") 171 } 172 173 if ipSpaceAllocation.IpSpaceId == "" || ipSpaceAllocation.parent == nil { 174 return fmt.Errorf("incomplete IpSpaceIpAllocation type") 175 } 176 177 client := ipSpaceAllocation.client 178 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations 179 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 180 if err != nil { 181 return err 182 } 183 184 tenantContext, err := ipSpaceAllocation.getTenantContext() 185 if err != nil { 186 return err 187 } 188 189 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpaceAllocation.IpSpaceId), ipSpaceAllocation.IpSpaceIpAllocation.ID) 190 if err != nil { 191 return err 192 } 193 194 err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, getTenantContextHeader(tenantContext)) 195 if err != nil { 196 return fmt.Errorf("error deleting IP Space IP Allocation: %s", err) 197 } 198 199 return nil 200 } 201 202 func allocateIpSpaceIp(client *Client, orgId, orgName, ipSpaceId string, ipAllocationConfig *types.IpSpaceIpAllocationRequest) ([]types.IpSpaceIpAllocationRequestResult, error) { 203 if orgId == "" || orgName == "" || ipSpaceId == "" { 204 return nil, fmt.Errorf("IP Space must have all values Org ID, Org Name and IP Space ID populated") 205 } 206 207 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocate 208 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 209 if err != nil { 210 return nil, err 211 } 212 213 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpaceId)) 214 if err != nil { 215 return nil, err 216 } 217 218 tenantContext := &TenantContext{ 219 OrgId: orgId, 220 OrgName: orgName, 221 } 222 223 task, err := client.OpenApiPostItemAsyncWithHeaders(apiVersion, urlRef, nil, ipAllocationConfig, getTenantContextHeader(tenantContext)) 224 if err != nil { 225 return nil, fmt.Errorf("error triggering IP Allocation task for IP Space '%s': %s", ipSpaceId, err) 226 } 227 228 err = task.WaitTaskCompletion() 229 if err != nil { 230 return nil, fmt.Errorf("error waiting for task completion: %s", err) 231 } 232 233 // Result of the task should contain a JSON with allocated IP details 234 if task.Task == nil || task.Task.Result == nil || task.Task.Result.ResultContent.Text == "" { 235 return nil, fmt.Errorf("error finding allocated IP result in task") 236 } 237 result := task.Task.Result.ResultContent.Text 238 239 unmarshalStorage := []types.IpSpaceIpAllocationRequestResult{} 240 err = json.Unmarshal([]byte(result), &unmarshalStorage) 241 if err != nil { 242 return nil, fmt.Errorf("error unmarshalling task result: %s", err) 243 } 244 245 return unmarshalStorage, nil 246 } 247 248 func getAllIpSpaceAllocations(client *Client, ipSpaceId string, org *Org, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) { 249 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations 250 apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint) 251 if err != nil { 252 return nil, err 253 } 254 255 urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, ipSpaceId)) 256 if err != nil { 257 return nil, err 258 } 259 260 tenantContext, err := org.getTenantContext() 261 if err != nil { 262 return nil, fmt.Errorf("error getting tenant context: %s", err) 263 } 264 265 typeResponses := []*types.IpSpaceIpAllocation{{}} 266 err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, getTenantContextHeader(tenantContext)) 267 if err != nil { 268 return nil, err 269 } 270 271 // Wrap all typeResponses into IpSpaceIpAllocation types with client 272 results := make([]*IpSpaceIpAllocation, len(typeResponses)) 273 for sliceIndex := range typeResponses { 274 results[sliceIndex] = &IpSpaceIpAllocation{ 275 IpSpaceIpAllocation: typeResponses[sliceIndex], 276 client: client, 277 parent: org, 278 IpSpaceId: ipSpaceId, 279 } 280 } 281 282 return results, nil 283 } 284 285 // GetAllIpSpaceFloatingIpSuggestions suggests IP addresses to use for networking services on Edge 286 // Gateway or Provider Gateway. 'gatewayId' is mandatory. Based on the specified Gateway, VCD will 287 // query all the applicable IP Spaces and suggest some IP addresses which can be utilized to 288 // configure the network services on the Gateway. Allocated IP Space's IP addresses, but not 289 // currently used for any network services are returned. Results can also be filtered by IPV4 or 290 // IPV6 IP address types. 291 // 292 // Filter examples:(filter=gatewayId==URN), (filter=gatewayId==URN;ipType==IPV6) 293 // Go code: 294 // queryParams := url.Values{} 295 // queryParams.Set("filter", "ipType==IPV4") 296 func (vcdClient *VCDClient) GetAllIpSpaceFloatingIpSuggestions(gatewayId string, queryParameters url.Values) ([]*types.IpSpaceFloatingIpSuggestion, error) { 297 if gatewayId == "" { 298 return nil, fmt.Errorf("edge gateway ID is mandatory") 299 } 300 301 queryParams := copyOrNewUrlValues(queryParameters) 302 queryParams = queryParameterFilterAnd("gatewayId=="+gatewayId, queryParams) 303 c := crudConfig{ 304 endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceFloatingIpSuggestions, 305 entityLabel: labelIpSpaceFloatingIpSuggestion, 306 queryParameters: queryParams, 307 } 308 309 return getAllInnerEntities[types.IpSpaceFloatingIpSuggestion](&vcdClient.Client, c) 310 }