github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/nsxv_ipset.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 "encoding/xml" 9 "fmt" 10 "net/http" 11 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 "github.com/vmware/go-vcloud-director/v2/util" 14 ) 15 16 // CreateNsxvIpSet creates an IP set from *types.EdgeIpSet. IP set defines a group of IP addresses 17 // that you can add as the source or destination in a firewall rule or in DHCP relay configuration. 18 func (vdc *Vdc) CreateNsxvIpSet(ipSetConfig *types.EdgeIpSet) (*types.EdgeIpSet, error) { 19 if err := validateCreateNsxvIpSet(ipSetConfig); err != nil { 20 return nil, err 21 } 22 23 vdcId, err := GetUuidFromHref(vdc.Vdc.HREF, true) 24 if err != nil { 25 return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err) 26 } 27 28 // build a path for IP set creation. The endpoint should look like: 29 // https://_hostname_/network/services/ipset/f9daf2da-b4f9-4921-a2f4-d77a943a381c where the 30 // trailing UUID is vDC ID 31 httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + vdcId) 32 if err != nil { 33 return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err) 34 } 35 36 // Success or an error of type types.NSXError is expected 37 _, err = vdc.client.ExecuteParamRequestWithCustomError(httpPath, nil, http.MethodPost, types.AnyXMLMime, 38 "error creating IP set: %s", ipSetConfig, &types.NSXError{}) 39 if err != nil { 40 return nil, err 41 } 42 43 createdIpSet, err := vdc.GetNsxvIpSetByName(ipSetConfig.Name) 44 if err != nil { 45 return nil, fmt.Errorf("could not lookup newly created IP set with name %s: %s", ipSetConfig.Name, err) 46 } 47 48 return createdIpSet, nil 49 } 50 51 // UpdateNsxvIpSet sends all fields of ipSetConfig. Omiting a value may reset it. ID is mandatory to 52 // perform update. 53 // Because the API always requires a Revision to be sent - the update fetches latest revision number 54 // automatically and embeds into the update structure. 55 func (vdc *Vdc) UpdateNsxvIpSet(ipSetConfig *types.EdgeIpSet) (*types.EdgeIpSet, error) { 56 err := validateUpdateNsxvIpSet(ipSetConfig) 57 if err != nil { 58 return nil, err 59 } 60 61 // Inject latest Revision for this IP set so that API accepts change 62 currentIpSet, err := vdc.GetNsxvIpSetById(ipSetConfig.ID) 63 if err != nil { 64 return nil, fmt.Errorf("could not fetch current IP set: %s", err) 65 } 66 ipSetConfig.Revision = currentIpSet.Revision 67 68 httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + ipSetConfig.ID) 69 if err != nil { 70 return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err) 71 } 72 73 // Result is either 204 for success, or an error of type types.NSXError 74 errString := fmt.Sprintf("error while updating IP set with ID %s :%%s", ipSetConfig.ID) 75 _, err = vdc.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime, 76 errString, ipSetConfig, &types.NSXError{}) 77 if err != nil { 78 return nil, err 79 } 80 81 updatedIpSet, err := vdc.GetNsxvIpSetById(ipSetConfig.ID) 82 if err != nil { 83 return nil, fmt.Errorf("could not lookup updated IP set with ID %s: %s", ipSetConfig.ID, err) 84 } 85 86 return updatedIpSet, nil 87 } 88 89 // GetNsxvIpSetByName searches for IP set by name. Names are unique therefore it can find only one. 90 // Returns ErrorEntityNotFound if an IP set is not found 91 func (vdc *Vdc) GetNsxvIpSetByName(name string) (*types.EdgeIpSet, error) { 92 if err := validateGetNsxvIpSet("", name); err != nil { 93 return nil, err 94 } 95 96 allIpSets, err := vdc.GetAllNsxvIpSets() 97 if err != nil { 98 return nil, err 99 } 100 101 util.Logger.Printf("[DEBUG] Searching for IP set with name: %s", name) 102 for _, ipSet := range allIpSets { 103 util.Logger.Printf("[DEBUG] Checking IP set: %#+v", ipSet) 104 if ipSet.Name != "" && ipSet.Name == name { 105 return ipSet, nil 106 } 107 } 108 109 return nil, ErrorEntityNotFound 110 } 111 112 // GetNsxvIpSetById searches for IP set by ID. Returns ErrorEntityNotFound if an IP set is not found 113 func (vdc *Vdc) GetNsxvIpSetById(id string) (*types.EdgeIpSet, error) { 114 if err := validateGetNsxvIpSet(id, ""); err != nil { 115 return nil, err 116 } 117 118 allIpSets, err := vdc.GetAllNsxvIpSets() 119 if err != nil { 120 return nil, err 121 } 122 123 util.Logger.Printf("[DEBUG] Searching for IP set with id: %s", id) 124 for _, ipSet := range allIpSets { 125 util.Logger.Printf("[DEBUG] Checking IP set: %#+v", ipSet) 126 if ipSet.ID != "" && ipSet.ID == id { 127 return ipSet, nil 128 } 129 } 130 131 return nil, ErrorEntityNotFound 132 } 133 134 // GetNsxvIpSetByNameOrId uses the same identifier to search by name and by ID. Priority is to try 135 // and find the IP set by ID. If it is not found - then a search by name is performed. 136 func (vdc *Vdc) GetNsxvIpSetByNameOrId(identifier string) (*types.EdgeIpSet, error) { 137 getByName := func(name string, refresh bool) (interface{}, error) { return vdc.GetNsxvIpSetByName(name) } 138 getById := func(id string, refresh bool) (interface{}, error) { return vdc.GetNsxvIpSetById(id) } 139 entity, err := getEntityByNameOrId(getByName, getById, identifier, true) 140 if entity == nil { 141 return nil, err 142 } 143 return entity.(*types.EdgeIpSet), err 144 } 145 146 // GetAllNsxvIpSets retrieves all IP sets and returns []*types.EdgeIpSet or an 147 // error of type ErrorEntityNotFound if there are no IP sets 148 func (vdc *Vdc) GetAllNsxvIpSets() ([]*types.EdgeIpSet, error) { 149 vdcId, err := GetUuidFromHref(vdc.Vdc.HREF, true) 150 if err != nil { 151 return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err) 152 } 153 154 // build a path for to read all IP sets in a scope. A scope is defined by vDC ID. The endpoint 155 // should look like: 156 // https://192.168.1.109/network/services/ipset/scope/f9daf2da-b4f9-4921-a2f4-d77a943a381c where 157 // the trailing UUID is vDC ID 158 httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/scope/" + vdcId) 159 if err != nil { 160 return nil, fmt.Errorf("could not get network services API endpoint for IP set: %s", err) 161 } 162 163 // Anonymous struct to unwrap list of IP sets <list><ipset></ipset><ipset></ipset></list> 164 ipSetsResponse := &struct { 165 XMLName xml.Name `xml:"list"` 166 types.EdgeIpSets `xml:"ipset"` 167 }{} 168 169 // This query returns all IP sets on the scope (scoped by vDC ID) 170 errString := fmt.Sprintf("unable to read IP sets for scope %s: %%s", vdcId) 171 _, err = vdc.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime, errString, nil, ipSetsResponse) 172 if err != nil { 173 return nil, err 174 } 175 176 if len(ipSetsResponse.EdgeIpSets) == 0 { 177 return nil, ErrorEntityNotFound 178 } 179 180 return ipSetsResponse.EdgeIpSets, nil 181 } 182 183 // DeleteNsxvIpSetById deletes IP set by its ID which is formatted as 184 // f9daf2da-b4f9-4921-a2f4-d77a943a381c:ipset-9 185 func (vdc *Vdc) DeleteNsxvIpSetById(id string) error { 186 err := validateDeleteNsxvIpSet(id, "") 187 if err != nil { 188 return err 189 } 190 191 // build a path for to delete exact IP set sample path is: DELETE API-URL/services/ipset/id:ipset-# 192 // https://192.168.1.109/network/services/ipset/f9daf2da-b4f9-4921-a2f4-d77a943a381c:ipset-9 193 httpPath, err := vdc.buildNsxvNetworkServiceEndpointURL(types.NsxvIpSetServicePath + "/" + id) 194 if err != nil { 195 return fmt.Errorf("could not get network services API endpoint for IP set: %s", err) 196 } 197 198 errString := fmt.Sprintf("unable to delete IP set with ID %s: %%s", id) 199 _, err = vdc.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime, 200 errString, nil, &types.NSXError{}) 201 if err != nil { 202 return err 203 } 204 205 return nil 206 } 207 208 // DeleteNsxvIpSetById deletes IP set by its name 209 func (vdc *Vdc) DeleteNsxvIpSetByName(name string) error { 210 err := validateDeleteNsxvIpSet("", name) 211 if err != nil { 212 return err 213 } 214 215 // Get IP set by name 216 ipSet, err := vdc.GetNsxvIpSetByName(name) 217 if err != nil { 218 return err 219 } 220 221 return vdc.DeleteNsxvIpSetById(ipSet.ID) 222 } 223 224 func validateCreateNsxvIpSet(ipSetConfig *types.EdgeIpSet) error { 225 226 if ipSetConfig.Name == "" { 227 return fmt.Errorf("IP set must have name defined") 228 } 229 230 if ipSetConfig.IPAddresses == "" { 231 return fmt.Errorf("IP set must IP addresses defined") 232 } 233 234 return nil 235 } 236 237 func validateUpdateNsxvIpSet(ipSetConfig *types.EdgeIpSet) error { 238 239 if ipSetConfig.ID == "" { 240 return fmt.Errorf("IP set ID must be set for update") 241 } 242 243 return validateCreateNsxvIpSet(ipSetConfig) 244 } 245 246 func validateGetNsxvIpSet(id, name string) error { 247 if id == "" && name == "" { 248 return fmt.Errorf("at least name or ID must be provided") 249 } 250 251 return nil 252 } 253 254 func validateDeleteNsxvIpSet(id, name string) error { 255 return validateGetNsxvIpSet(id, name) 256 }