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