Revision 2522e489
b/Changelog | ||
---|---|---|
41 | 41 |
* Compute quotas for CPU and memory of running vms. |
42 | 42 |
* Obsolete PUBLIC_USE_POOL setting, since Cyclades manages IP pool for all |
43 | 43 |
type of networks. |
44 |
* Extend servers info API respones with 'SNF:fqdn' attribute, and introduce
|
|
44 |
* Extend servers info API response with 'SNF:fqdn' attribute, and introduce
|
|
45 | 45 |
CYCLADES_SERVERS_FQDN to set the template for servers FDQN. |
46 |
* Extend servers info API response with 'SNF:port_forwarding' attribute, |
|
47 |
describing port fowarding rules (DNAT) that are applied to vms. The |
|
48 |
description of such rules is done via the new CYCLADES_PORT_FORWARDING |
|
49 |
setting. |
|
46 | 50 |
|
47 | 51 |
Pithos |
48 | 52 |
------ |
b/snf-cyclades-app/conf/20-snf-cyclades-app-api.conf | ||
---|---|---|
112 | 112 |
## the id of the VM. If set to 'None' the first public IPv4 or IPv6 address |
113 | 113 |
## of the VM will be used. |
114 | 114 |
#CYCLADES_SERVERS_FQDN = 'snf-%(id)s.vm.example.synnefo.org' |
115 |
# |
|
116 |
## Description of applied port forwarding rules (DNAT) for Cyclades VMs. This |
|
117 |
## setting contains a mapping from the port of each VM to a tuple contaning the |
|
118 |
## destination IP/hostname and the new port: (host, port). Instead of a tuple a |
|
119 |
## python callable object may be used which must return such a tuple. The caller |
|
120 |
## will pass to the callable the following positional arguments, in the |
|
121 |
## following order: |
|
122 |
## * server_id: The ID of the VM in the DB |
|
123 |
## * ip_address: The IPv4 address of the public VM NIC |
|
124 |
## * fqdn: The FQDN of the VM |
|
125 |
## * user: The UUID of the owner of the VM |
|
126 |
## |
|
127 |
## Here is an example describing the mapping of the SSH port of all VMs to |
|
128 |
## the external address 'gate.example.synnefo.org' and port 60000+server_id. |
|
129 |
## e.g. iptables -t nat -A prerouting -d gate.example.synnefo.org \ |
|
130 |
## --dport (61000 # $(VM_ID)) -j DNAT --to-destination $(VM_IP):22 |
|
131 |
##CYCLADES_PORT_FORWARDING = { |
|
132 |
## 22: lambda ip_address, server_id, fqdn, user: |
|
133 |
## ("gate.example.synnefo.org", 61000 + server_id), |
|
134 |
##} |
|
135 |
#CYCLADES_PORT_FORWARDING = {} |
b/snf-cyclades-app/synnefo/api/servers.py | ||
---|---|---|
170 | 170 |
d["config_drive"] = "" |
171 | 171 |
d["accessIPv4"] = "" |
172 | 172 |
d["accessIPv6"] = "" |
173 |
d["SNF:fqdn"] = get_server_fqdn(vm) |
|
173 |
fqdn = get_server_fqdn(vm) |
|
174 |
d["SNF:fqdn"] = fqdn |
|
175 |
d["SNF:port_forwarding"] = get_server_port_forwarding(vm, fqdn) |
|
174 | 176 |
|
175 | 177 |
return d |
176 | 178 |
|
... | ... | |
196 | 198 |
raise faults.InternalServerError(msg) |
197 | 199 |
|
198 | 200 |
|
201 |
def get_server_port_forwarding(vm, fqdn): |
|
202 |
"""Create API 'port_forwarding' attribute from corresponding setting. |
|
203 |
|
|
204 |
Create the 'port_forwarding' API vm attribute based on the corresponding |
|
205 |
setting (CYCLADES_PORT_FORWARDING), which can be either a tuple |
|
206 |
of the form (host, port) or a callable object returning such tuple. In |
|
207 |
case of callable object, must be called with the following arguments: |
|
208 |
* ip_address |
|
209 |
* server_id |
|
210 |
* fqdn |
|
211 |
* owner UUID |
|
212 |
|
|
213 |
""" |
|
214 |
port_forwarding = {} |
|
215 |
for dport, to_dest in settings.CYCLADES_PORT_FORWARDING.items(): |
|
216 |
if hasattr(to_dest, "__call__"): |
|
217 |
public_nics = vm.nics.filter(network__public=True, state="ACTIVE")\ |
|
218 |
.exclude(ipv4=None).order_by('index') |
|
219 |
if public_nics: |
|
220 |
vm_ipv4 = public_nics[0].ipv4 |
|
221 |
else: |
|
222 |
vm_ipv4 = None |
|
223 |
to_dest = to_dest(vm_ipv4, vm.id, fqdn, vm.userid) |
|
224 |
msg = ("Invalid setting: CYCLADES_PORT_FOWARDING." |
|
225 |
" Value must be a tuple of two elements (host, port).") |
|
226 |
if to_dest is None: |
|
227 |
continue |
|
228 |
if not isinstance(to_dest, tuple) or len(to_dest) != 2: |
|
229 |
raise faults.InternalServerError(msg) |
|
230 |
else: |
|
231 |
try: |
|
232 |
host, port = to_dest |
|
233 |
except (TypeError, ValueError): |
|
234 |
raise faults.InternalServerError(msg) |
|
235 |
|
|
236 |
port_forwarding[dport] = {"host": host, "port": str(port)} |
|
237 |
return port_forwarding |
|
238 |
|
|
239 |
|
|
199 | 240 |
def diagnostics_to_dict(diagnostics): |
200 | 241 |
""" |
201 | 242 |
Extract api data from diagnostics QuerySet. |
b/snf-cyclades-app/synnefo/api/tests/servers.py | ||
---|---|---|
202 | 202 |
server = json.loads(response.content)['server'] |
203 | 203 |
self.assertEqual(server["SNF:fqdn"], nic.ipv4) |
204 | 204 |
|
205 |
def test_server_port_forwarding(self): |
|
206 |
vm = mfactory.VirtualMachineFactory() |
|
207 |
ports = { |
|
208 |
22: ("foo", 61000), |
|
209 |
80: lambda ip, id, fqdn, user: ("bar", 61001)} |
|
210 |
with override_settings(settings, |
|
211 |
CYCLADES_PORT_FORWARDING=ports): |
|
212 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
|
213 |
server = json.loads(response.content)['server'] |
|
214 |
self.assertEqual(server["SNF:port_forwarding"], |
|
215 |
{"22": {"host": "foo", "port": "61000"}, |
|
216 |
"80": {"host": "bar", "port": "61001"}}) |
|
217 |
|
|
218 |
def _port_from_ip(ip, base): |
|
219 |
fields = ip.split('.', 4) |
|
220 |
return (base + 256*int(fields[2]) + int(fields[3])) |
|
221 |
|
|
222 |
ports = { |
|
223 |
22: lambda ip, id, fqdn, user: |
|
224 |
ip and ("gate", _port_from_ip(ip, 10000)) or None} |
|
225 |
with override_settings(settings, |
|
226 |
CYCLADES_PORT_FORWARDING=ports): |
|
227 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
|
228 |
server = json.loads(response.content)['server'] |
|
229 |
self.assertEqual(server["SNF:port_forwarding"], {}) |
|
230 |
|
|
231 |
mfactory.NetworkInterfaceFactory(machine=vm, ipv4="192.168.2.2", |
|
232 |
network__public=True) |
|
233 |
with override_settings(settings, |
|
234 |
CYCLADES_PORT_FORWARDING=ports): |
|
235 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
|
236 |
server = json.loads(response.content)['server'] |
|
237 |
self.assertEqual(server["SNF:port_forwarding"], |
|
238 |
{"22": {"host": "gate", "port": "10514"}}) |
|
239 |
|
|
205 | 240 |
def test_server_building_nics(self): |
206 | 241 |
db_vm = self.vm2 |
207 | 242 |
user = self.vm2.userid |
b/snf-cyclades-app/synnefo/app_settings/default/api.py | ||
---|---|---|
112 | 112 |
# the id of the VM. If set to 'None' the first public IPv4 or IPv6 address |
113 | 113 |
# of the VM will be used. |
114 | 114 |
CYCLADES_SERVERS_FQDN = 'snf-%(id)s.vm.example.synnefo.org' |
115 |
|
|
116 |
# Description of applied port forwarding rules (DNAT) for Cyclades VMs. This |
|
117 |
# setting contains a mapping from the port of each VM to a tuple contaning the |
|
118 |
# destination IP/hostname and the new port: (host, port). Instead of a tuple a |
|
119 |
# python callable object may be used which must return such a tuple. The caller |
|
120 |
# will pass to the callable the following positional arguments, in the |
|
121 |
# following order: |
|
122 |
# * server_id: The ID of the VM in the DB |
|
123 |
# * ip_address: The IPv4 address of the public VM NIC |
|
124 |
# * fqdn: The FQDN of the VM |
|
125 |
# * user: The UUID of the owner of the VM |
|
126 |
# |
|
127 |
# Here is an example describing the mapping of the SSH port of all VMs to |
|
128 |
# the external address 'gate.example.synnefo.org' and port 60000+server_id. |
|
129 |
# e.g. iptables -t nat -A prerouting -d gate.example.synnefo.org \ |
|
130 |
# --dport (61000 + $(VM_ID)) -j DNAT --to-destination $(VM_IP):22 |
|
131 |
#CYCLADES_PORT_FORWARDING = { |
|
132 |
# 22: lambda ip_address, server_id, fqdn, user: |
|
133 |
# ("gate.example.synnefo.org", 61000 + server_id), |
|
134 |
#} |
|
135 |
CYCLADES_PORT_FORWARDING = {} |
Also available in: Unified diff