Merge branch 'master' of https://github.com/open-cloud/xos into AddHelloWorldService
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index 67d8bb6..8945eea 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -456,7 +456,8 @@
type: tosca.nodes.VOLTTenant
properties:
service_specific_id: 123
- vlan_id: 432
+ s_tag: 222
+ c_tag: 432
requirements:
- provider_service:
node: service_volt
diff --git a/xos/cord/admin.py b/xos/cord/admin.py
index 9e7946e..981f275 100644
--- a/xos/cord/admin.py
+++ b/xos/cord/admin.py
@@ -1,7 +1,6 @@
from django.contrib import admin
from cord.models import *
-from core.models import Container
from django import forms
from django.utils.safestring import mark_safe
from django.contrib.auth.admin import UserAdmin
@@ -52,7 +51,8 @@
return VOLTService.get_service_objects_by_user(request.user)
class VOLTTenantForm(forms.ModelForm):
- vlan_id = forms.CharField()
+ s_tag = forms.CharField()
+ c_tag = forms.CharField()
creator = forms.ModelChoiceField(queryset=User.objects.all())
def __init__(self,*args,**kwargs):
@@ -61,7 +61,8 @@
self.fields['provider_service'].queryset = VOLTService.get_service_objects().all()
if self.instance:
# fields for the attributes
- self.fields['vlan_id'].initial = self.instance.vlan_id
+ self.fields['c_tag'].initial = self.instance.c_tag
+ self.fields['s_tag'].initial = self.instance.s_tag
self.fields['creator'].initial = self.instance.creator
if (not self.instance) or (not self.instance.pk):
# default fields for an 'add' form
@@ -71,7 +72,8 @@
self.fields["provider_service"].initial = VOLTService.get_service_objects().all()[0]
def save(self, commit=True):
- self.instance.vlan_id = self.cleaned_data.get("vlan_id")
+ self.instance.s_tag = self.cleaned_data.get("s_tag")
+ self.instance.c_tag = self.cleaned_data.get("c_tag")
self.instance.creator = self.cleaned_data.get("creator")
return super(VOLTTenantForm, self).save(commit=commit)
@@ -79,10 +81,10 @@
model = VOLTTenant
class VOLTTenantAdmin(ReadOnlyAwareAdmin):
- list_display = ('backend_status_icon', 'id', 'service_specific_id', 'vlan_id', 'subscriber_root' )
+ list_display = ('backend_status_icon', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber_root' )
list_display_links = ('backend_status_icon', 'id')
fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_root', 'service_specific_id', # 'service_specific_attribute',
- 'vlan_id', 'creator'],
+ 's_tag', 'c_tag', 'creator'],
'classes':['suit-tab suit-tab-general']})]
readonly_fields = ('backend_status_text', 'service_specific_attribute')
form = VOLTTenantForm
@@ -160,7 +162,6 @@
bbs_account = forms.CharField(required=False)
creator = forms.ModelChoiceField(queryset=User.objects.all())
instance = forms.ModelChoiceField(queryset=Instance.objects.all(),required=False)
- container = forms.ModelChoiceField(queryset=Container.objects.all(),required=False)
use_cobm = forms.BooleanField(required=False)
last_ansible_hash = forms.CharField(required=False)
@@ -173,7 +174,6 @@
self.fields['bbs_account'].initial = self.instance.bbs_account
self.fields['creator'].initial = self.instance.creator
self.fields['instance'].initial = self.instance.instance
- self.fields['container'].initial = self.instance.container
self.fields['use_cobm'].initial = self.instance.use_cobm
self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
if (not self.instance) or (not self.instance.pk):
@@ -188,7 +188,6 @@
self.instance.creator = self.cleaned_data.get("creator")
self.instance.instance = self.cleaned_data.get("instance")
self.instance.last_ansible_hash = self.cleaned_data.get("last_ansible_hash")
- self.instance.container = self.cleaned_data.get("container")
self.instance.use_cobm = self.cleaned_data.get("use_cobm")
return super(VCPETenantForm, self).save(commit=commit)
@@ -199,7 +198,7 @@
list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
list_display_links = ('backend_status_icon', 'id')
fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id', # 'service_specific_attribute',
- 'bbs_account', 'creator', 'use_cobm', 'instance', 'container', 'last_ansible_hash'],
+ 'bbs_account', 'creator', 'use_cobm', 'instance', 'last_ansible_hash'],
'classes':['suit-tab suit-tab-general']})]
readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account')
form = VCPETenantForm
diff --git a/xos/cord/models.py b/xos/cord/models.py
index 4227f52..afbe3ef 100644
--- a/xos/cord/models.py
+++ b/xos/cord/models.py
@@ -254,7 +254,7 @@
KIND = VOLT_KIND
- default_attributes = {"vlan_id": None, }
+ default_attributes = {"vlan_id": None, "s_tag": None, "c_tag": None}
def __init__(self, *args, **kwargs):
volt_services = VOLTService.get_service_objects().all()
if volt_services:
@@ -263,12 +263,30 @@
self.cached_vcpe = None
@property
+ def s_tag(self):
+ return self.get_attribute("s_tag", self.default_attributes["s_tag"])
+
+ @s_tag.setter
+ def s_tag(self, value):
+ self.set_attribute("s_tag", value)
+
+ @property
+ def c_tag(self):
+ return self.get_attribute("c_tag", self.default_attributes["c_tag"])
+
+ @c_tag.setter
+ def c_tag(self, value):
+ self.set_attribute("c_tag", value)
+
+ # for now, vlan_id is a synonym for c_tag
+
+ @property
def vlan_id(self):
- return self.get_attribute("vlan_id", self.default_attributes["vlan_id"])
+ return self.c_tag
@vlan_id.setter
def vlan_id(self, value):
- self.set_attribute("vlan_id", value)
+ self.c_tag = value
@property
def vcpe(self):
diff --git a/xos/cord/rest_examples/add_volt_tenant.sh b/xos/cord/rest_examples/add_volt_tenant.sh
index 5dd3dd4..4bbe2bb 100755
--- a/xos/cord/rest_examples/add_volt_tenant.sh
+++ b/xos/cord/rest_examples/add_volt_tenant.sh
@@ -3,8 +3,9 @@
source ./config.sh
SERVICE_SPECIFIC_ID=1238
-VLAN_ID=1238
+C_TAG=1238
+S_TAG=3333
-echo curl "-H \"Accept: application/json; indent=4\" -H \"Content-Type: application/json\" -u $AUTH -X POST -d \"{\\\"service_specific_id\\\": \\\"$SERVICE_SPECIFIC_ID\\\", \\\"vlan_id\\\": \\\"$VLAN_ID\\\"}\" $HOST/xoslib/volttenant/"
+echo curl "-H \"Accept: application/json; indent=4\" -H \"Content-Type: application/json\" -u $AUTH -X POST -d \"{\\\"service_specific_id\\\": \\\"$SERVICE_SPECIFIC_ID\\\", \\\"c_tag\\\": \\\"$C_TAG\\\", \\\"s_tag\\\": \\\"$S_TAG\\\"}\" $HOST/xoslib/volttenant/"
-curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "{\"service_specific_id\": \"$SERVICE_SPECIFIC_ID\", \"vlan_id\": \"$VLAN_ID\"}" $HOST/xoslib/volttenant/
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "{\"service_specific_id\": \"$SERVICE_SPECIFIC_ID\", \"c_tag\": \"$C_TAG\", \"s_tag\": \"$S_TAG\"}" $HOST/xoslib/volttenant/
diff --git a/xos/cord/rest_examples/config.sh b/xos/cord/rest_examples/config.sh
index 7b8c8e1..06162ee 100644
--- a/xos/cord/rest_examples/config.sh
+++ b/xos/cord/rest_examples/config.sh
@@ -1,5 +1,6 @@
#HOST=198.0.0.44:8000
-HOST=10.254.1.22:8000
+#HOST=10.254.1.22:8000
+HOST=clnode050.clemson.cloudlab.us:9999
#AUTH=scott@onlab.us:letmein
AUTH=padmin@vicci.org:letmein
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 317c6a5..ce7759c 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1203,7 +1203,7 @@
class ImageAdmin(XOSBaseAdmin):
fieldsets = [('Image Details',
- {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
+ {'fields': ['backend_status_text', 'name', 'kind', 'disk_format', 'container_format'],
'classes': ['suit-tab suit-tab-general']})
]
readonly_fields = ('backend_status_text', )
@@ -1214,7 +1214,7 @@
user_readonly_fields = ['name', 'disk_format', 'container_format']
- list_display = ['backend_status_icon', 'name']
+ list_display = ['backend_status_icon', 'name', 'kind']
list_display_links = ('backend_status_icon', 'name', )
class NodeForm(forms.ModelForm):
@@ -1282,13 +1282,14 @@
class InstanceAdmin(XOSBaseAdmin):
form = InstanceForm
fieldsets = [
- ('Instance Details', {'fields': ['backend_status_text', 'slice', 'deployment', 'flavor', 'image', 'node', 'all_ips_string', 'instance_id', 'instance_name', 'ssh_command'], 'classes': ['suit-tab suit-tab-general'], })
+ ('Instance Details', {'fields': ['backend_status_text', 'slice', 'deployment', 'isolation', 'flavor', 'image', 'node', 'all_ips_string', 'instance_id', 'instance_name', 'ssh_command', ], 'classes': ['suit-tab suit-tab-general'], }),
+ ('Container Settings', {'fields': ['volumes'], 'classes': ['suit-tab suit-tab-container'], }),
]
readonly_fields = ('backend_status_text', 'ssh_command', 'all_ips_string')
- list_display = ['backend_status_icon', 'all_ips_string', 'instance_id', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deployment']
+ list_display = ['backend_status_icon', 'all_ips_string', 'instance_id', 'instance_name', 'isolation', 'slice', 'flavor', 'image', 'node', 'deployment']
list_display_links = ('backend_status_icon', 'all_ips_string', 'instance_id', )
- suit_form_tabs =(('general', 'Instance Details'), ('ports', 'Ports'))
+ suit_form_tabs =(('general', 'Instance Details'), ('ports', 'Ports'), ('container', 'Container Settings'))
inlines = [TagInline, InstancePortInline]
@@ -1372,38 +1373,38 @@
# obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
# obj.delete()
-class ContainerPortInline(XOSTabularInline):
- fields = ['backend_status_icon', 'network', 'container', 'ip', 'mac', 'segmentation_id']
- readonly_fields = ("backend_status_icon", "ip", "mac", "segmentation_id")
- model = Port
- selflink_fieldname = "network"
- extra = 0
- verbose_name_plural = "Ports"
- verbose_name = "Port"
- suit_classes = 'suit-tab suit-tab-ports'
+#class ContainerPortInline(XOSTabularInline):
+# fields = ['backend_status_icon', 'network', 'container', 'ip', 'mac', 'segmentation_id']
+# readonly_fields = ("backend_status_icon", "ip", "mac", "segmentation_id")
+# model = Port
+# selflink_fieldname = "network"
+# extra = 0
+# verbose_name_plural = "Ports"
+# verbose_name = "Port"
+# suit_classes = 'suit-tab suit-tab-ports'
-class ContainerAdmin(XOSBaseAdmin):
- fieldsets = [
- ('Container Details', {'fields': ['backend_status_text', 'slice', 'node', 'docker_image', 'volumes', 'no_sync'], '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', 'Container Details'), ('ports', 'Ports'))
-
- inlines = [TagInline, ContainerPortInline]
-
- 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 ContainerAdmin(XOSBaseAdmin):
+# fieldsets = [
+# ('Container Details', {'fields': ['backend_status_text', 'slice', 'node', 'docker_image', 'volumes', 'no_sync'], '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', 'Container Details'), ('ports', 'Ports'))
+#
+# inlines = [TagInline, ContainerPortInline]
+#
+# 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
@@ -1760,7 +1761,7 @@
readonly_fields = ('backend_status_icon', )
class NetworkPortInline(XOSTabularInline):
- fields = ['backend_status_icon', 'network', 'instance', 'container', 'ip', 'mac']
+ fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
readonly_fields = ("backend_status_icon", "ip", "mac")
model = Port
selflink_fieldname = "instance"
@@ -2057,5 +2058,5 @@
admin.site.register(TenantRoot, TenantRootAdmin)
admin.site.register(TenantRootRole, TenantRootRoleAdmin)
admin.site.register(TenantAttribute, TenantAttributeAdmin)
- admin.site.register(Container, ContainerAdmin)
+# admin.site.register(Container, ContainerAdmin)
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index bc97dab..c380e9c 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -24,7 +24,6 @@
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/image.py b/xos/core/models/image.py
index 21d4f23..1a3cbf7 100644
--- a/xos/core/models/image.py
+++ b/xos/core/models/image.py
@@ -7,7 +7,10 @@
# Create your models here.
class Image(PlCoreBase):
+ KIND_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), )
+
name = StrippedCharField(max_length=256, unique=True)
+ kind = models.CharField(null=False, blank=False, max_length=30, choices=KIND_CHOICES, default="vm")
disk_format = StrippedCharField(max_length=256)
container_format = StrippedCharField(max_length=256)
path = StrippedCharField(max_length=256, null=True, blank=True, help_text="Path to image on local disk")
diff --git a/xos/core/models/instance.py b/xos/core/models/instance.py
index 75826f6..927c8e3 100644
--- a/xos/core/models/instance.py
+++ b/xos/core/models/instance.py
@@ -80,6 +80,8 @@
# Create your models here.
class Instance(PlCoreBase):
+ ISOLATION_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), )
+
objects = InstanceManager()
deleted_objects = InstanceDeletionManager()
instance_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance id")
@@ -97,6 +99,8 @@
flavor = models.ForeignKey(Flavor, help_text="Flavor of this instance", default=get_default_flavor)
tags = generic.GenericRelation(Tag)
userData = models.TextField(blank=True, null=True, help_text="user_data passed to instance during creation")
+ isolation = models.CharField(null=False, blank=False, max_length=30, choices=ISOLATION_CHOICES, default="vm")
+ volumes = models.TextField(null=True, blank=True, help_text="Comma-separated list of directories to expose to parent context")
def __unicode__(self):
if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index 48af5a6..b12068c 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, Container
+from core.models import PlCoreBase, Site, Slice, Instance, Controller
from core.models import ControllerLinkManager,ControllerLinkDeletionManager
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
@@ -211,7 +211,6 @@
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")
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index c263bba..9646ce8 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -353,8 +353,8 @@
super(TenantWithContainer, self).__init__(*args, **kwargs)
self.cached_instance=None
self.orig_instance_id = self.get_initial_attribute("instance_id")
- self.cached_container=None
- self.orig_container_id = self.get_initial_attribute("container_id")
+# self.cached_container=None
+# self.orig_container_id = self.get_initial_attribute("container_id")
@property
@@ -381,29 +381,29 @@
self.cached_instance=None
self.set_attribute("instance_id", value)
- @property
- def container(self):
- from core.models import Container
- if getattr(self, "cached_container", None):
- return self.cached_container
- container_id=self.get_attribute("container_id")
- if not container_id:
- return None
- containers=Container.objects.filter(id=container_id)
- if not containers:
- return None
- container=containers[0]
- container.caller = self.creator
- self.cached_container = container
- return container
-
- @container.setter
- def container(self, value):
- if value:
- value = value.id
- if (value != self.get_attribute("container_id", None)):
- self.cached_container=None
- self.set_attribute("container_id", value)
+# @property
+# def container(self):
+# from core.models import Container
+# if getattr(self, "cached_container", None):
+# return self.cached_container
+# container_id=self.get_attribute("container_id")
+# if not container_id:
+# return None
+# containers=Container.objects.filter(id=container_id)
+# if not containers:
+# return None
+# container=containers[0]
+# container.caller = self.creator
+# self.cached_container = container
+# return container
+#
+# @container.setter
+# def container(self, value):
+# if value:
+# value = value.id
+# if (value != self.get_attribute("container_id", None)):
+# self.cached_container=None
+# self.set_attribute("container_id", value)
@property
def creator(self):
@@ -464,13 +464,13 @@
nodes = sorted(nodes, key=lambda node: node.instances.all().count())
return nodes[0]
- def pick_node_for_container_on_metal(self):
- from core.models import Node
- nodes = list(Node.objects.all())
- # TODO: logic to filter nodes by which nodes are up, and which
- # nodes the slice can instantiate on.
- nodes = sorted(nodes, key=lambda node: node.containers.all().count())
- return nodes[0]
+# def pick_node_for_container_on_metal(self):
+# from core.models import Node
+# nodes = list(Node.objects.all())
+# # TODO: logic to filter nodes by which nodes are up, and which
+# # nodes the slice can instantiate on.
+# nodes = sorted(nodes, key=lambda node: node.containers.all().count())
+# return nodes[0]
def manage_container_in_instance(self):
from core.models import Instance, Flavor
@@ -506,72 +506,72 @@
instance.delete()
raise
- def manage_container_on_metal(self):
- from core.models import Container, Instance, Flavor, Port
-
- if self.deleted:
- return
-
- if (self.container is not None):
- self.container.delete()
- self.container = None
-
- if self.container is None:
- if not self.provider_service.slices.count():
- raise XOSConfigurationError("The VCPE service has no slices")
-
- slice = self.provider_service.slices.all()[0]
- node = self.pick_node_for_container_on_metal()
-
- # Our current docker network strategy requires that there be some
- # instance on the server that connects to the networks, so that
- # the containers can piggyback off of that configuration.
- instances = Instance.objects.filter(slice=slice, node=node)
- if not instances:
- flavors = Flavor.objects.filter(name="m1.small")
- if not flavors:
- raise XOSConfigurationError("No m1.small flavor")
-
- node =self.pick_node_for_instance()
- instance = Instance(slice = self.provider_service.slices.all()[0],
- node = node,
- image = self.image,
- creator = self.creator,
- deployment = node.site_deployment.deployment,
- flavor = flavors[0])
- instance.save()
-
- # Now make the container...
- container = Container(slice = slice,
- node = node,
- docker_image = "andybavier/docker-vcpe",
- creator = self.creator,
- no_sync=True)
- container.save()
-
- # ... and add the ports for the container
- # XXX probably should be done in model_policy
- for network in slice.networks.all():
- if (network.name.endswith("-nat")):
- continue
- port = Port(network = network,
- container = container)
- port.save()
-
- container.no_sync = False
- container.save()
-
- try:
- self.container = container
- super(TenantWithContainer, self).save()
- except:
- container.delete()
- raise
+# def manage_container_on_metal(self):
+# from core.models import Container, Instance, Flavor, Port
+#
+# if self.deleted:
+# return
+#
+# if (self.container is not None):
+# self.container.delete()
+# self.container = None
+#
+# if self.container is None:
+# if not self.provider_service.slices.count():
+# raise XOSConfigurationError("The VCPE service has no slices")
+#
+# slice = self.provider_service.slices.all()[0]
+# node = self.pick_node_for_container_on_metal()
+#
+# # Our current docker network strategy requires that there be some
+# # instance on the server that connects to the networks, so that
+# # the containers can piggyback off of that configuration.
+# instances = Instance.objects.filter(slice=slice, node=node)
+# if not instances:
+# flavors = Flavor.objects.filter(name="m1.small")
+# if not flavors:
+# raise XOSConfigurationError("No m1.small flavor")
+#
+# node =self.pick_node_for_instance()
+# instance = Instance(slice = self.provider_service.slices.all()[0],
+# node = node,
+# image = self.image,
+# creator = self.creator,
+# deployment = node.site_deployment.deployment,
+# flavor = flavors[0])
+# instance.save()
+#
+# # Now make the container...
+# container = Container(slice = slice,
+# node = node,
+# docker_image = "andybavier/docker-vcpe",
+# creator = self.creator,
+# no_sync=True)
+# container.save()
+#
+# # ... and add the ports for the container
+# # XXX probably should be done in model_policy
+# for network in slice.networks.all():
+# if (network.name.endswith("-nat")):
+# continue
+# port = Port(network = network,
+# container = container)
+# port.save()
+#
+# container.no_sync = False
+# container.save()
+#
+# try:
+# self.container = container
+# super(TenantWithContainer, self).save()
+# except:
+# container.delete()
+# raise
def manage_container(self):
- if self.use_cobm:
- self.manage_container_on_metal()
- else:
+# if self.use_cobm:
+# self.manage_container_on_metal()
+# else:
self.manage_container_in_instance()
def cleanup_container(self):
@@ -579,10 +579,10 @@
# print "XXX cleanup instance", self.instance
self.instance.delete()
self.instance = None
- if self.container:
- # print "XXX cleanup container", self.container
- self.container.delete()
- self.container = None
+# if self.container:
+# # print "XXX cleanup container", self.container
+# self.container.delete()
+# self.container = None
class CoarseTenant(Tenant):
""" TODO: rename "CoarseTenant" --> "StaticTenant" """
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
index c26ac54..297ac4a 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -28,7 +28,9 @@
class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
id = ReadOnlyField()
service_specific_id = ReadOnlyField()
- vlan_id = ReadOnlyField()
+ vlan_id = ReadOnlyField() # XXX remove this
+ c_tag = ReadOnlyField()
+ s_tag = ReadOnlyField()
vcpe_id = ReadOnlyField()
instance = ReadOnlyField()
image = ReadOnlyField()
@@ -59,7 +61,7 @@
class Meta:
model = CordSubscriber
fields = ('humanReadableName', 'id',
- 'service_specific_id', 'vlan_id',
+ 'service_specific_id', 'vlan_id', 's_tag', 'c_tag',
'vcpe_id', 'instance', 'instance_name', 'image', 'image_name',
'firewall_enable', 'firewall_rules',
'url_filter_enable', 'url_filter_rules', 'url_filter_level',
diff --git a/xos/core/xoslib/methods/volttenant.py b/xos/core/xoslib/methods/volttenant.py
index e5998da..bf48290 100644
--- a/xos/core/xoslib/methods/volttenant.py
+++ b/xos/core/xoslib/methods/volttenant.py
@@ -26,7 +26,9 @@
class VOLTTenantIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
id = ReadOnlyField()
service_specific_id = serializers.CharField()
- vlan_id = serializers.CharField()
+ #vlan_id = serializers.CharField()
+ s_tag = serializers.CharField()
+ c_tag = serializers.CharField()
provider_service = serializers.PrimaryKeyRelatedField(queryset=VOLTService.get_service_objects().all(), default=get_default_volt_service)
humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
@@ -35,7 +37,7 @@
class Meta:
model = VOLTTenant
- fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_id', 'vlan_id', 'computeNodeName' )
+ fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_id', 's_tag', 'c_tag', 'computeNodeName' )
def getHumanReadableName(self, obj):
return obj.__unicode__()
@@ -62,9 +64,19 @@
if service_specific_id is not None:
queryset = queryset.filter(service_specific_id=service_specific_id)
- vlan_id = self.request.QUERY_PARAMS.get('vlan_id', None)
- if vlan_id is not None:
- ids = [x.id for x in queryset if x.get_attribute("vlan_id", None)==vlan_id]
+# vlan_id = self.request.QUERY_PARAMS.get('vlan_id', None)
+# if vlan_id is not None:
+# ids = [x.id for x in queryset if x.get_attribute("vlan_id", None)==vlan_id]
+# queryset = queryset.filter(id__in=ids)
+
+ c_tag = self.request.QUERY_PARAMS.get('c_tag', None)
+ if c_tag is not None:
+ ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
+ queryset = queryset.filter(id__in=ids)
+
+ s_tag = self.request.QUERY_PARAMS.get('s_tag', None)
+ if s_tag is not None:
+ ids = [x.id for x in queryset if x.get_attribute("s_tag", None)==s_tag]
queryset = queryset.filter(id__in=ids)
return queryset
@@ -74,7 +86,7 @@
existing_obj = None
for obj in VOLTTenant.get_tenant_objects().all():
- if (obj.vlan_id == data.get("vlan_id", None)) and (obj.service_specific_id == data.get("service_specific_id",None)):
+ if (obj.c_tag == data.get("c_tag", None)) and (obj.s_tag == data.get("s_tag", None)) and (obj.service_specific_id == data.get("service_specific_id",None)):
existing_obj = obj
if existing_obj:
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
index 318d54c..089c91b 100644
--- a/xos/core/xoslib/objects/cordsubscriber.py
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -113,7 +113,9 @@
# ("services", "vcpe.services"),
# ("cdn_enable", "vcpe.cdn_enable"),
- ("vlan_id", "volt.vlan_id"),
+ ("vlan_id", "volt.vlan_id"), # XXX remove this
+ ("c_tag", "volt.c_tag"),
+ ("s_tag", "volt.s_tag"),
("bbs_account", "volt.vcpe.bbs_account"),
("ssh_command", "volt.vcpe.ssh_command"),
diff --git a/xos/core/xoslib/templates/xosCordSubscriber.html b/xos/core/xoslib/templates/xosCordSubscriber.html
index b7e2163..db42fb8 100644
--- a/xos/core/xoslib/templates/xosCordSubscriber.html
+++ b/xos/core/xoslib/templates/xosCordSubscriber.html
@@ -7,7 +7,8 @@
<table class="xos-detail-table cord-subscriber-table">
<tr><td class="xos-label-cell">Id:</td><td><%= model.attributes.id %></td></tr>
<tr><td class="xos-label-cell">Service Specific Id:</td><td><%= model.attributes.service_specific_id %></td></tr>
- <tr><td class="xos-label-cell">VLAN Id:</td><td><%= model.attributes.vlan_id %></td></tr>
+ <tr><td class="xos-label-cell">S-Tag:</td><td><%= model.attributes.s_tag %></td></tr>
+ <tr><td class="xos-label-cell">C-Tag:</td><td><%= model.attributes.c_tag %></td></tr>
</table>
</div>
diff --git a/xos/model_policies/model_policy_Image.py b/xos/model_policies/model_policy_Image.py
index 72f76fa..c77d5bb 100644
--- a/xos/model_policies/model_policy_Image.py
+++ b/xos/model_policies/model_policy_Image.py
@@ -2,6 +2,10 @@
from core.models import Controller, ControllerImages, Image
from collections import defaultdict
+ if (image.kind == "container"):
+ # container images do not get instantiated
+ return
+
controller_images = ControllerImages.objects.filter(image=image)
existing_controllers = [cs.controller for cs in controller_images]
diff --git a/xos/model_policies/model_policy_Instance.py b/xos/model_policies/model_policy_Instance.py
index a13428d..23761f3 100644
--- a/xos/model_policies/model_policy_Instance.py
+++ b/xos/model_policies/model_policy_Instance.py
@@ -1,3 +1,35 @@
+def handle_container_on_metal(instance):
+ from core.models import Instance, Flavor, Port, Image
+
+ if instance.deleted:
+ return
+
+ # Our current docker network strategy requires that there be some
+ # VM on the server that connects to the networks, so that
+ # the containers can piggyback off of that configuration.
+ if not Instance.objects.filter(slice=instance.slice, node=instance.node, isolation="vm").exists():
+ flavors = Flavor.objects.filter(name="m1.small")
+ if not flavors:
+ raise XOSConfigurationError("No m1.small flavor")
+
+ images = Image.objects.filter(kind="vm")
+
+ companion_instance = Instance(slice = instance.slice,
+ node = instance.node,
+ image = images[0],
+ creator = instance.creator,
+ deployment = instance.node.site_deployment.deployment,
+ flavor = flavors[0])
+ companion_instance.save()
+
+ # Add the ports for the container
+ for network in instance.slice.networks.all():
+ if (network.name.endswith("-nat")):
+ continue
+
+ if not Port.objects.filter(network=network, instance=instance).exists():
+ port = Port(network = network, instance=instance)
+ port.save()
def handle(instance):
from core.models import Controller, ControllerSlice, ControllerNetwork, NetworkSlice
@@ -7,7 +39,10 @@
controller=instance.node.site_deployment.controller)
for cn in controller_networks:
- if (cn.lazy_blocked):
+ if (cn.lazy_blocked):
cn.lazy_blocked=False
cn.backend_register = '{}'
cn.save()
+
+ if (instance.isolation=="container"):
+ handle_container_on_metal(instance)
diff --git a/xos/observers/vcpe/steps/sync_vcpetenant.py b/xos/observers/vcpe/steps/sync_vcpetenant.py
index 1a45b54..120954b 100644
--- a/xos/observers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/observers/vcpe/steps/sync_vcpetenant.py
@@ -113,15 +113,21 @@
logger.info("neither bbs_slice nor bbs_server is configured in the vCPE")
vlan_ids = []
+ s_tags = []
+ c_tags = []
if o.volt:
- vlan_ids.append(o.volt.vlan_id)
+ vlan_ids.append(o.volt.vlan_id) # XXX remove this
+ s_tags.append(o.volt.s_tag)
+ c_tags.append(o.volt.c_tag)
try:
full_setup = Config().observer_full_setup
except:
full_setup = True
- fields = {"vlan_ids": vlan_ids,
+ fields = {"vlan_ids": vlan_ids, # XXX remove this
+ "s_tags": s_tags,
+ "c_tags": c_tags,
"dnsdemux_ip": dnsdemux_ip,
"cdn_prefixes": cdn_prefixes,
"bbs_addrs": bbs_addrs,
diff --git a/xos/observers/vcpe/steps/sync_vcpetenant.yaml b/xos/observers/vcpe/steps/sync_vcpetenant.yaml
index b5a112a..e4d3167 100644
--- a/xos/observers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/observers/vcpe/steps/sync_vcpetenant.yaml
@@ -13,6 +13,14 @@
{% for vlan_id in vlan_ids %}
- {{ vlan_id }}
{% endfor %}
+ c_tags:
+ {% for c_tag in c_tags %}
+ - {{ c_tag }}
+ {% endfor %}
+ s_tags:
+ {% for s_tag in s_tags %}
+ - {{ s_tag }}
+ {% endfor %}
firewall_rules:
{% for firewall_rule in firewall_rules.split("\n") %}
- {{ firewall_rule }}
diff --git a/xos/openstack_observer/steps/sync_container.py b/xos/openstack_observer/steps/sync_container.py
index 0f5dcc4..26e03e5 100644
--- a/xos/openstack_observer/steps/sync_container.py
+++ b/xos/openstack_observer/steps/sync_container.py
@@ -8,7 +8,7 @@
from xos.config import Config
from observer.syncstep import SyncStep
from observer.ansible import run_template_ssh
-from core.models import Service, Slice, Container
+from core.models import Service, Slice, Instance
from services.onos.models import ONOSService, ONOSApp
from util.logger import Logger, logging
@@ -19,34 +19,28 @@
logger = Logger(level=logging.INFO)
class SyncContainer(SyncStep):
- provides=[Container]
- observes=Container
+ provides=[Instance]
+ observes=Instance
requested_interval=0
template_name = "sync_container.yaml"
def __init__(self, *args, **kwargs):
super(SyncContainer, self).__init__(*args, **kwargs)
-# def fetch_pending(self, deleted):
-# if (not deleted):
-# objs = ONOSService.get_service_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
-# else:
-# objs = ONOSService.get_deleted_service_objects()
-#
-# return objs
+ def fetch_pending(self, deletion=False):
+ objs = super(SyncContainer, self).fetch_pending(deletion)
+ objs = [x for x in objs if x.isolation=="container"]
+ return objs
def get_node(self,o):
return o.node
def get_node_key(self, node):
return "/root/setup/node_key"
- #return "/opt/xos/node-key"
def get_instance_port(self, container_port):
- print container_port
- print container_port.network
for p in container_port.network.links.all():
- if (p.instance) and (p.instance.node == container_port.container.node) and (p.mac):
+ if (p.instance) and (p.instance.isolation=="vm") and (p.instance.node == container_port.instance.node) and (p.mac):
return p
return None
@@ -81,7 +75,7 @@
fields["baremetal_ssh"] = True
fields["instance_name"] = "rootcontext"
fields["container_name"] = "%s-%s" % (o.slice.name, str(o.id))
- fields["docker_image"] = o.docker_image
+ fields["docker_image"] = o.image.name
fields["username"] = "root"
fields["ports"] = self.get_ports(o)
fields["volumes"] = [x.strip() for x in o.volumes.split(",")]
diff --git a/xos/openstack_observer/steps/sync_instances.py b/xos/openstack_observer/steps/sync_instances.py
index 1209448..1130c24 100644
--- a/xos/openstack_observer/steps/sync_instances.py
+++ b/xos/openstack_observer/steps/sync_instances.py
@@ -22,6 +22,11 @@
observes=Instance
playbook='sync_instances.yaml'
+ def fetch_pending(self, deletion=False):
+ objs = super(SyncInstances, self).fetch_pending(deletion)
+ objs = [x for x in objs if x.isolation=="vm"]
+ return objs
+
def get_userdata(self, instance, pubkeys):
userdata = '#cloud-config\n\nopencloud:\n slicename: "%s"\n hostname: "%s"\n restapi_hostname: "%s"\n restapi_port: "%s"\n' % (instance.slice.name, instance.node.name, RESTAPI_HOSTNAME, str(RESTAPI_PORT))
userdata += 'ssh_authorized_keys:\n'
diff --git a/xos/openstack_observer/steps/sync_ports.py b/xos/openstack_observer/steps/sync_ports.py
index 7b20d29..178fa86 100644
--- a/xos/openstack_observer/steps/sync_ports.py
+++ b/xos/openstack_observer/steps/sync_ports.py
@@ -144,14 +144,11 @@
# 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(Q(port_id__isnull=True), Q(instance__isnull=False) | Q(container__isnull=False)):
+ for port in Port.objects.filter(Q(port_id__isnull=True), Q(instance__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
+ controller = port.instance.node.site_deployment.controller
+ slice = port.instance.slice
+
if controller:
cn=port.network.controllernetworks.filter(controller=controller)
if not cn:
diff --git a/xos/openstack_observer/templates/start-container.sh.j2 b/xos/openstack_observer/templates/start-container.sh.j2
index dc3b7cb..86491eb 100644
--- a/xos/openstack_observer/templates/start-container.sh.j2
+++ b/xos/openstack_observer/templates/start-container.sh.j2
@@ -6,11 +6,13 @@
CONTAINER={{ container_name }}
IMAGE={{ docker_image }}
+{% if volumes %}
{% for volume in volumes %}
DEST_DIR=/var/container_volumes/$CONTAINER/{{ volume }}
mkdir -p $DEST_DIR
VOLUME_ARGS="$VOLUME_ARGS -v $DEST_DIR:{{ volume }}"
{% endfor %}
+{% endif %}
docker inspect $CONTAINER > /dev/null 2>&1
if [ "$?" == 1 ]
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 88d8f5f..aca3e3e 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -236,10 +236,14 @@
specific vlan_id.
properties:
xos_base_tenant_props
- vlan_id:
+ s_tag:
type: string
required: false
- description: vlan_id for connection to subscriber household.
+ description: s_tag, identifies which volt port
+ c_tag:
+ type: string
+ required: false
+ description: c_tag, identifies which subscriber within s_tag
tosca.nodes.User:
derived_from: tosca.nodes.Root
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 4352ef5..63b4e0c 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -364,10 +364,14 @@
type: string
required: false
description: Service specific ID opaque to XOS but meaningful to service
- vlan_id:
+ s_tag:
type: string
required: false
- description: vlan_id for connection to subscriber household.
+ description: s_tag, identifies which volt port
+ c_tag:
+ type: string
+ required: false
+ description: c_tag, identifies which subscriber within s_tag
tosca.nodes.User:
derived_from: tosca.nodes.Root
diff --git a/xos/tosca/resources/VOLTTenant.py b/xos/tosca/resources/VOLTTenant.py
index f00b515..89c24e3 100644
--- a/xos/tosca/resources/VOLTTenant.py
+++ b/xos/tosca/resources/VOLTTenant.py
@@ -14,7 +14,7 @@
class XOSVOLTTenant(XOSResource):
provides = "tosca.nodes.VOLTTenant"
xos_model = VOLTTenant
- copyin_props = ["service_specific_id", "vlan_id"]
+ copyin_props = ["service_specific_id", "s_tag", "c_tag"]
name_field = None
def get_xos_args(self, throw_exception=True):
diff --git a/xos/tosca/samples/cord.yaml b/xos/tosca/samples/cord.yaml
index 477be2f..567ced0 100644
--- a/xos/tosca/samples/cord.yaml
+++ b/xos/tosca/samples/cord.yaml
@@ -125,7 +125,8 @@
type: tosca.nodes.VOLTTenant
properties:
service_specific_id: 1234
- vlan_id: 4321
+ s_tag: 222
+ c_tag: 432
requirements:
- provider_service:
node: service_volt