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  }