github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/nsxv_ipset.go (about)

     1  /*
     2   * Copyright 2019 VMware, Inc.  All rights reserved.  Licensed under the Apache v2 License.
     3   */
     4  
     5  package govcd
     6  
     7  import (
     8  	"encoding/xml"
     9  	"fmt"
    10  	"net/http"
    11  
    12  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    13  	"github.com/vmware/go-vcloud-director/v2/util"
    14  )
    15  
    16  // CreateNsxvIpSet creates an IP set from *types.EdgeIpSet. IP set defines a group of IP addresses
    17  // that you can add as the source or destination in a firewall rule or in DHCP relay configuration.
    18  func (vdc *Vdc) CreateNsxvIpSet(ipSetConfig *types.EdgeIpSet) (*types.EdgeIpSet, error) {
    19  	if err := validateCreateNsxvIpSet(ipSetConfig); err != nil {
    20  		return nil, err
    21  	}
    22  
    23  	vdcId, err := GetUuidFromHref(vdc.Vdc.HREF, true)
    24  	if err != nil {
    25  		return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err)
    26  	}
    27  
    28  	// build a path for IP set creation. The endpoint should look like:
    29  	// https://_hostname_/network/services/ipset/f9daf2da-b4f9-4921-a2f4-d77a943a381c where the
    30  	// trailing UUID is vDC ID
    31  	httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + vdcId)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err)
    34  	}
    35  
    36  	// Success or an error of type types.NSXError is expected
    37  	_, err = vdc.client.ExecuteParamRequestWithCustomError(httpPath, nil, http.MethodPost, types.AnyXMLMime,
    38  		"error creating IP set: %s", ipSetConfig, &types.NSXError{})
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	createdIpSet, err := vdc.GetNsxvIpSetByName(ipSetConfig.Name)
    44  	if err != nil {
    45  		return nil, fmt.Errorf("could not lookup newly created IP set with name %s: %s", ipSetConfig.Name, err)
    46  	}
    47  
    48  	return createdIpSet, nil
    49  }
    50  
    51  // UpdateNsxvIpSet sends all fields of ipSetConfig. Omiting a value may reset it. ID is mandatory to
    52  // perform update.
    53  // Because the API always requires a Revision to be sent - the update fetches latest revision number
    54  // automatically and embeds into the update structure.
    55  func (vdc *Vdc) UpdateNsxvIpSet(ipSetConfig *types.EdgeIpSet) (*types.EdgeIpSet, error) {
    56  	err := validateUpdateNsxvIpSet(ipSetConfig)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	// Inject latest Revision for this IP set so that API accepts change
    62  	currentIpSet, err := vdc.GetNsxvIpSetById(ipSetConfig.ID)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("could not fetch current IP set: %s", err)
    65  	}
    66  	ipSetConfig.Revision = currentIpSet.Revision
    67  
    68  	httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + ipSetConfig.ID)
    69  	if err != nil {
    70  		return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err)
    71  	}
    72  
    73  	// Result is either 204 for success, or an error of type types.NSXError
    74  	errString := fmt.Sprintf("error while updating IP set with ID %s :%%s", ipSetConfig.ID)
    75  	_, err = vdc.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime,
    76  		errString, ipSetConfig, &types.NSXError{})
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	updatedIpSet, err := vdc.GetNsxvIpSetById(ipSetConfig.ID)
    82  	if err != nil {
    83  		return nil, fmt.Errorf("could not lookup updated IP set with ID %s: %s", ipSetConfig.ID, err)
    84  	}
    85  
    86  	return updatedIpSet, nil
    87  }
    88  
    89  // GetNsxvIpSetByName searches for IP set by name. Names are unique therefore it can find only one.
    90  // Returns ErrorEntityNotFound if an IP set is not found
    91  func (vdc *Vdc) GetNsxvIpSetByName(name string) (*types.EdgeIpSet, error) {
    92  	if err := validateGetNsxvIpSet("", name); err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	allIpSets, err := vdc.GetAllNsxvIpSets()
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	util.Logger.Printf("[DEBUG] Searching for IP set with name: %s", name)
   102  	for _, ipSet := range allIpSets {
   103  		util.Logger.Printf("[DEBUG] Checking IP set: %#+v", ipSet)
   104  		if ipSet.Name != "" && ipSet.Name == name {
   105  			return ipSet, nil
   106  		}
   107  	}
   108  
   109  	return nil, ErrorEntityNotFound
   110  }
   111  
   112  // GetNsxvIpSetById searches for IP set by ID. Returns ErrorEntityNotFound if an IP set is not found
   113  func (vdc *Vdc) GetNsxvIpSetById(id string) (*types.EdgeIpSet, error) {
   114  	if err := validateGetNsxvIpSet(id, ""); err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	allIpSets, err := vdc.GetAllNsxvIpSets()
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	util.Logger.Printf("[DEBUG] Searching for IP set with id: %s", id)
   124  	for _, ipSet := range allIpSets {
   125  		util.Logger.Printf("[DEBUG] Checking IP set: %#+v", ipSet)
   126  		if ipSet.ID != "" && ipSet.ID == id {
   127  			return ipSet, nil
   128  		}
   129  	}
   130  
   131  	return nil, ErrorEntityNotFound
   132  }
   133  
   134  // GetNsxvIpSetByNameOrId uses the same identifier to search by name and by ID. Priority is to try
   135  // and find the IP set by ID. If it is not found - then a search by name is performed.
   136  func (vdc *Vdc) GetNsxvIpSetByNameOrId(identifier string) (*types.EdgeIpSet, error) {
   137  	getByName := func(name string, refresh bool) (interface{}, error) { return vdc.GetNsxvIpSetByName(name) }
   138  	getById := func(id string, refresh bool) (interface{}, error) { return vdc.GetNsxvIpSetById(id) }
   139  	entity, err := getEntityByNameOrId(getByName, getById, identifier, true)
   140  	if entity == nil {
   141  		return nil, err
   142  	}
   143  	return entity.(*types.EdgeIpSet), err
   144  }
   145  
   146  // GetAllNsxvIpSets retrieves all IP sets and returns []*types.EdgeIpSet or an
   147  // error of type ErrorEntityNotFound if there are no IP sets
   148  func (vdc *Vdc) GetAllNsxvIpSets() ([]*types.EdgeIpSet, error) {
   149  	vdcId, err := GetUuidFromHref(vdc.Vdc.HREF, true)
   150  	if err != nil {
   151  		return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err)
   152  	}
   153  
   154  	// build a path for to read all IP sets in a scope. A scope is defined by vDC ID. The endpoint
   155  	// should look like:
   156  	// https://192.168.1.109/network/services/ipset/scope/f9daf2da-b4f9-4921-a2f4-d77a943a381c where
   157  	// the trailing UUID is vDC ID
   158  	httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/scope/" + vdcId)
   159  	if err != nil {
   160  		return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err)
   161  	}
   162  
   163  	// Anonymous struct to unwrap list of IP sets <list><ipset></ipset><ipset></ipset></list>
   164  	ipSetsResponse := &struct {
   165  		XMLName          xml.Name `xml:"list"`
   166  		types.EdgeIpSets `xml:"ipset"`
   167  	}{}
   168  
   169  	// This query returns all IP sets on the scope (scoped by vDC ID)
   170  	errString := fmt.Sprintf("unable to read IP sets for scope %s: %%s", vdcId)
   171  	_, err = vdc.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime, errString, nil, ipSetsResponse)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	if len(ipSetsResponse.EdgeIpSets) == 0 {
   177  		return nil, ErrorEntityNotFound
   178  	}
   179  
   180  	return ipSetsResponse.EdgeIpSets, nil
   181  }
   182  
   183  // DeleteNsxvIpSetById deletes IP set by its ID which is formatted as
   184  // f9daf2da-b4f9-4921-a2f4-d77a943a381c:ipset-9
   185  func (vdc *Vdc) DeleteNsxvIpSetById(id string) error {
   186  	err := validateDeleteNsxvIpSet(id, "")
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	// build a path for to delete exact IP set sample path is: DELETE API-URL/services/ipset/id:ipset-#
   192  	// https://192.168.1.109/network/services/ipset/f9daf2da-b4f9-4921-a2f4-d77a943a381c:ipset-9
   193  	httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + id)
   194  	if err != nil {
   195  		return fmt.Errorf("could not get network services API endpoint for IP set: %s", err)
   196  	}
   197  
   198  	errString := fmt.Sprintf("unable to delete IP set with ID %s: %%s", id)
   199  	_, err = vdc.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime,
   200  		errString, nil, &types.NSXError{})
   201  	if err != nil {
   202  		return err
   203  	}
   204  
   205  	return nil
   206  }
   207  
   208  // DeleteNsxvIpSetById deletes IP set by its name
   209  func (vdc *Vdc) DeleteNsxvIpSetByName(name string) error {
   210  	err := validateDeleteNsxvIpSet("", name)
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	// Get IP set by name
   216  	ipSet, err := vdc.GetNsxvIpSetByName(name)
   217  	if err != nil {
   218  		return err
   219  	}
   220  
   221  	return vdc.DeleteNsxvIpSetById(ipSet.ID)
   222  }
   223  
   224  func validateCreateNsxvIpSet(ipSetConfig *types.EdgeIpSet) error {
   225  
   226  	if ipSetConfig.Name == "" {
   227  		return fmt.Errorf("IP set must have name defined")
   228  	}
   229  
   230  	if ipSetConfig.IPAddresses == "" {
   231  		return fmt.Errorf("IP set must IP addresses defined")
   232  	}
   233  
   234  	return nil
   235  }
   236  
   237  func validateUpdateNsxvIpSet(ipSetConfig *types.EdgeIpSet) error {
   238  
   239  	if ipSetConfig.ID == "" {
   240  		return fmt.Errorf("IP set ID must be set for update")
   241  	}
   242  
   243  	return validateCreateNsxvIpSet(ipSetConfig)
   244  }
   245  
   246  func validateGetNsxvIpSet(id, name string) error {
   247  	if id == "" && name == "" {
   248  		return fmt.Errorf("at least name or ID must be provided")
   249  	}
   250  
   251  	return nil
   252  }
   253  
   254  func validateDeleteNsxvIpSet(id, name string) error {
   255  	return validateGetNsxvIpSet(id, name)
   256  }