Revision 86961519
b/snf-cyclades-app/synnefo/api/management/commands/port-inspect.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
from datetime import datetime |
|
35 | 34 |
from optparse import make_option |
36 | 35 |
from django.core.management.base import BaseCommand, CommandError |
37 | 36 |
|
38 |
from synnefo.lib.utils import merge_time |
|
39 |
from snf_django.lib.astakos import UserCache |
|
40 | 37 |
from synnefo.logic.rapi import GanetiApiError |
41 |
from synnefo.management.common import Omit, convert_api_faults |
|
42 |
from synnefo.management import common |
|
43 |
from synnefo.settings import (CYCLADES_SERVICE_TOKEN as ASTAKOS_TOKEN, |
|
44 |
ASTAKOS_BASE_URL) |
|
45 |
|
|
38 |
from synnefo.management.common import convert_api_faults |
|
39 |
from synnefo.logic.reconciliation import nics_from_instance |
|
40 |
from snf_django.management.utils import pprint_table |
|
46 | 41 |
from synnefo.api.util import get_port |
42 |
|
|
43 |
|
|
47 | 44 |
class Command(BaseCommand): |
48 | 45 |
help = "Inspect a port on DB and Ganeti" |
49 | 46 |
args = "<port ID>" |
... | ... | |
71 | 68 |
port = get_port(args[0], None) |
72 | 69 |
|
73 | 70 |
sep = '-' * 80 + '\n' |
74 |
labels = ['name', 'id', 'device_id', 'network_id', |
|
75 |
'device_owner', 'mac_address', 'ipv4', 'subnet4', |
|
76 |
'ipv6', 'subnet6', 'state', |
|
77 |
'security_groups', 'user_id'] |
|
78 |
|
|
79 |
uuid = port.userid |
|
80 |
security_groups = port.security_groups.values_list('id', |
|
81 |
flat=True) |
|
82 |
sg_csv = ','.join(map(str, security_groups)) |
|
83 |
|
|
84 |
ipv4 = '' |
|
85 |
ipv6 = '' |
|
86 |
subnet4 = '' |
|
87 |
subnet6 = '' |
|
88 |
for ip in port.ips.all(): |
|
89 |
if ip.subnet.ipversion == 4: |
|
90 |
ipv4 = ip.address |
|
91 |
subnet4 = str(ip.subnet.id) |
|
92 |
else: |
|
93 |
ipv6 = ip.address |
|
94 |
subnet6 = str(ip.subnet.id) |
|
95 |
|
|
96 |
fields = [port.name, str(port.id), str(port.machine.id), |
|
97 |
str(port.network.id), port.device_owner, port.mac, |
|
98 |
ipv4, subnet4, ipv6, subnet6, port.state, sg_csv, uuid] |
|
71 |
|
|
72 |
db_nic = { |
|
73 |
"id": port.id, |
|
74 |
"name": port.name, |
|
75 |
"userid": port.userid, |
|
76 |
"server": port.machine_id, |
|
77 |
"network": port.network_id, |
|
78 |
"device_owner": port.device_owner, |
|
79 |
"mac": port.mac, |
|
80 |
"state": port.state} |
|
99 | 81 |
|
100 | 82 |
self.stdout.write(sep) |
101 | 83 |
self.stdout.write('State of port in DB\n') |
102 | 84 |
self.stdout.write(sep) |
103 |
for l, f in zip(labels, fields): |
|
104 |
if f: |
|
105 |
self.stdout.write(l.ljust(18) + ': ' + f.ljust(20) + '\n') |
|
106 |
else: |
|
107 |
self.stdout.write(l.ljust(18) + ': ' + '\n') |
|
108 |
|
|
109 |
self.stdout.write('\n') |
|
110 |
''' |
|
85 |
pprint_table(self.stdout, db_nic.items(), None, separator=" | ") |
|
86 |
|
|
87 |
self.stdout.write('\n\n') |
|
88 |
ips = list(port.ips.values_list("address", "network_id", "subnet_id", |
|
89 |
"subnet__cidr", "floating_ip")) |
|
90 |
headers = ["Address", "Network", "Subnet", "CIDR", "is_floating"] |
|
91 |
pprint_table(self.stdout, ips, headers, separator=" | ") |
|
92 |
|
|
93 |
self.stdout.write('\n\n') |
|
94 |
|
|
95 |
self.stdout.write(sep) |
|
96 |
self.stdout.write('State of port in Ganeti\n') |
|
97 |
self.stdout.write(sep) |
|
98 |
vm = port.machine |
|
99 |
if vm is None: |
|
100 |
self.stdout.write("Port is not attached to any instance.\n") |
|
101 |
return |
|
102 |
|
|
111 | 103 |
client = vm.get_client() |
112 | 104 |
try: |
113 |
g_vm = client.GetInstance(vm.backend_vm_id) |
|
114 |
self.stdout.write('\n') |
|
115 |
self.stdout.write(sep) |
|
116 |
self.stdout.write('State of Server in Ganeti\n') |
|
117 |
self.stdout.write(sep) |
|
118 |
for i in GANETI_INSTANCE_FIELDS: |
|
119 |
try: |
|
120 |
value = g_vm[i] |
|
121 |
if i.find('time') != -1: |
|
122 |
value = datetime.fromtimestamp(value) |
|
123 |
self.stdout.write(i.ljust(14) + ': ' + str(value) + '\n') |
|
124 |
except KeyError: |
|
125 |
pass |
|
105 |
vm_info = client.GetInstance(vm.backend_vm_id) |
|
126 | 106 |
except GanetiApiError as e: |
127 | 107 |
if e.code == 404: |
128 |
self.stdout.write('Server does not exist in backend %s\n' % |
|
129 |
vm.backend.clustername) |
|
130 |
else: |
|
131 |
raise e |
|
108 |
self.stdout.write("NIC seems attached to server %s, but" |
|
109 |
" server does not exist in backend.\n" |
|
110 |
% vm) |
|
132 | 111 |
|
133 |
if not options['jobs']: |
|
112 |
nics = nics_from_instance(vm_info) |
|
113 |
try: |
|
114 |
gnt_nic = filter(lambda nic: nic.get("name") == port.backend_uuid, |
|
115 |
nics)[0] |
|
116 |
except IndexError: |
|
117 |
self.stdout.write("NIC %s is not attached to instance %s" |
|
118 |
% (port, vm)) |
|
134 | 119 |
return |
120 |
pprint_table(self.stdout, gnt_nic.items(), None, separator=" | ") |
|
135 | 121 |
|
136 |
self.stdout.write('\n') |
|
137 |
self.stdout.write(sep) |
|
138 |
self.stdout.write('Non-archived jobs concerning Server in Ganeti\n') |
|
139 |
self.stdout.write(sep) |
|
140 |
jobs = client.GetJobs() |
|
141 |
for j in jobs: |
|
142 |
info = client.GetJobStatus(j) |
|
143 |
summary = ' '.join(info['summary']) |
|
144 |
job_is_relevant = summary.startswith("INSTANCE") and\ |
|
145 |
(summary.find(vm.backend_vm_id) != -1) |
|
146 |
if job_is_relevant: |
|
147 |
for i in GANETI_JOB_FIELDS: |
|
148 |
value = info[i] |
|
149 |
if i.find('_ts') != -1: |
|
150 |
value = merge_time(value) |
|
151 |
try: |
|
152 |
self.stdout.write(i.ljust(14) + ': ' + str(value) + |
|
153 |
'\n') |
|
154 |
except KeyError: |
|
155 |
pass |
|
156 |
self.stdout.write('\n' + sep) |
|
157 |
# Return the RAPI client to pool |
|
158 | 122 |
vm.put_client(client) |
159 |
''' |
b/snf-cyclades-app/synnefo/api/management/commands/port-list.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
from optparse import make_option |
|
34 |
#from optparse import make_option
|
|
35 | 35 |
|
36 | 36 |
from snf_django.management.commands import ListCommand |
37 | 37 |
from synnefo.db.models import NetworkInterface |
... | ... | |
45 | 45 |
class Command(ListCommand): |
46 | 46 |
help = "List ports" |
47 | 47 |
|
48 |
|
|
49 | 48 |
object_class = NetworkInterface |
50 | 49 |
user_uuid_field = "userid" |
51 | 50 |
astakos_url = ASTAKOS_BASE_URL |
... | ... | |
54 | 53 |
def get_fixed_ips(ip): |
55 | 54 |
|
56 | 55 |
def labels((a, b)): |
57 |
return str({"subnet": b, "ip_address": str(a) })
|
|
56 |
return str({"subnet": b, "ip_address": str(a)}) |
|
58 | 57 |
|
59 | 58 |
lista = ip.get_ip_addresses_subnets() |
60 | 59 |
lista = map(labels, lista) |
... | ... | |
66 | 65 |
"user.uuid": ("userid", "The UUID of the port's owner"), |
67 | 66 |
"mac_address": ("mac", "The MAC address of the port"), |
68 | 67 |
"device_id": ("machine.id", "The vm's id the port is conncted to"), |
69 |
"status": ("status", "The port's status"),
|
|
68 |
"state": ("state", "The port's status"),
|
|
70 | 69 |
"device_owner": ("device_owner", "The owner of the port (vm/router)"), |
71 | 70 |
"network": ("network.id", "The network's ID the port is\ |
72 | 71 |
connected to"), |
... | ... | |
77 | 76 |
} |
78 | 77 |
|
79 | 78 |
fields = ["id", "name", "user.uuid", "mac_address", "network", |
80 |
"device_id", "fixed_ips"] |
|
79 |
"device_id", "fixed_ips", "state"] |
b/snf-cyclades-app/synnefo/api/ports.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
from django.conf import settings |
|
34 |
#from django.conf import settings
|
|
35 | 35 |
from django.conf.urls import patterns |
36 | 36 |
from django.http import HttpResponse |
37 | 37 |
from django.utils import simplejson as json |
... | ... | |
41 | 41 |
from snf_django.lib import api |
42 | 42 |
|
43 | 43 |
from synnefo.api import util |
44 |
from synnefo.db.models import NetworkInterface, SecurityGroup, IPAddress
|
|
44 |
from synnefo.db.models import NetworkInterface |
|
45 | 45 |
from synnefo.logic import ports |
46 | 46 |
|
47 | 47 |
from logging import getLogger |
... | ... | |
81 | 81 |
log.debug('list_ports detail=%s', detail) |
82 | 82 |
|
83 | 83 |
user_ports = NetworkInterface.objects.filter( |
84 |
network__userid=request.user_uniq)
|
|
84 |
machine__userid=request.user_uniq)
|
|
85 | 85 |
|
86 | 86 |
port_dicts = [port_to_dict(port, detail) |
87 | 87 |
for port in user_ports.order_by('id')] |
... | ... | |
110 | 110 |
if network.public: |
111 | 111 |
raise api.faults.Forbidden('forbidden') |
112 | 112 |
|
113 |
vm = util.get_vm(dev_id, user_id) |
|
113 |
vm = util.get_vm(dev_id, user_id, non_deleted=True, non_suspended=True)
|
|
114 | 114 |
|
115 | 115 |
name = api.utils.get_attribute(port_dict, "name", required=False) |
116 |
|
|
117 | 116 |
if name is None: |
118 | 117 |
name = "" |
119 | 118 |
|
... | ... | |
179 | 178 |
@transaction.commit_on_success |
180 | 179 |
def delete_port(request, port_id): |
181 | 180 |
log.info('delete_port %s', port_id) |
182 |
port = util.get_port(port_id, request.user_uniq, for_update=True) |
|
183 |
''' |
|
184 |
FIXME delete the port |
|
185 |
skip the backend part... |
|
186 |
release the ips associated with the port |
|
187 |
''' |
|
181 |
user_id = request.user_uniq |
|
182 |
port = util.get_port(port_id, user_id, for_update=True) |
|
183 |
ports.delete(port) |
|
188 | 184 |
return HttpResponse(status=204) |
189 | 185 |
|
190 | 186 |
#util functions |
... | ... | |
193 | 189 |
def port_to_dict(port, detail=True): |
194 | 190 |
d = {'id': str(port.id), 'name': port.name} |
195 | 191 |
if detail: |
196 |
d['user_id'] = port.network.userid |
|
197 |
d['tenant_id'] = port.network.userid |
|
192 |
user_id = port.machine.id |
|
193 |
d['user_id'] = user_id |
|
194 |
d['tenant_id'] = user_id |
|
198 | 195 |
d['device_id'] = str(port.machine.id) |
196 |
# TODO: Change this based on the status of VM |
|
199 | 197 |
d['admin_state_up'] = True |
200 | 198 |
d['mac_address'] = port.mac |
201 | 199 |
d['status'] = port.state |
b/snf-cyclades-app/synnefo/logic/ports.py | ||
---|---|---|
30 | 30 |
# documentation are those of the authors and should not be |
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 |
import ipaddr |
|
34 |
|
|
35 | 33 |
from functools import wraps |
36 | 34 |
from django.db import transaction |
37 | 35 |
|
38 |
from django.conf import settings |
|
39 |
from snf_django.lib.api import faults |
|
36 |
#from django.conf import settings |
|
40 | 37 |
from synnefo.api import util |
41 |
from synnefo import quotas |
|
42 |
from synnefo.db.models import NetworkInterface, IPAddress |
|
38 |
from snf_django.lib.api import faults |
|
39 |
from synnefo.db.models import NetworkInterface |
|
40 |
from synnefo.logic import backend |
|
43 | 41 |
|
44 | 42 |
from logging import getLogger |
45 | 43 |
log = getLogger(__name__) |
... | ... | |
54 | 52 |
return wrapper |
55 | 53 |
return decorator |
56 | 54 |
|
55 |
|
|
57 | 56 |
@transaction.commit_on_success |
58 | 57 |
def create(network, machine, name="", security_groups=None, |
59 | 58 |
device_owner='vm'): |
... | ... | |
61 | 60 |
if network.state != 'ACTIVE': |
62 | 61 |
raise faults.Conflict('Network build in process') |
63 | 62 |
|
63 |
user_id = machine.userid |
|
64 | 64 |
#create the port |
65 | 65 |
port = NetworkInterface.objects.create(name=name, |
66 | 66 |
network=network, |
67 | 67 |
machine=machine, |
68 |
userid=machine.userid,
|
|
68 |
userid=user_id,
|
|
69 | 69 |
device_owner=device_owner, |
70 | 70 |
state="BUILDING") |
71 | 71 |
#add the security groups if any |
72 | 72 |
if security_groups: |
73 | 73 |
port.security_groups.add(*security_groups) |
74 | 74 |
|
75 |
#add new port to every subnet of the network |
|
76 |
for subn in network.subnets.all(): |
|
77 |
IPAddress.objects.create(subnet=subn, |
|
78 |
network=network, |
|
79 |
nic=port, |
|
80 |
userid=machine.userid, |
|
81 |
# FIXME |
|
82 |
address="192.168.0." + str(subn.id)) |
|
75 |
ipaddress = None |
|
76 |
if network.subnets.filter(ipversion=4).exists(): |
|
77 |
ipaddress = util.allocate_ip(network, user_id) |
|
78 |
ipaddress.nic = port |
|
79 |
ipaddress.save() |
|
80 |
|
|
81 |
jobID = backend.connect_to_network(machine, port) |
|
82 |
|
|
83 |
log.info("Created Port %s with IP Address: %s. Job: %s", |
|
84 |
port, ipaddress, jobID) |
|
83 | 85 |
|
84 |
# Issue commission to Quotaholder and accept it since at the end of |
|
85 |
# this transaction the Network object will be created in the DB. |
|
86 |
# Note: the following call does a commit! |
|
87 |
#quotas.issue_and_accept_commission(new_port) |
|
86 |
# TODO: Consider quotas for Ports |
|
88 | 87 |
|
89 | 88 |
return port |
90 | 89 |
|
90 |
|
|
91 | 91 |
@transaction.commit_on_success |
92 | 92 |
def delete(port): |
93 |
port.ips.all().delete() |
|
94 |
port.delete() |
|
93 |
"""Delete a port by removing the NIC card the instance. |
|
94 |
|
|
95 |
Send a Job to remove the NIC card from the instance. The port |
|
96 |
will be deleted and the associated IPv4 addressess will be released |
|
97 |
when the job completes successfully. |
|
98 |
|
|
99 |
""" |
|
100 |
|
|
101 |
jobID = backend.disconnect_from_network(port.machine, port) |
|
102 |
log.info("Removing port %s, Job: %s", port, jobID) |
|
103 |
return port |
Also available in: Unified diff