Add container class, add segmentation_id to Port, allow ports to be attached to containers
diff --git a/xos/core/admin.py b/xos/core/admin.py
index a5b89be..dfa96b9 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1372,6 +1372,29 @@
# obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
# obj.delete()
+class ContainerAdmin(XOSBaseAdmin):
+ fieldsets = [
+ ('Instance Details', {'fields': ['backend_status_text', 'slice', 'node'], 'classes': ['suit-tab suit-tab-general'], })
+ ]
+ readonly_fields = ('backend_status_text', )
+ list_display = ['backend_status_icon', 'id']
+ list_display_links = ('backend_status_icon', 'id', )
+
+ suit_form_tabs =(('general', 'Instance Details'),) # ('ports', 'Ports'))
+
+ #inlines = [TagInline, InstancePortInline]
+
+ def formfield_for_foreignkey(self, db_field, request, **kwargs):
+ if db_field.name == 'slice':
+ kwargs['queryset'] = Slice.select_by_user(request.user)
+
+ return super(ContainerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+ def queryset(self, request):
+ # admins can see all instances. Users can only see instances of
+ # the slices they belong to.
+ return Container.select_by_user(request.user)
+
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
@@ -1727,7 +1750,7 @@
readonly_fields = ('backend_status_icon', )
class NetworkPortInline(XOSTabularInline):
- fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
+ fields = ['backend_status_icon', 'network', 'instance', 'container', 'ip', 'mac']
readonly_fields = ("backend_status_icon", "ip", "mac")
model = Port
selflink_fieldname = "instance"
@@ -2024,4 +2047,5 @@
admin.site.register(TenantRoot, TenantRootAdmin)
admin.site.register(TenantRootRole, TenantRootRoleAdmin)
admin.site.register(TenantAttribute, TenantAttributeAdmin)
+ admin.site.register(Container, ContainerAdmin)
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index c380e9c..bc97dab 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -24,6 +24,7 @@
from .node import Node
from .slicetag import SliceTag
from .instance import Instance
+from .container import Container
from .reservation import ReservedResource
from .reservation import Reservation
from .network import Network, NetworkParameterType, NetworkParameter, Port, NetworkTemplate, Router, NetworkSlice, ControllerNetwork
diff --git a/xos/core/models/container.py b/xos/core/models/container.py
new file mode 100644
index 0000000..151b576
--- /dev/null
+++ b/xos/core/models/container.py
@@ -0,0 +1,83 @@
+import os
+from django.db import models
+from django.db.models import Q
+from django.core import exceptions
+from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
+from core.models.plcorebase import StrippedCharField
+from core.models import Image
+from core.models import Slice, SlicePrivilege
+from core.models import Node
+from core.models import Site
+from core.models import Deployment
+from core.models import Controller
+from core.models import User
+from core.models import Tag
+from core.models import Flavor
+from django.contrib.contenttypes import generic
+from xos.config import Config
+from monitor import driver as monitor
+from django.core.exceptions import PermissionDenied, ValidationError
+
+config = Config()
+
+
+# Create your models here.
+class Container(PlCoreBase):
+ name = StrippedCharField(max_length=200, help_text="Container name")
+ slice = models.ForeignKey(Slice, related_name='containers')
+ node = models.ForeignKey(Node, related_name='containers')
+ creator = models.ForeignKey(User, related_name='containers', blank=True, null=True)
+ docker_image = StrippedCharField(null=True, blank=True, max_length=200, help_text="name of docker container to instantiate")
+
+ def __unicode__(self):
+ return u'container-%s' % str(self.id)
+
+ def save(self, *args, **kwds):
+ if not self.name:
+ self.name = self.slice.name
+ if not self.creator and hasattr(self, 'caller'):
+ self.creator = self.caller
+ if not self.creator:
+ raise ValidationError('container has no creator')
+
+ if (self.slice.creator != self.creator):
+ # Check to make sure there's a slice_privilege for the user. If there
+ # isn't, then keystone will throw an exception inside the observer.
+ slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
+ if not slice_privs:
+ raise ValidationError('container creator has no privileges on slice')
+
+# XXX smbaker - disabled for now, was causing fault in tenant view create slice
+# if not self.controllerNetwork.test_acl(slice=self.slice):
+# raise exceptions.ValidationError("Deployment %s's ACL does not allow any of this slice %s's users" % (self.controllerNetwork.name, self.slice.name))
+
+ super(Container, self).save(*args, **kwds)
+
+ def can_update(self, user):
+ return True
+
+ @staticmethod
+ def select_by_user(user):
+ if user.is_admin:
+ qs = Container.objects.all()
+ else:
+ slices = Slice.select_by_user(user)
+ qs = Container.objects.filter(slice__in=slices)
+ return qs
+
+ def get_public_keys(self):
+ slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
+ pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+
+ if self.creator.public_key:
+ pubkeys.add(self.creator.public_key)
+
+ if self.slice.creator.public_key:
+ pubkeys.add(self.slice.creator.public_key)
+
+ if self.slice.service and self.slice.service.public_key:
+ pubkeys.add(self.slice.service.public_key)
+
+ return pubkeys
+
+
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index 2bdf17f..48af5a6 100644
--- a/xos/core/models/network.py
+++ b/xos/core/models/network.py
@@ -2,7 +2,7 @@
import socket
import sys
from django.db import models
-from core.models import PlCoreBase, Site, Slice, Instance, Controller
+from core.models import PlCoreBase, Site, Slice, Instance, Controller, Container
from core.models import ControllerLinkManager,ControllerLinkDeletionManager
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
@@ -158,7 +158,7 @@
router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
subnet = models.CharField(max_length=32, blank=True)
-
+
class Meta:
unique_together = ('network', 'controller')
@@ -211,9 +211,12 @@
class Port(PlCoreBase):
network = models.ForeignKey(Network,related_name='links')
instance = models.ForeignKey(Instance, null=True, blank=True, related_name='ports')
+ container = models.ForeignKey(Container, null=True, blank=True, related_name='ports')
ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum port id")
mac = models.CharField(null=True, blank=True, max_length=256, help_text="MAC address associated with this port")
+ #unattached = models.BooleanField(default=False, help_text="create this port even if no Instance is attached")
+ segmentation_id = models.CharField(null=True, blank=True, max_length=256, help_text="GRE segmentation id for port")
class Meta:
unique_together = ('network', 'instance')
diff --git a/xos/openstack_observer/steps/sync_ports.py b/xos/openstack_observer/steps/sync_ports.py
index 967bef9..7b20d29 100644
--- a/xos/openstack_observer/steps/sync_ports.py
+++ b/xos/openstack_observer/steps/sync_ports.py
@@ -144,9 +144,14 @@
# For ports that were created by the user, find that ones
# that don't have neutron ports, and create them.
- for port in Port.objects.filter(port_id__isnull=True, instance__isnull=False):
- #logger.info("XXX working on port %s" % port)
- controller = port.instance.node.site_deployment.controller
+ for port in Port.objects.filter(Q(port_id__isnull=True), Q(instance__isnull=False) | Q(container__isnull=False)):
+ logger.info("XXX working on port %s" % port)
+ if port.instance:
+ controller = port.instance.node.site_deployment.controller
+ slice = port.instance.slice
+ else:
+ controller = port.container.node.site_deployment.controller
+ slice = port.container.slice
if controller:
cn=port.network.controllernetworks.filter(controller=controller)
if not cn:
@@ -174,7 +179,7 @@
caller = port.network.owner.creator
auth = {'username': caller.email,
'password': caller.remote_password,
- 'tenant': port.instance.slice.name} # port.network.owner.name}
+ 'tenant': slice.name}
client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
driver = OpenStackDriver(client=client)
@@ -183,6 +188,10 @@
if neutron_port["fixed_ips"]:
port.ip = neutron_port["fixed_ips"][0]["ip_address"]
port.mac = neutron_port["mac_address"]
+
+ neutron_network = driver.shell.quantum.list_networks(cn.net_id)["networks"][0]
+ if "provider:segmentation_id" in neutron_network:
+ port.segmentation_id = neutron_network["provider:segmentation_id"]
except:
logger.log_exc("failed to create neutron port for %s" % port)
continue