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