github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/lbappprofile.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  	"fmt"
     9  	"net/http"
    10  
    11  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    12  )
    13  
    14  // CreateLbAppProfile creates a load balancer application profile based on mandatory fields. It is a
    15  // synchronous operation. It returns created object with all fields (including ID) populated or an error.
    16  func (egw *EdgeGateway) CreateLbAppProfile(lbAppProfileConfig *types.LbAppProfile) (*types.LbAppProfile, error) {
    17  	if err := validateCreateLbAppProfile(lbAppProfileConfig, egw); err != nil {
    18  		return nil, err
    19  	}
    20  
    21  	httpPath, err := egw.buildProxiedEdgeEndpointURL(types.LbAppProfilePath)
    22  	if err != nil {
    23  		return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
    24  	}
    25  	// We expect to get http.StatusCreated or if not an error of type types.NSXError
    26  	resp, err := egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPost, types.AnyXMLMime,
    27  		"error creating load balancer application profile: %s", lbAppProfileConfig, &types.NSXError{})
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	// Location header should look similar to:
    33  	// [/network/edges/edge-3/loadbalancer/config/applicationprofiles/applicationProfile-4]
    34  	lbAppProfileID, err := extractNsxObjectIdFromPath(resp.Header.Get("Location"))
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	readAppProfile, err := egw.GetLbAppProfileById(lbAppProfileID)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("unable to retrieve application profile with ID (%s) after creation: %s",
    42  			lbAppProfileID, err)
    43  	}
    44  	return readAppProfile, nil
    45  }
    46  
    47  // GetLbAppProfiles returns a list of all LB application profiles in a given edge gateway
    48  func (egw *EdgeGateway) GetLbAppProfiles() ([]*types.LbAppProfile, error) {
    49  	httpPath, err := egw.buildProxiedEdgeEndpointURL(types.LbAppProfilePath)
    50  	if err != nil {
    51  		return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
    52  	}
    53  
    54  	// Anonymous struct to unwrap response
    55  	lbAppProfileResponse := &struct {
    56  		LbAppProfiles []*types.LbAppProfile `xml:"applicationProfile"`
    57  	}{}
    58  
    59  	// This query returns all application profiles as the API does not have filtering options
    60  	_, err = egw.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime,
    61  		"unable to read load balancer application profile: %s", nil, lbAppProfileResponse)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return lbAppProfileResponse.LbAppProfiles, nil
    66  }
    67  
    68  // getLbAppProfile is able to find the types.LbAppProfile type by Name and/or ID.
    69  // If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found
    70  // name do not match.
    71  func (egw *EdgeGateway) getLbAppProfile(lbAppProfileConfig *types.LbAppProfile) (*types.LbAppProfile, error) {
    72  	if err := validateGetLbAppProfile(lbAppProfileConfig, egw); err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	lbAppProfiles, err := egw.GetLbAppProfiles()
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	// Search for application profile by ID or by Name
    82  	for _, profile := range lbAppProfiles {
    83  		// If ID was specified for lookup - look for the same ID
    84  		if lbAppProfileConfig.ID != "" && profile.ID == lbAppProfileConfig.ID {
    85  			return profile, nil
    86  		}
    87  
    88  		// If Name was specified for lookup - look for the same Name
    89  		if lbAppProfileConfig.Name != "" && profile.Name == lbAppProfileConfig.Name {
    90  			// We found it by name. Let's verify if search ID was specified and it matches the lookup object
    91  			if lbAppProfileConfig.ID != "" && profile.ID != lbAppProfileConfig.ID {
    92  				return nil, fmt.Errorf("load balancer application profile was found by name (%s)"+
    93  					", but its ID (%s) does not match specified ID (%s)",
    94  					profile.Name, profile.ID, lbAppProfileConfig.ID)
    95  			}
    96  			return profile, nil
    97  		}
    98  	}
    99  
   100  	return nil, ErrorEntityNotFound
   101  }
   102  
   103  // GetLbAppProfileById wraps getLbAppProfile and needs only an ID for lookup
   104  func (egw *EdgeGateway) GetLbAppProfileById(id string) (*types.LbAppProfile, error) {
   105  	return egw.getLbAppProfile(&types.LbAppProfile{ID: id})
   106  }
   107  
   108  // GetLbAppProfileByName wraps getLbAppProfile and needs only a Name for lookup
   109  func (egw *EdgeGateway) GetLbAppProfileByName(name string) (*types.LbAppProfile, error) {
   110  	return egw.getLbAppProfile(&types.LbAppProfile{Name: name})
   111  }
   112  
   113  // UpdateLbAppProfile updates types.LbAppProfile with all fields. At least name or ID must be specified.
   114  // If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found
   115  // name do not match.
   116  func (egw *EdgeGateway) UpdateLbAppProfile(lbAppProfileConfig *types.LbAppProfile) (*types.LbAppProfile, error) {
   117  	err := validateUpdateLbAppProfile(lbAppProfileConfig, egw)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	lbAppProfileConfig.ID, err = egw.getLbAppProfileIdByNameId(lbAppProfileConfig.Name, lbAppProfileConfig.ID)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("cannot update load balancer application profile: %s", err)
   125  	}
   126  
   127  	httpPath, err := egw.buildProxiedEdgeEndpointURL(types.LbAppProfilePath + lbAppProfileConfig.ID)
   128  	if err != nil {
   129  		return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
   130  	}
   131  
   132  	// Result should be 204, if not we expect an error of type types.NSXError
   133  	_, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime,
   134  		"error while updating load balancer application profile : %s", lbAppProfileConfig, &types.NSXError{})
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	readAppProfile, err := egw.GetLbAppProfileById(lbAppProfileConfig.ID)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("unable to retrieve application profile with ID (%s) after update: %s",
   142  			lbAppProfileConfig.ID, err)
   143  	}
   144  	return readAppProfile, nil
   145  }
   146  
   147  // DeleteLbAppProfile is able to delete the types.LbAppProfile type by Name and/or ID.
   148  // If both - Name and ID are specified it performs a lookup by ID and returns an error if the specified name and found
   149  // name do not match.
   150  func (egw *EdgeGateway) DeleteLbAppProfile(lbAppProfileConfig *types.LbAppProfile) error {
   151  	err := validateDeleteLbAppProfile(lbAppProfileConfig, egw)
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	lbAppProfileConfig.ID, err = egw.getLbAppProfileIdByNameId(lbAppProfileConfig.Name, lbAppProfileConfig.ID)
   157  	if err != nil {
   158  		return fmt.Errorf("cannot delete load balancer application profile: %s", err)
   159  	}
   160  
   161  	httpPath, err := egw.buildProxiedEdgeEndpointURL(types.LbAppProfilePath + lbAppProfileConfig.ID)
   162  	if err != nil {
   163  		return fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
   164  	}
   165  
   166  	_, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime,
   167  		"unable to delete application profile: %s", nil, &types.NSXError{})
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  // DeleteLbAppProfileById wraps DeleteLbAppProfile and requires only ID for deletion
   176  func (egw *EdgeGateway) DeleteLbAppProfileById(id string) error {
   177  	return egw.DeleteLbAppProfile(&types.LbAppProfile{ID: id})
   178  }
   179  
   180  // DeleteLbAppProfileByName wraps DeleteLbAppProfile and requires only Name for deletion
   181  func (egw *EdgeGateway) DeleteLbAppProfileByName(name string) error {
   182  	return egw.DeleteLbAppProfile(&types.LbAppProfile{Name: name})
   183  }
   184  
   185  func validateCreateLbAppProfile(lbAppProfileConfig *types.LbAppProfile, egw *EdgeGateway) error {
   186  	if !egw.HasAdvancedNetworking() {
   187  		return fmt.Errorf("only advanced edge gateways support load balancers")
   188  	}
   189  
   190  	if lbAppProfileConfig.Name == "" {
   191  		return fmt.Errorf("load balancer application profile Name cannot be empty")
   192  	}
   193  
   194  	return nil
   195  }
   196  
   197  func validateGetLbAppProfile(lbAppProfileConfig *types.LbAppProfile, egw *EdgeGateway) error {
   198  	if !egw.HasAdvancedNetworking() {
   199  		return fmt.Errorf("only advanced edge gateways support load balancers")
   200  	}
   201  
   202  	if lbAppProfileConfig.ID == "" && lbAppProfileConfig.Name == "" {
   203  		return fmt.Errorf("to read load balancer application profile at least one of `ID`, `Name`" +
   204  			" fields must be specified")
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  func validateUpdateLbAppProfile(lbAppProfileConfig *types.LbAppProfile, egw *EdgeGateway) error {
   211  	// Update and create have the same requirements for now
   212  	return validateCreateLbAppProfile(lbAppProfileConfig, egw)
   213  }
   214  
   215  func validateDeleteLbAppProfile(lbAppProfileConfig *types.LbAppProfile, egw *EdgeGateway) error {
   216  	// Read and delete have the same requirements for now
   217  	return validateGetLbAppProfile(lbAppProfileConfig, egw)
   218  }
   219  
   220  // getLbAppProfileIdByNameId checks if at least name or ID is set and returns the ID.
   221  // If the ID is specified - it passes through the ID. If only name was specified
   222  // it will lookup the object by name and return the ID.
   223  func (egw *EdgeGateway) getLbAppProfileIdByNameId(name, id string) (string, error) {
   224  	if name == "" && id == "" {
   225  		return "", fmt.Errorf("at least Name or ID must be specific to find load balancer "+
   226  			"application profile got name (%s) ID (%s)", name, id)
   227  	}
   228  	if id != "" {
   229  		return id, nil
   230  	}
   231  
   232  	// if only name was specified, ID must be found, because only ID can be used in request path
   233  	readlbAppProfile, err := egw.GetLbAppProfileByName(name)
   234  	if err != nil {
   235  		return "", fmt.Errorf("unable to find load balancer application profile by name: %s", err)
   236  	}
   237  	return readlbAppProfile.ID, nil
   238  }