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 }