Skip to content

Commit 47b52d2

Browse files
committed
ZStack EIP and PortForwarding Support
1 parent 34a521f commit 47b52d2

2 files changed

Lines changed: 396 additions & 6 deletions

File tree

zstack/networkservice.go

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
package zstack
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
"strings"
9+
"time"
10+
11+
"github.com/Sirupsen/logrus"
12+
"github.com/cnrancher/go-zstack/common"
13+
"github.com/pkg/errors"
14+
)
15+
16+
const (
17+
vipURI = "/zstack/v1/vips"
18+
deleteVipURI = "/zstack/v1/vips/{uuid}"
19+
deleteInstanceURI = "/zstack/v1/vm-instances/{uuid}"
20+
portForwardRuleURI = "/zstack/v1/port-forwarding"
21+
eipURI = "/zstack/v1/eips"
22+
)
23+
24+
//CreatePortForwardRuleRequest struct
25+
type CreatePortForwardRuleRequest struct {
26+
CreatePortForwardRuleContent map[string]string `json:"params,omitempty"`
27+
Tags common.Tags `json:",inline"`
28+
}
29+
30+
//PortForwardRule struct
31+
type PortForwardRule struct {
32+
UUID string `json:"uuid,omitempty"`
33+
Name string `json:"name,omitempty"`
34+
Description string `json:"description,omitempty"`
35+
VIPIP string `json:"vipIp,omitempty"`
36+
GuestIP string `json:"guestIp,omitempty"`
37+
VipUUID string `json:"vipUuid,omitempty"`
38+
VipPortStart uint16 `json:"vipPortStart,omitempty"`
39+
VipPortEnd uint16 `json:"vipPortEnd,omitempty"`
40+
PrivatePortStart uint16 `json:"privatePortStart,omitempty"`
41+
PrivatePortEnd uint16 `json:"privatePortEnd,omitempty"`
42+
VMNicUUID string `json:"vmNicUuid,omitempty"`
43+
ProtocolType string `json:"protocolType,omitempty"`
44+
State string `json:"state,omitempty"`
45+
AllowedCidr string `json:"allowedCidr,omitempty"`
46+
CreateDate string `json:"createDate,omitempty"`
47+
LastOpDate string `json:"lastOpDate,omitempty"`
48+
}
49+
50+
//CreatePortForwardRuleResponse struct
51+
type CreatePortForwardRuleResponse struct {
52+
Error *common.Error `json:"error,omitempty"`
53+
Inventory PortForwardRule `json:"inventory,omitempty"`
54+
}
55+
56+
//QueryPortForwardRulesResponse struct
57+
type QueryPortForwardRulesResponse struct {
58+
Error *common.Error `json:"error,omitempty"`
59+
Inventories []PortForwardRule `json:"inventories,omitempty"`
60+
}
61+
62+
//CreateVipRequest struct
63+
type CreateVipRequest struct {
64+
CreateVipContent map[string]string `json:"params,omitempty"`
65+
Tags common.Tags `json:",inline"`
66+
}
67+
68+
//VipRule struct
69+
type VipRule struct {
70+
UUID string `json:"uuid,omitempty"`
71+
Name string `json:"name,omitempty"`
72+
Description string `json:"description,omitempty"`
73+
L3NetworkUUID string `json:"l3NetworkUuid,omitempty"`
74+
IP string `json:"ip,omitempty"`
75+
State string `json:"state,omitempty"`
76+
Gateway string `json:"gateway,omitempty"`
77+
Netmask string `json:"netmask,omitempty"`
78+
ServiceProvider string `json:"serviceProvider,omitempty"`
79+
PeerL3NetworkUUID []string `json:"peerL3NetworkUuid,omitempty"`
80+
UseFor string `json:"useFor,omitempty"`
81+
CreateDate string `json:"createDate,omitempty"`
82+
LastOpDate string `json:"lastOpDate,omitempty"`
83+
}
84+
85+
//CreateVipResponse struct
86+
type CreateVipResponse struct {
87+
Error *common.Error `json:"error,omitempty"`
88+
Inventory VipRule `json:"inventory,omitempty"`
89+
}
90+
91+
//VipResponses struct
92+
type VipResponses struct {
93+
Error *common.Error `json:"error,omitempty"`
94+
Inventories []VipRule `json:"inventories,omitempty"`
95+
}
96+
97+
//CreateEipRequest struct
98+
type CreateEipRequest struct {
99+
CreateEipContent map[string]string `json:"params,omitempty"`
100+
Tags common.Tags `json:",inline"`
101+
}
102+
103+
//CreateEipResponse struct
104+
type CreateEipResponse struct {
105+
Error *common.Error `json:"error,omitempty"`
106+
Inventory struct {
107+
UUID string `json:"uuid,omitempty"`
108+
Name string `json:"name,omitempty"`
109+
Description string `json:"description,omitempty"`
110+
VMNicUUID string `json:"vmNicUuid,omitempty"`
111+
VipUUID string `json:"vipUuid,omitempty"`
112+
CreateDate string `json:"createDate,omitempty"`
113+
LastOpDate string `json:"lastOpDate,omitempty"`
114+
State string `json:"state,omitempty"`
115+
VipIP string `json:"vipIp,omitempty"`
116+
GuestIP string `json:"guestIp,omitempty"`
117+
} `json:"inventory,omitempty"`
118+
}
119+
120+
//CreateEip will map created public vip to vm private ip
121+
func (d *Driver) CreateEip(vipuuid string, vmnicuuid string) error {
122+
d.initClients()
123+
eip := CreateEipRequest{
124+
CreateEipContent: map[string]string{
125+
"name": "eip-for-rancher-" + d.InstanceUUID,
126+
"vipUuid": vipuuid,
127+
"vmNicUuid": vmnicuuid,
128+
},
129+
Tags: common.Tags{
130+
SystemTags: []string{},
131+
UserTags: []string{},
132+
},
133+
}
134+
requestBody, _ := json.Marshal(eip)
135+
resp, err := d.getInstanceClient().CreateRequestWithURI(http.MethodPost, eipURI, requestBody)
136+
137+
if err != nil {
138+
return err
139+
}
140+
141+
async, err := common.GetAsyncResponse(d.client, resp)
142+
responseStruct := CreateEipResponse{}
143+
144+
if err = async.QueryRealResponse(&responseStruct, 60*time.Second); err != nil {
145+
return errors.Wrap(err, "Get error when query response for zstack create EIP job.")
146+
}
147+
if responseStruct.Error != nil {
148+
return errors.Wrap(responseStruct.Error.WrapError(), "Get error when create zstack EIP.")
149+
}
150+
return nil
151+
}
152+
153+
//CreateVip will create a public vip from provided public L3 network pool
154+
func (d *Driver) CreateVip() (string, string, error) {
155+
d.initClients()
156+
vip := CreateVipRequest{
157+
CreateVipContent: map[string]string{
158+
"name": "vip-for-rancher-" + d.InstanceUUID,
159+
"l3NetworkUuid": d.PublicL3NetworkUUID,
160+
},
161+
Tags: common.Tags{
162+
SystemTags: []string{},
163+
UserTags: []string{},
164+
},
165+
}
166+
requestBody, _ := json.Marshal(vip)
167+
168+
resp, err := d.getInstanceClient().CreateRequestWithURI(http.MethodPost, vipURI, requestBody)
169+
170+
if err != nil {
171+
return "", "", err
172+
}
173+
174+
async, err := common.GetAsyncResponse(d.client, resp)
175+
responseStruct := CreateVipResponse{}
176+
177+
if err = async.QueryRealResponse(&responseStruct, 60*time.Second); err != nil {
178+
return "", "", errors.Wrap(err, "Get error when query response for zstack create VIP job.")
179+
}
180+
if responseStruct.Error != nil {
181+
return "", "", errors.Wrap(responseStruct.Error.WrapError(), "Get error when delete zstack VIP.")
182+
}
183+
return responseStruct.Inventory.IP, responseStruct.Inventory.UUID, nil
184+
}
185+
186+
//DeleteVip will delete public vip and related EIP and/or Portforwarding rules
187+
func (d *Driver) DeleteVip() error {
188+
d.initClients()
189+
// _, publicipv4uuid, err := d.QueryVipIPUUID()
190+
// if err != nil {
191+
// return err
192+
// }
193+
194+
if d.PublicIPv4UUID == "" {
195+
return errors.New("PublicIPv4UUID is empty")
196+
}
197+
198+
realURI := strings.Replace(deleteVipURI, "{uuid}", d.PublicIPv4UUID, -1)
199+
resp, err := d.getInstanceClient().CreateRequestWithURI(http.MethodDelete, realURI, nil)
200+
if err != nil {
201+
return err
202+
}
203+
204+
async, err := common.GetAsyncResponse(d.client, resp)
205+
responseStruct := CreateVipResponse{}
206+
207+
if err = async.QueryRealResponse(&responseStruct, 60*time.Second); err != nil {
208+
return errors.Wrap(err, "Get error when query response for zstack delete vip job.")
209+
}
210+
if responseStruct.Error != nil {
211+
return errors.Wrap(responseStruct.Error.WrapError(), "Get error when delete zstack vip.")
212+
}
213+
return nil
214+
}
215+
216+
//CreatePortForwardRule will create a tcp or udp port forward rule from port 1 to 65535
217+
func (d *Driver) CreatePortForwardRule(vipuuid string, vmnicuuid string, proto string) error {
218+
d.initClients()
219+
portforward := CreatePortForwardRuleRequest{
220+
CreatePortForwardRuleContent: map[string]string{
221+
"vipUuid": vipuuid,
222+
"vipPortStart": "1",
223+
"vipPortEnd": "65535",
224+
"privatePortStart": "1",
225+
"privatePortEnd": "65535",
226+
"protocolType": proto,
227+
"vmNicUuid": vmnicuuid,
228+
"name": "pf-for-rancher-" + proto + "-" + d.InstanceUUID,
229+
},
230+
Tags: common.Tags{
231+
SystemTags: []string{},
232+
UserTags: []string{},
233+
},
234+
}
235+
requestBody, _ := json.Marshal(portforward)
236+
resp, err := d.getInstanceClient().CreateRequestWithURI(http.MethodPost, portForwardRuleURI, requestBody)
237+
if err != nil {
238+
return err
239+
}
240+
responseStruct := CreatePortForwardRuleResponse{}
241+
async, err := common.GetAsyncResponse(d.client, resp)
242+
243+
if err = async.QueryRealResponse(&responseStruct, 60*time.Second); err != nil {
244+
return errors.Wrap(err, "Get error when query response for zstack create portforward rules.")
245+
}
246+
if responseStruct.Error != nil {
247+
return errors.Wrap(responseStruct.Error.WrapError(), "Get error when create portforward rules.")
248+
}
249+
return nil
250+
}
251+
252+
//QueryVipIPUUID will return vip and its uuid of current instance
253+
func (d *Driver) QueryVipIPUUID() (string, string, error) {
254+
d.initClients()
255+
inventory, err := d.getInstanceClient().QueryInstance(d.InstanceUUID)
256+
if err != nil {
257+
return "", "", err
258+
}
259+
if len(inventory.VMNics) == 0 {
260+
return "", "", fmt.Errorf("Nics not found")
261+
}
262+
GuestIP := inventory.VMNics[0].IP
263+
var realURI string
264+
265+
if strings.ToLower(d.PublicL3NetworkMode) == "portforward" {
266+
realURI = fmt.Sprintf("%s?q=portForwarding.guestIp=%s", vipURI, GuestIP)
267+
} else if strings.ToLower(d.PublicL3NetworkMode) == "eip" {
268+
realURI = fmt.Sprintf("%s?q=eip.guestIp=%s", vipURI, GuestIP)
269+
} else {
270+
return "", "", fmt.Errorf("Unsupported network mode")
271+
}
272+
resp, err := d.getInstanceClient().CreateRequestWithURI(http.MethodGet, realURI, nil)
273+
if err != nil {
274+
return "", "", err
275+
}
276+
responseBody, err := ioutil.ReadAll(resp.Body)
277+
if err != nil {
278+
return "", "", err
279+
}
280+
responseStruct := VipResponses{}
281+
if err = json.Unmarshal(responseBody, &responseStruct); err != nil {
282+
logrus.Warnf("Unmarshaling response when Querying pf rules. Error: %s", err.Error())
283+
}
284+
if resp.StatusCode != 200 {
285+
if responseStruct.Error != nil {
286+
return "", "", responseStruct.Error.WrapError()
287+
}
288+
return "", "", fmt.Errorf("status code %d,Error massage %s", resp.StatusCode, string(responseBody))
289+
}
290+
if len(responseStruct.Inventories) > 0 {
291+
return responseStruct.Inventories[0].IP, responseStruct.Inventories[0].UUID, nil
292+
}
293+
return "", "", fmt.Errorf("Not any portforward rules")
294+
}

0 commit comments

Comments
 (0)