Commit 4b649f24 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

cyclades: Create ports without 'device_id'

Allow creation of ports that are not connected to any instance. Such
ports will be in 'DOWN' state. To allow this, 'machine' attribute of
NetworkInterface model has been made to allow null values. Finally, the
'logic.ports' module has been remove, and the corresponding code has
been merged into 'logic.servers' module.
parent 414c3f11
......@@ -34,17 +34,11 @@
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from synnefo.management.common import convert_api_faults
from synnefo.api import util
from synnefo.management.common import get_network, get_vm
from synnefo.management import common
from synnefo.logic import servers
class Command(BaseCommand):
can_import_settings = True
output_transaction = True
help = "Attach a floating IP to a VM or router"
option_list = BaseCommand.option_list + (
......@@ -55,20 +49,22 @@ class Command(BaseCommand):
help='The server id the floating-ip will be attached to'),
)
@convert_api_faults
@common.convert_api_faults
def handle(self, *args, **options):
if not args or len(args) > 1:
raise CommandError("Command accepts exactly one argument")
floating_ip = args[0] # this is the floating-ip address
floating_ip_id = args[0] # this is the floating-ip address
device = options['machine']
if not device:
raise CommandError('Please give either a server or a router id')
#get the vm
vm = get_vm(device)
servers.add_floating_ip(vm, floating_ip)
vm = common.get_vm(device)
floating_ip = common.get_floating_ip_by_id(floating_ip_id,
for_update=True)
servers.create_port(vm.userid, floating_ip.network,
use_ipaddress=floating_ip, machine=vm)
self.stdout.write("Attached %s to %s.\n" % (floating_ip, vm))
......@@ -31,33 +31,32 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from optparse import make_option
#from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from synnefo.management.common import get_floating_ip_by_address
from synnefo.management import common
from synnefo.logic import servers
class Command(BaseCommand):
can_import_settings = True
output_transaction = True
class Command(BaseCommand):
help = "Dettach a floating IP from a VM or router"
@common.convert_api_faults
def handle(self, *args, **options):
if not args or len(args)>1:
if not args or len(args) > 1:
raise CommandError("Command accepts exactly one argument")
address = args[0]
floating_ip_id = args[0]
#get the floating-ip
floating_ip = get_floating_ip_by_address(address, for_update=True)
floating_ip = common.get_floating_ip_by_id(floating_ip_id,
for_update=True)
if not floating_ip.nic:
raise CommandError('This floating IP is not attached to a device')
nic = floating_ip.nic
vm = nic.machine
servers.disconnect(vm, nic)
servers.delete_port(nic)
self.stdout.write("Dettached floating IP %s from %s.\n"
% (floating_ip_id, vm))
% (floating_ip_id, vm))
......@@ -38,7 +38,7 @@ from django.core.management.base import BaseCommand, CommandError
from synnefo.api import util
from synnefo.management import common, pprint
from snf_django.management.utils import parse_bool
from synnefo.logic import ports
from synnefo.logic import servers
HELP_MSG = """Create a new port.
......@@ -57,6 +57,11 @@ class Command(BaseCommand):
dest="name",
default=None,
help="Name of the port."),
make_option(
"--owner",
dest="user_id",
default=None,
help="UUID of the owner of the Port."),
make_option(
"--network",
dest="network_id",
......@@ -103,6 +108,7 @@ class Command(BaseCommand):
raise CommandError("Command doesn't accept any arguments")
name = options["name"]
user_id = options["user_id"]
network_id = options["network_id"]
server_id = options["server_id"]
#router_id = options["router_id"]
......@@ -114,12 +120,14 @@ class Command(BaseCommand):
if not name:
name = ""
if (server_id and router_id) or not (server_id or router_id):
raise CommandError("Please give either a server or a router id")
if not network_id:
raise CommandError("Please specify a 'network'")
if user_id is None:
raise CommandError("Please specify the owner of the port")
vm = None
owner = None
if server_id:
owner = "vm"
vm = common.get_vm(server_id)
......@@ -130,8 +138,6 @@ class Command(BaseCommand):
vm = common.get_vm(router_id)
if not vm.router:
raise CommandError("Router '%s' does not exist." % router_id)
else:
raise CommandError("Neither server or router is specified")
# get the network
network = common.get_network(network_id)
......@@ -146,9 +152,6 @@ class Command(BaseCommand):
elif floating_ip_id:
ipaddress = common.get_floating_ip_by_id(floating_ip_id,
for_update=True)
if ipv4_address is not None:
ipaddress = util.allocate_ip(network, vm.userid,
address=ipv4_address)
# validate security groups
sg_list = []
......@@ -158,11 +161,15 @@ class Command(BaseCommand):
sg = util.get_security_group(int(gid))
sg_list.append(sg)
new_port = ports.create(network, vm, name=name, ipaddress=ipaddress,
security_groups=sg_list,
device_owner=owner)
new_port = servers.create_port(user_id, network, machine=vm,
name=name,
use_ipaddress=ipaddress,
address=ipv4_address,
security_groups=sg_list,
device_owner=owner)
self.stdout.write("Created port '%s' in DB:\n" % new_port)
pprint.pprint_port(new_port, stdout=self.stdout)
pprint.pprint_port_ips(new_port, stdout=self.stdout)
self.stdout.write("\n")
common.wait_server_task(new_port.machine, wait, stdout=self.stdout)
if vm is not None:
common.wait_server_task(new_port.machine, wait, stdout=self.stdout)
......@@ -64,10 +64,10 @@ class Command(ListCommand):
"name": ("name", "The name of the port"),
"user.uuid": ("userid", "The UUID of the port's owner"),
"mac_address": ("mac", "The MAC address of the port"),
"device_id": ("machine.id", "The vm's id the port is conncted to"),
"device_id": ("machine_id", "The vm's id the port is conncted to"),
"state": ("state", "The port's status"),
"device_owner": ("device_owner", "The owner of the port (vm/router)"),
"network": ("network.id", "The network's ID the port is\
"network": ("network_id", "The network's ID the port is\
connected to"),
"created": ("created", "The date the port was created"),
"updated": ("updated", "The date the port was updated"),
......
......@@ -30,7 +30,7 @@
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from synnefo.logic import ports
from synnefo.logic import servers
from synnefo.api.util import get_port
from synnefo.management import common
from snf_django.management.utils import parse_bool
......@@ -54,9 +54,12 @@ class Command(BaseCommand):
if len(args) < 1:
raise CommandError("Please provide a port ID")
port = get_port(args[0], None)
port = get_port(args[0], None, for_update=True)
ports.delete(port)
servers.delete_port(port)
wait = parse_bool(options["wait"])
common.wait_server_task(port.machine, wait, stdout=self.stdout)
if port.machine is not None:
common.wait_server_task(port.machine, wait, stdout=self.stdout)
else:
self.stdout.write("Successfully removed port %s\n" % port)
......@@ -44,7 +44,7 @@ from snf_django.lib.api import faults
from synnefo.api import util
from synnefo.db.models import NetworkInterface
from synnefo.logic import ports
from synnefo.logic import servers
from logging import getLogger
......@@ -98,6 +98,7 @@ def list_ports(request, detail=False):
@api.api_method(http_method='POST', user_required=True, logger=log)
@transaction.commit_on_success
def create_port(request):
user_id = request.user_uniq
req = api.utils.get_request_dict(request)
......@@ -105,7 +106,6 @@ def create_port(request):
port_dict = api.utils.get_attribute(req, "port")
net_id = api.utils.get_attribute(port_dict, "network_id")
dev_id = api.utils.get_attribute(port_dict, "device_id")
network = util.get_network(net_id, user_id, non_deleted=True)
......@@ -143,8 +143,11 @@ def create_port(request):
ipaddress = util.allocate_ip(network, user_id,
address=fixed_ip_address)
vm = util.get_vm(dev_id, user_id, for_update=True, non_deleted=True,
non_suspended=True)
device_id = api.utils.get_attribute(port_dict, "device_id", required=False)
vm = None
if device_id is not None:
vm = util.get_vm(device_id, user_id, for_update=True, non_deleted=True,
non_suspended=True)
name = api.utils.get_attribute(port_dict, "name", required=False)
if name is None:
......@@ -161,8 +164,8 @@ def create_port(request):
sg = util.get_security_group(int(gid))
sg_list.append(sg)
new_port = ports.create(network, vm, ipaddress=ipaddress,
security_groups=sg_list)
new_port = servers.create_port(user_id, network, use_ipaddress=ipaddress,
machine=vm)
response = render_port(request, port_to_dict(new_port), status=201)
......@@ -215,7 +218,7 @@ def delete_port(request, port_id):
log.info('delete_port %s', port_id)
user_id = request.user_uniq
port = util.get_port(port_id, user_id, for_update=True)
ports.delete(port)
servers.delete_port(port)
return HttpResponse(status=204)
#util functions
......@@ -224,10 +227,11 @@ def delete_port(request, port_id):
def port_to_dict(port, detail=True):
d = {'id': str(port.id), 'name': port.name}
if detail:
user_id = port.machine.id
user_id = port.userid
machine_id = port.machine_id
d['user_id'] = user_id
d['tenant_id'] = user_id
d['device_id'] = str(port.machine.id)
d['device_id'] = str(machine_id) if machine_id else None
# TODO: Change this based on the status of VM
d['admin_state_up'] = True
d['mac_address'] = port.mac
......
......@@ -928,7 +928,11 @@ def add_floating_ip(request, vm, args):
if address is None:
raise faults.BadRequest("Missing 'address' attribute")
servers.add_floating_ip(vm, address)
userid = vm.userid
floating_ip = util.get_floating_ip_by_address(userid, address,
for_update=True)
servers.create_port(userid, floating_ip.network, machine=vm,
user_ipaddress=floating_ip)
return HttpResponse(status=202)
......@@ -937,6 +941,10 @@ def remove_floating_ip(request, vm, args):
address = args.get("address")
if address is None:
raise faults.BadRequest("Missing 'address' attribute")
servers.remove_floating_ip(vm, address)
floating_ip = util.get_floating_ip_by_address(vm.userid, address,
for_update=True)
if floating_ip.nic is None:
raise faults.BadRequest("Floating IP %s not attached to instance"
% address)
servers.delete_port(floating_ip.nic)
return HttpResponse(status=202)
......@@ -76,12 +76,6 @@ class PortTest(BaseAPITest):
response = self.delete(url, user=nic.network.userid)
self.assertEqual(response.status_code, 400)
def test_delete_port_from_nonvm(self):
nic = dbmf.NetworkInterfaceFactory(device_owner='router')
url = join_urls(PORTS_URL, str(nic.id))
response = self.delete(url, user=nic.network.userid)
self.assertEqual(response.status_code, 400)
def test_remove_nic_malformed(self):
url = join_urls(PORTS_URL, "123")
response = self.delete(url)
......@@ -278,6 +272,33 @@ class PortTest(BaseAPITest):
user=vm.userid)
self.assertBadRequest(response)
def test_create_port_without_device(self):
net = dbmf.NetworkWithSubnetFactory(userid="test_user",
public=False,
subnet__cidr="192.168.2.0/24",
subnet__pool__size=3,
subnet__pool__offset=1)
request = {
"port": {
"name": "port_with_address",
"network_id": str(net.id),
}
}
response = self.post(PORTS_URL, params=json.dumps(request),
user="test_user")
self.assertEqual(response.status_code, 201)
new_port = json.loads(response.content)["port"]
self.assertEqual(new_port["device_id"], None)
# And with address
request["port"]["fixed_ips"] = [{"ip_address": "192.168.2.2"}]
with override_settings(settings, GANETI_USE_HOTPLUG=True):
response = self.post(PORTS_URL, params=json.dumps(request),
user="test_user")
self.assertEqual(response.status_code, 201)
new_port = json.loads(response.content)["port"]
self.assertEqual(new_port["device_id"], None)
self.assertEqual(new_port["fixed_ips"][0]["ip_address"], "192.168.2.2")
def test_add_nic_to_deleted_network(self):
user = 'userr'
vm = dbmf.VirtualMachineFactory(name='yo', userid=user,
......@@ -311,20 +332,6 @@ class PortTest(BaseAPITest):
self.assertBadRequest(response)
#self.assertFault(response, 403, 'forbidden')
def test_add_nic_malformed_1(self):
user = 'userr'
dbmf.VirtualMachineFactory(name='yo', userid=user)
net = dbmf.NetworkFactory(state='ACTIVE', userid=user)
request = {
"port": {
"name": "port1",
"network_id": str(net.id)
}
}
response = self.post(PORTS_URL, params=json.dumps(request),
user=net.userid)
self.assertBadRequest(response)
def test_add_nic_malformed_2(self):
user = 'userr'
vm = dbmf.VirtualMachineFactory(name='yo', userid=user)
......
......@@ -240,8 +240,8 @@ def get_port(port_id, user_id, for_update=False):
else:
port = objects.get(network__userid=user_id, id=port_id)
if (port.device_owner != "vm") and for_update:
raise faults.BadRequest('Can not update non vm port')
# if (port.device_owner != "vm") and for_update:
# raise faults.BadRequest('Can not update non vm port')
return port
except (ValueError, NetworkInterface.DoesNotExist):
......@@ -275,7 +275,7 @@ def get_floating_ip_by_id(userid, floating_ip_id, for_update=False):
return objects.get(id=floating_ip_id, floating_ip=True,
userid=userid, deleted=False)
except IPAddress.DoesNotExist:
raise faults.ItemNotFound("Floating IP %s does not exist." %
raise faults.ItemNotFound("Floating IP with ID %s does not exist." %
floating_ip_id)
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'NetworkInterface.machine'
db.alter_column('db_networkinterface', 'machine_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['db.VirtualMachine']))
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'NetworkInterface.machine'
raise RuntimeError("Cannot reverse this migration. 'NetworkInterface.machine' and its values cannot be restored.")
models = {
'db.backend': {
'Meta': {'ordering': "['clustername']", 'object_name': 'Backend'},
'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'disk_templates': ('synnefo.db.fields.SeparatedValuesField', [], {'null': 'True'}),
'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'hypervisor': ('django.db.models.fields.CharField', [], {'default': "'kvm'", 'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'index': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'unique': 'True'}),
'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'password_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
},
'db.backendnetwork': {
'Meta': {'unique_together': "(('network', 'backend'),)", 'object_name': 'BackendNetwork'},
'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'on_delete': 'models.PROTECT', 'to': "orm['db.Backend']"}),
'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
},
'db.bridgepooltable': {
'Meta': {'object_name': 'BridgePoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'db.flavor': {
'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'disk_template': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
},
'db.ipaddress': {
'Meta': {'unique_together': "(('network', 'address'),)", 'object_name': 'IPAddress'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'floating_ip': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ips'", 'to': "orm['db.Network']"}),
'nic': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ips'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['db.NetworkInterface']"}),
'serial': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ips'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['db.QuotaHolderSerial']"}),
'subnet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ips'", 'to': "orm['db.Subnet']"}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'})
},
'db.ipaddresslog': {
'Meta': {'object_name': 'IPAddressLog'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}),
'allocated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'network_id': ('django.db.models.fields.IntegerField', [], {}),
'released_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'server_id': ('django.db.models.fields.IntegerField', [], {})
},
'db.ippooltable': {
'Meta': {'object_name': 'IPPoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {}),
'subnet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ip_pools'", 'null': 'True', 'to': "orm['db.Subnet']"})
},
'db.macprefixpooltable': {
'Meta': {'object_name': 'MacPrefixPoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'db.network': {
'Meta': {'object_name': 'Network'},
'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'external_router': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'flavor': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'floating_ip_pool': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'link': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
'mode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
'serial': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'network'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['db.QuotaHolderSerial']"}),
'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
'tags': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'db_index': 'True'})
},
'db.networkinterface': {
'Meta': {'object_name': 'NetworkInterface'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'device_owner': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'index': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'mac': ('django.db.models.fields.CharField', [], {'max_length': '32', 'unique': 'True', 'null': 'True'}),
'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'null': 'True', 'to': "orm['db.VirtualMachine']"}),
'name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '128', 'null': 'True'}),
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
'security_groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.SecurityGroup']", 'null': 'True', 'symmetrical': 'False'}),
'state': ('django.db.models.fields.CharField', [], {'default': "'ACTIVE'", 'max_length': '32'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'db_index': 'True'})
},
'db.quotaholderserial': {
'Meta': {'ordering': "['serial']", 'object_name': 'QuotaHolderSerial'},
'accept': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),