github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/nsxv_nat.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 ) 14 15 // requestEdgeNatRules nests EdgeNatRule as a convenience for unmarshalling POST requests 16 type requestEdgeNatRules struct { 17 XMLName xml.Name `xml:"natRules"` 18 EdgeNatRules []*types.EdgeNatRule `xml:"natRule"` 19 } 20 21 // responseEdgeNatRules is used to unwrap response when retrieving 22 type responseEdgeNatRules struct { 23 XMLName xml.Name `xml:"nat"` 24 Version string `xml:"version"` 25 NatRules requestEdgeNatRules `xml:"natRules"` 26 } 27 28 // CreateNsxvNatRule creates NAT rule using proxied NSX-V API. It is a synchronuous operation. 29 // It returns an object with all fields populated (including ID) 30 func (egw *EdgeGateway) CreateNsxvNatRule(natRuleConfig *types.EdgeNatRule) (*types.EdgeNatRule, error) { 31 if err := validateCreateNsxvNatRule(natRuleConfig, egw); err != nil { 32 return nil, err 33 } 34 35 // Wrap the provided rule for POST request 36 natRuleRequest := requestEdgeNatRules{ 37 EdgeNatRules: []*types.EdgeNatRule{natRuleConfig}, 38 } 39 40 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateNatPath) 41 if err != nil { 42 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 43 } 44 // We expect to get http.StatusCreated or if not an error of type types.NSXError 45 resp, err := egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPost, types.AnyXMLMime, 46 "error creating NAT rule: %s", natRuleRequest, &types.NSXError{}) 47 if err != nil { 48 return nil, err 49 } 50 51 // Location header should look similar to: 52 // [/network/edges/edge-1/nat/config/rules/197157] 53 natRuleId, err := extractNsxObjectIdFromPath(resp.Header.Get("Location")) 54 if err != nil { 55 return nil, err 56 } 57 58 readNatRule, err := egw.GetNsxvNatRuleById(natRuleId) 59 if err != nil { 60 return nil, fmt.Errorf("unable to retrieve NAT rule with ID (%s) after creation: %s", 61 natRuleId, err) 62 } 63 return readNatRule, nil 64 } 65 66 // UpdateNsxvNatRule updates types.EdgeNatRule with all fields using proxied NSX-V API. ID is 67 // mandatory to perform the update. 68 func (egw *EdgeGateway) UpdateNsxvNatRule(natRuleConfig *types.EdgeNatRule) (*types.EdgeNatRule, error) { 69 err := validateUpdateNsxvNatRule(natRuleConfig, egw) 70 if err != nil { 71 return nil, err 72 } 73 74 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateNatPath + "/" + natRuleConfig.ID) 75 if err != nil { 76 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 77 } 78 79 // Result should be 204, if not we expect an error of type types.NSXError 80 _, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime, 81 "error while updating NAT rule : %s", natRuleConfig, &types.NSXError{}) 82 if err != nil { 83 return nil, err 84 } 85 86 readNatRule, err := egw.GetNsxvNatRuleById(natRuleConfig.ID) 87 if err != nil { 88 return nil, fmt.Errorf("unable to retrieve NAT rule with ID (%s) after update: %s", 89 readNatRule.ID, err) 90 } 91 return readNatRule, nil 92 } 93 94 // GetNsxvNatRules returns a list of all NAT rules in a given edge gateway 95 func (egw *EdgeGateway) GetNsxvNatRules() ([]*types.EdgeNatRule, error) { 96 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeNatPath) 97 if err != nil { 98 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 99 } 100 101 natRuleResponse := &responseEdgeNatRules{} 102 103 // This query returns all application rules as the API does not have filtering options 104 _, err = egw.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime, 105 "unable to read NAT rule: %s", nil, natRuleResponse) 106 if err != nil { 107 return nil, err 108 } 109 return natRuleResponse.NatRules.EdgeNatRules, nil 110 } 111 112 // GetNsxvNatRuleById retrieves types.EdgeNatRule by NAT rule ID as shown in the UI using proxied 113 // NSX-V API. 114 // It returns and error `ErrorEntityNotFound` if the NAT rule is not found. 115 func (egw *EdgeGateway) GetNsxvNatRuleById(id string) (*types.EdgeNatRule, error) { 116 if err := validateGetNsxvNatRule(id, egw); err != nil { 117 return nil, err 118 } 119 120 edgeNatRules, err := egw.GetNsxvNatRules() 121 if err != nil { 122 return nil, err 123 } 124 125 for _, rule := range edgeNatRules { 126 if rule.ID != "" && rule.ID == id { 127 return rule, nil 128 } 129 } 130 131 return nil, ErrorEntityNotFound 132 } 133 134 // DeleteNsxvNatRuleById deletes types.EdgeNatRule by NAT rule ID as shown in the UI using proxied 135 // NSX-V API. 136 // It returns and error `ErrorEntityNotFound` if the NAT rule is now found. 137 func (egw *EdgeGateway) DeleteNsxvNatRuleById(id string) error { 138 err := validateDeleteNsxvNatRule(id, egw) 139 if err != nil { 140 return err 141 } 142 143 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateNatPath + "/" + id) 144 if err != nil { 145 return fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 146 } 147 148 // check if the rule exists and pass back the error at it may be 'ErrorEntityNotFound' 149 _, err = egw.GetNsxvNatRuleById(id) 150 if err != nil { 151 return err 152 } 153 154 _, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime, 155 "unable to delete nat rule: %s", nil, &types.NSXError{}) 156 if err != nil { 157 return err 158 } 159 160 return nil 161 } 162 163 func validateCreateNsxvNatRule(natRuleConfig *types.EdgeNatRule, egw *EdgeGateway) error { 164 if !egw.HasAdvancedNetworking() { 165 return fmt.Errorf("only advanced edge gateways support NAT rules") 166 } 167 168 if natRuleConfig.Action == "" { 169 return fmt.Errorf("NAT rule must have an action") 170 } 171 172 if natRuleConfig.TranslatedAddress == "" { 173 return fmt.Errorf("NAT rule must translated address specified") 174 } 175 176 return nil 177 } 178 179 func validateUpdateNsxvNatRule(natRuleConfig *types.EdgeNatRule, egw *EdgeGateway) error { 180 if natRuleConfig.ID == "" { 181 return fmt.Errorf("NAT rule must ID must be set for update") 182 } 183 184 return validateCreateNsxvNatRule(natRuleConfig, egw) 185 } 186 187 func validateGetNsxvNatRule(id string, egw *EdgeGateway) error { 188 if !egw.HasAdvancedNetworking() { 189 return fmt.Errorf("only advanced edge gateways support NAT rules") 190 } 191 192 if id == "" { 193 return fmt.Errorf("unable to retrieve NAT rule without ID") 194 } 195 196 return nil 197 } 198 199 func validateDeleteNsxvNatRule(id string, egw *EdgeGateway) error { 200 return validateGetNsxvNatRule(id, egw) 201 }