github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/nsxv_firewall.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 // requestEdgeFirewallRules nests EdgeFirewallRule as a convenience for unmarshalling POST requests 17 type requestEdgeFirewallRules struct { 18 XMLName xml.Name `xml:"firewallRules"` 19 EdgeFirewallRules []*types.EdgeFirewallRule `xml:"firewallRule"` 20 } 21 22 // responseEdgeFirewallRules is used to unwrap response when retrieving 23 type responseEdgeFirewallRules struct { 24 XMLName xml.Name `xml:"firewall"` 25 Version string `xml:"version"` 26 EdgeFirewallRules requestEdgeFirewallRules `xml:"firewallRules"` 27 } 28 29 // CreateNsxvFirewallRule creates firewall rule using proxied NSX-V API. It is a synchronous operation. 30 // It returns an object with all fields populated (including ID) 31 // If aboveRuleId is not empty, it will send a query parameter aboveRuleId= which instructs NSX to 32 // place this rule above the specified rule ID 33 func (egw *EdgeGateway) CreateNsxvFirewallRule(firewallRuleConfig *types.EdgeFirewallRule, aboveRuleId string) (*types.EdgeFirewallRule, error) { 34 if err := validateCreateNsxvFirewallRule(firewallRuleConfig, egw); err != nil { 35 return nil, err 36 } 37 38 params := make(map[string]string) 39 if aboveRuleId != "" { 40 params["aboveRuleId"] = aboveRuleId 41 } 42 43 // Wrap the provided rule for POST request 44 firewallRuleRequest := requestEdgeFirewallRules{ 45 EdgeFirewallRules: []*types.EdgeFirewallRule{firewallRuleConfig}, 46 } 47 48 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateFirewallPath) 49 if err != nil { 50 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 51 } 52 // We expect to get http.StatusCreated or if not an error of type types.NSXError 53 // The query must be wrapped differently, depending if it mus specify the "aboveRuleId" parameter 54 var resp *http.Response 55 if aboveRuleId == "" { 56 resp, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPost, types.AnyXMLMime, 57 "error creating firewall rule: %s", firewallRuleRequest, &types.NSXError{}) 58 } else { 59 errString := fmt.Sprintf("error creating firewall rule (aboveRuleId: %s): %%s", aboveRuleId) 60 resp, err = egw.client.ExecuteParamRequestWithCustomError(httpPath, params, http.MethodPost, types.AnyXMLMime, 61 errString, firewallRuleConfig, &types.NSXError{}) 62 } 63 if err != nil { 64 return nil, err 65 } 66 67 // Location header should look similar to: 68 // [/network/edges/edge-1/firewall/config/rules/197157] 69 firewallRuleId, err := extractNsxObjectIdFromPath(resp.Header.Get("Location")) 70 if err != nil { 71 return nil, err 72 } 73 74 readFirewallRule, err := egw.GetNsxvFirewallRuleById(firewallRuleId) 75 if err != nil { 76 return nil, fmt.Errorf("unable to retrieve firewall rule with ID (%s) after creation: %s", 77 firewallRuleId, err) 78 } 79 return readFirewallRule, nil 80 } 81 82 // UpdateNsxvFirewallRule updates types.EdgeFirewallRule with all fields using proxied NSX-V API. 83 // Real firewall rule ID (not the number shown in UI) is mandatory to perform the update. 84 func (egw *EdgeGateway) UpdateNsxvFirewallRule(firewallRuleConfig *types.EdgeFirewallRule) (*types.EdgeFirewallRule, error) { 85 err := validateUpdateNsxvFirewallRule(firewallRuleConfig, egw) 86 if err != nil { 87 return nil, err 88 } 89 90 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateFirewallPath + "/" + firewallRuleConfig.ID) 91 if err != nil { 92 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 93 } 94 95 // Result is either 204 for success, or an error of type types.NSXError 96 _, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime, 97 "error while updating firewall rule : %s", firewallRuleConfig, &types.NSXError{}) 98 if err != nil { 99 return nil, err 100 } 101 102 readFirewallRule, err := egw.GetNsxvFirewallRuleById(firewallRuleConfig.ID) 103 if err != nil { 104 return nil, fmt.Errorf("unable to retrieve firewall rule with ID (%s) after update: %s", 105 readFirewallRule.ID, err) 106 } 107 return readFirewallRule, nil 108 } 109 110 // GetNsxvFirewallRuleById retrieves types.EdgeFirewallRule by real (not the number shown in UI) 111 // firewall rule ID as shown in the UI using proxied NSX-V API. 112 // It returns and error `ErrorEntityNotFound` if the firewall rule is not found 113 func (egw *EdgeGateway) GetNsxvFirewallRuleById(id string) (*types.EdgeFirewallRule, error) { 114 if err := validateGetNsxvFirewallRule(id, egw); err != nil { 115 return nil, err 116 } 117 118 edgeFirewallRules, err := egw.GetAllNsxvFirewallRules() 119 if err != nil { 120 return nil, err 121 } 122 123 util.Logger.Printf("[DEBUG] Searching for firewall rule with ID: %s", id) 124 for _, rule := range edgeFirewallRules { 125 util.Logger.Printf("[DEBUG] Checking rule: %#+v", rule) 126 if rule.ID != "" && rule.ID == id { 127 return rule, nil 128 } 129 } 130 131 return nil, ErrorEntityNotFound 132 } 133 134 // GetAllNsxvFirewallRules retrieves all firewall rules and returns []*types.EdgeFirewallRule or an 135 // error of type ErrorEntityNotFound if there are no firewall rules 136 func (egw *EdgeGateway) GetAllNsxvFirewallRules() ([]*types.EdgeFirewallRule, error) { 137 if !egw.HasAdvancedNetworking() { 138 return nil, fmt.Errorf("only advanced edge gateways support firewall rules") 139 } 140 141 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeFirewallPath) 142 if err != nil { 143 return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 144 } 145 146 firewallRuleResponse := &responseEdgeFirewallRules{} 147 148 // This query returns all application rules as the API does not have filtering options 149 _, err = egw.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime, 150 "unable to read firewall rules: %s", nil, firewallRuleResponse) 151 if err != nil { 152 return nil, err 153 } 154 155 if len(firewallRuleResponse.EdgeFirewallRules.EdgeFirewallRules) == 0 { 156 return nil, ErrorEntityNotFound 157 } 158 159 return firewallRuleResponse.EdgeFirewallRules.EdgeFirewallRules, nil 160 } 161 162 // DeleteNsxvFirewallRuleById deletes types.EdgeFirewallRule by real (not the number shown in UI) 163 // firewall rule ID as shown in the UI using proxied NSX-V API. 164 // It returns and error `ErrorEntityNotFound` if the firewall rule is not found. 165 func (egw *EdgeGateway) DeleteNsxvFirewallRuleById(id string) error { 166 err := validateDeleteNsxvFirewallRule(id, egw) 167 if err != nil { 168 return err 169 } 170 171 httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeCreateFirewallPath + "/" + id) 172 if err != nil { 173 return fmt.Errorf("could not get Edge Gateway API endpoint: %s", err) 174 } 175 176 // check if the rule exists and pass back the error at it may be 'ErrorEntityNotFound' 177 _, err = egw.GetNsxvFirewallRuleById(id) 178 if err != nil { 179 return err 180 } 181 182 _, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime, 183 "unable to delete firewall rule: %s", nil, &types.NSXError{}) 184 if err != nil { 185 return err 186 } 187 188 return nil 189 } 190 191 func validateCreateNsxvFirewallRule(firewallRuleConfig *types.EdgeFirewallRule, egw *EdgeGateway) error { 192 if !egw.HasAdvancedNetworking() { 193 return fmt.Errorf("only advanced edge gateways support firewall rules") 194 } 195 196 if firewallRuleConfig.Action == "" { 197 return fmt.Errorf("firewall rule must have action specified") 198 } 199 200 return nil 201 } 202 203 func validateUpdateNsxvFirewallRule(firewallRuleConfig *types.EdgeFirewallRule, egw *EdgeGateway) error { 204 if firewallRuleConfig.ID == "" { 205 return fmt.Errorf("firewall rule ID must be set for update") 206 } 207 208 return validateCreateNsxvFirewallRule(firewallRuleConfig, egw) 209 } 210 211 func validateGetNsxvFirewallRule(id string, egw *EdgeGateway) error { 212 if !egw.HasAdvancedNetworking() { 213 return fmt.Errorf("only advanced edge gateways support firewall rules") 214 } 215 216 if id == "" { 217 return fmt.Errorf("unable to retrieve firewall rule without ID") 218 } 219 220 return nil 221 } 222 223 func validateDeleteNsxvFirewallRule(id string, egw *EdgeGateway) error { 224 return validateGetNsxvFirewallRule(id, egw) 225 }