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