33
33
flags.DEFINE_integer('vpn_end_port', 2000,
34
34
'End port for the cloudpipe VPN servers')
36
37
class NoMorePorts(exception.Error):
38
"""No ports available to allocate for the given ip"""
67
69
return network_data
70
def find_free_port_for_ip(cls, ip):
72
def find_free_port_for_ip(cls, vpn_ip):
71
73
"""Finds a free port for a given ip from the redis set"""
72
74
# TODO(vish): these redis commands should be generalized and
73
75
# placed into a base class. Conceptually, it is
74
76
# similar to an association, but we are just
75
77
# storing a set of values instead of keys that
76
78
# should be turned into objects.
77
redis = datastore.Redis.instance()
78
key = 'ip:%s:ports' % ip
79
cls._ensure_set_exists(vpn_ip)
81
port = datastore.Redis.instance().spop(cls._redis_ports_key(vpn_ip))
87
def _redis_ports_key(cls, vpn_ip):
88
"""Key that ports are stored under in redis"""
89
return 'ip:%s:ports' % vpn_ip
92
def _ensure_set_exists(cls, vpn_ip):
93
"""Creates the set of ports for the ip if it doesn't already exist"""
79
94
# TODO(vish): these ports should be allocated through an admin
80
95
# command instead of a flag
81
if (not redis.exists(key) and
82
not redis.exists(cls._redis_association_name('ip', ip))):
96
redis = datastore.Redis.instance()
97
if (not redis.exists(cls._redis_ports_key(vpn_ip)) and
98
not redis.exists(cls._redis_association_name('ip', vpn_ip))):
83
99
for i in range(FLAGS.vpn_start_port, FLAGS.vpn_end_port + 1):
86
port = redis.spop(key)
100
redis.sadd(cls._redis_ports_key(vpn_ip), i)
92
def num_ports_for_ip(cls, ip):
103
def num_ports_for_ip(cls, vpn_ip):
93
104
"""Calculates the number of free ports for a given ip"""
94
return datastore.Redis.instance().scard('ip:%s:ports' % ip)
105
cls._ensure_set_exists(vpn_ip)
106
return datastore.Redis.instance().scard('ip:%s:ports' % vpn_ip)
109
def ip(self): # pylint: disable=C0103
98
110
"""The ip assigned to the project"""