Skip to content

Commit 1feb060

Browse files
committed
Add lb listener & backend class
1 parent 1ec0f64 commit 1feb060

File tree

6 files changed

+293
-5
lines changed

6 files changed

+293
-5
lines changed

qingcloud/iaas/connection.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,10 +1668,10 @@ def modify_loadbalancer_listener_attributes(self, loadbalancer_listener,
16681668
16691669
@param loadbalancer_listener: the ID of listener.
16701670
@param loadbalancer_listener_name: the name of the listener.
1671-
@param balance_mode: defined in constants.py
1671+
@param balance_mode: defined in constants.py,
16721672
BALANCE_ROUNDROBIN, BALANCE_LEASTCONN
1673-
@param forwardfor: extra http headers, represented as bitwise flag
1674-
HEADER_QC_LB_IP, HEADER_QC_LB_ID, HEADER_X_FORWARD_FOR.
1673+
@param forwardfor: extra http headers, represented as bitwise flag defined in constants.py,
1674+
HEADER_QC_LB_IP, HEADER_QC_LB_ID and HEADER_X_FORWARD_FOR.
16751675
Example: if you need X-Forwarded-For and QC-LB-IP in http header,
16761676
then forwardfor should be HEADER_X_FORWARD_FOR | HEADER_QC_LB_IP.
16771677
@param description: the description of the listener.

qingcloud/iaas/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,5 @@
132132
BALANCE_ROUNDROBIN = "roundrobin"
133133
BALANCE_LEASTCONN = "leastconn"
134134
HEADER_X_FORWARD_FOR = 1
135-
HEADER_QC_LB_ID = 2
136-
HEADER_QC_LB_IP = 4
135+
HEADER_QC_LBID = 2
136+
HEADER_QC_LBIP = 4

qingcloud/iaas/lb_backend.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# =========================================================================
2+
# Copyright 2012-present Yunify, Inc.
3+
# -------------------------------------------------------------------------
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this work except in compliance with the License.
6+
# You may obtain a copy of the License in the LICENSE file, or at:
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# =========================================================================
16+
17+
import json
18+
19+
20+
class LoadBalancerBackend(object):
21+
""" LoadBalancerBackend is used to define backend in load balancer listener.
22+
"""
23+
resource_id = None
24+
loadbalancer_backend_name = None
25+
port = None
26+
weight = None
27+
28+
def __init__(self, resource_id, port, weight=1,
29+
loadbalancer_backend_id=None, loadbalancer_backend_name=None,
30+
**kw):
31+
self.resource_id = resource_id
32+
self.port = port
33+
self.weight = weight
34+
self.loadbalancer_backend_name = loadbalancer_backend_name
35+
if loadbalancer_backend_id:
36+
self.loadbalancer_backend_id = loadbalancer_backend_id
37+
38+
def __repr__(self):
39+
return '<%s>%s' % (self.__class__.__name__, self.to_json())
40+
41+
@classmethod
42+
def create_from_string(cls, string):
43+
""" Create load balancer backend from json formatted string.
44+
"""
45+
if not isinstance(string, basestring):
46+
return string
47+
data = json.loads(string)
48+
if isinstance(data, dict):
49+
return cls(**data)
50+
if isinstance(data, list):
51+
return [cls(**item) for item in data]
52+
53+
def to_json(self):
54+
return {
55+
'resource_id': self.resource_id,
56+
'loadbalancer_backend_name': self.loadbalancer_backend_name,
57+
'port': self.port,
58+
'weight': self.weight,
59+
}

qingcloud/iaas/lb_listener.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# =========================================================================
2+
# Copyright 2012-present Yunify, Inc.
3+
# -------------------------------------------------------------------------
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this work except in compliance with the License.
6+
# You may obtain a copy of the License in the LICENSE file, or at:
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# =========================================================================
16+
17+
import json
18+
19+
from qingcloud.iaas.constants import HEADER_X_FORWARD_FOR, HEADER_QC_LBID, HEADER_QC_LBIP
20+
21+
HEADERS = {
22+
'X-FORWARD-FOR': HEADER_X_FORWARD_FOR,
23+
'QC-LBID': HEADER_QC_LBID,
24+
'QC-LBIP': HEADER_QC_LBIP,
25+
}
26+
27+
28+
class LoadBalancerListener(object):
29+
""" LoadBalancerListener is used to define listener in load balancer.
30+
"""
31+
loadbalancer_listener_id = None
32+
loadbalancer_listener_name = None
33+
listener_port = None
34+
listener_protocol = None
35+
backend_protocol = None
36+
balance_mode = None
37+
forwardfor = None
38+
session_sticky = None
39+
healthy_check_method = None
40+
healthy_check_option = None
41+
42+
def __init__(self, listener_port, listener_protocol, backend_protocol,
43+
balance_mode='roundrobin', forwardfor=None, headers=None, session_sticky='',
44+
healthy_check_method='tcp', healthy_check_option='10|5|2|5',
45+
loadbalancer_listener_name=None, loadbalancer_listener_id=None,
46+
**kw):
47+
self.listener_port = listener_port
48+
self.listener_protocol = listener_protocol
49+
self.backend_protocol = backend_protocol
50+
self.balance_mode = balance_mode
51+
self.forwardfor = forwardfor or LoadBalancerListener.get_forwardfor(headers)
52+
self.session_sticky = session_sticky
53+
self.healthy_check_method = healthy_check_method
54+
self.healthy_check_option = healthy_check_option
55+
self.loadbalancer_listener_name = loadbalancer_listener_name
56+
if loadbalancer_listener_id:
57+
self.loadbalancer_listener_id = loadbalancer_listener_id
58+
59+
def __repr__(self):
60+
return '<%s>%s' % (self.__class__.__name__, self.to_json())
61+
62+
@staticmethod
63+
def get_forwardfor(headers):
64+
""" Get forwardfor from header array.
65+
"""
66+
if not headers:
67+
return 0
68+
69+
forwardfor = 0
70+
for head in headers:
71+
if head in HEADERS:
72+
forwardfor |= HEADERS[head]
73+
return forwardfor
74+
75+
@classmethod
76+
def create_from_string(cls, string):
77+
""" Create load balancer listener from json formatted string.
78+
"""
79+
if not isinstance(string, basestring):
80+
return string
81+
data = json.loads(string)
82+
if isinstance(data, dict):
83+
return cls(**data)
84+
if isinstance(data, list):
85+
return [cls(**item) for item in data]
86+
87+
def to_json(self):
88+
return {
89+
'loadbalancer_listener_name': self.loadbalancer_listener_name,
90+
'listener_port': self.listener_port,
91+
'listener_protocol': self.listener_protocol,
92+
'backend_protocol': self.backend_protocol,
93+
'balance_mode': self.balance_mode,
94+
'forwardfor': self.forwardfor,
95+
'session_sticky': self.session_sticky,
96+
'healthy_check_method': self.healthy_check_method,
97+
'healthy_check_option': self.healthy_check_option,
98+
}

tests/test_lb_backend.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# =========================================================================
2+
# Copyright 2012-present Yunify, Inc.
3+
# -------------------------------------------------------------------------
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this work except in compliance with the License.
6+
# You may obtain a copy of the License in the LICENSE file, or at:
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# =========================================================================
16+
17+
import unittest
18+
19+
from qingcloud.iaas.lb_backend import LoadBalancerBackend
20+
21+
class LoadBalancerBackendTestCase(unittest.TestCase):
22+
23+
def test_init_backend(self):
24+
port = 443
25+
weight = 12
26+
backend = LoadBalancerBackend('i-test1234', port, weight)
27+
self.assertEqual(backend.to_json()['port'], port)
28+
self.assertEqual(backend.to_json()['weight'], weight)
29+
30+
def test_create_from_string(self):
31+
string = '''
32+
[{"status":"down","loadbalancer_backend_id":"lbb-rruzir3s","weight":1,
33+
"resource_id":"i-1234abcd","loadbalancer_backend_name":"",
34+
"port":23,"controller":"self", "create_time":"2014-02-03T17:12:03Z",
35+
"owner":"usr-1234abcd", "loadbalancer_listener_id":"lbl-1234abcd",
36+
"loadbalancer_id":"lb-1234abcd"},
37+
{"status":"down","loadbalancer_backend_id":"lbb-vz51avzj","weight":1,
38+
"resource_id":"i-1234abcd","loadbalancer_backend_name":"",
39+
"port":3,"controller":"self","create_time":"2014-02-03T17:12:07Z",
40+
"owner":"usr-1234abcd","loadbalancer_listener_id":"lbl-1234abcd",
41+
"loadbalancer_id":"lb-1234abcd"}]
42+
'''
43+
backends = LoadBalancerBackend.create_from_string(string)
44+
self.assertEqual(len(backends), 2)

tests/test_lb_listener.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# =========================================================================
2+
# Copyright 2012-present Yunify, Inc.
3+
# -------------------------------------------------------------------------
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this work except in compliance with the License.
6+
# You may obtain a copy of the License in the LICENSE file, or at:
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# =========================================================================
16+
17+
import unittest
18+
19+
from qingcloud.iaas.lb_listener import LoadBalancerListener
20+
21+
class LoadBalancerListenerTestCase(unittest.TestCase):
22+
23+
def test_init_instance(self):
24+
port = 80
25+
protocol = 'http'
26+
listener = LoadBalancerListener(port, listener_protocol=protocol,
27+
backend_protocol=protocol)
28+
json = listener.to_json()
29+
self.assertEqual(json['listener_port'], port)
30+
self.assertEqual(json['listener_protocol'], protocol)
31+
32+
def test_init_forwardfor(self):
33+
port = 80
34+
protocol = 'http'
35+
listener = LoadBalancerListener(port, listener_protocol=protocol,
36+
backend_protocol=protocol, forwardfor=1)
37+
json = listener.to_json()
38+
self.assertEqual(json['forwardfor'], 1)
39+
40+
listener = LoadBalancerListener(port, listener_protocol=protocol,
41+
backend_protocol=protocol, headers=['QC-LBIP'])
42+
json = listener.to_json()
43+
self.assertEqual(json['forwardfor'], 4)
44+
45+
listener = LoadBalancerListener(port, listener_protocol=protocol,
46+
backend_protocol=protocol, forwardfor=1, headers=['QC-LBIP'])
47+
json = listener.to_json()
48+
self.assertEqual(json['forwardfor'], 1)
49+
50+
def test_get_forwardfor(self):
51+
headers = []
52+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 0)
53+
headers = ['wrong_header']
54+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 0)
55+
headers = ['X-FORWARD-FOR']
56+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 1)
57+
headers = ['QC-LBID']
58+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 2)
59+
headers = ['QC-LBIP']
60+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 4)
61+
headers = ['X-FORWARD-FOR', 'QC-LBID']
62+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 3)
63+
headers = ['X-FORWARD-FOR', 'QC-LBIP', 'QC-LBID']
64+
self.assertEqual(LoadBalancerListener.get_forwardfor(headers), 7)
65+
66+
def test_create_from_string(self):
67+
string = '''
68+
[{"forwardfor":0,"loadbalancer_listener_id":"lbl-1234abcd",
69+
"balance_mode":"roundrobin","listener_protocol":"tcp",
70+
"backend_protocol":"tcp","healthy_check_method":"tcp",
71+
"session_sticky":"","loadbalancer_listener_name":"demo",
72+
"controller":"self","backends":[],"create_time":"2014-02-02T16:51:25Z",
73+
"healthy_check_option":"10|5|2|5","owner":"usr-1234abcd",
74+
"console_id":"qingcloud","loadbalancer_id":"lb-1234abcd",
75+
"listener_port":443},
76+
{"forwardfor":0,
77+
"loadbalancer_listener_id":"lbl-1234abcd","balance_mode":"roundrobin",
78+
"listener_protocol":"http","backend_protocol":"http",
79+
"healthy_check_method":"tcp","session_sticky":"",
80+
"loadbalancer_listener_name":"demo","controller":"self",
81+
"backends":[],"create_time":"2014-02-02T16:51:19Z",
82+
"healthy_check_option":"10|5|2|5","owner":"usr-1234abcd",
83+
"console_id":"qingcloud","loadbalancer_id":"lb-1234abcd",
84+
"listener_port":80}]
85+
'''
86+
listeners = LoadBalancerListener.create_from_string(string)
87+
self.assertEqual(len(listeners), 2)

0 commit comments

Comments
 (0)