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 }