Merge branch 'master' of https://github.com/open-cloud/xos
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index b5ba737..1a1b6ef 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -554,6 +554,22 @@
self.set_attribute("instance_id", value)
@property
+ def external_hostname(self):
+ return self.get_attribute("external_hostname", "")
+
+ @external_hostname.setter
+ def external_hostname(self, value):
+ self.set_attribute("external_hostname", value)
+
+ @property
+ def external_container(self):
+ return self.get_attribute("external_container", "")
+
+ @external_container.setter
+ def external_container(self, value):
+ self.set_attribute("external_container", value)
+
+ @property
def creator(self):
from core.models import User
if getattr(self, "cached_creator", None):
diff --git a/xos/services/onos/admin.py b/xos/services/onos/admin.py
index 3f9f96c..fb0f1d7 100644
--- a/xos/services/onos/admin.py
+++ b/xos/services/onos/admin.py
@@ -19,16 +19,28 @@
from django.contrib.admin.utils import quote
class ONOSServiceForm(forms.ModelForm):
- use_external_host = forms.CharField(required=False)
+ rest_hostname = forms.CharField(required=False)
+ rest_port = forms.CharField(required=False)
+ no_container = forms.BooleanField(required=False)
+# external_hostname = forms.CharField(required=False)
+# external_container = forms.CharField(required=False)
def __init__(self,*args,**kwargs):
super (ONOSServiceForm,self ).__init__(*args,**kwargs)
if self.instance:
# fields for the attributes
- self.fields['use_external_host'].initial = self.instance.use_external_host
+ self.fields['rest_hostname'].initial = self.instance.rest_hostname
+ self.fields['rest_port'].initial = self.instance.rest_port
+ self.fields['no_container'].initial = self.instance.no_container
+# self.fields['external_hostname'].initial = self.instance.external_hostname
+# self.fields['external_container'].initial = self.instance.external_hostname
def save(self, commit=True):
- self.instance.use_external_host = self.cleaned_data.get("use_external_host")
+ self.instance.rest_hostname = self.cleaned_data.get("rest_hostname")
+ self.instance.rest_port = self.cleaned_data.get("rest_port")
+ self.instance.no_container = self.cleaned_data.get("no_container")
+# self.instance.external_hostname = self.cleaned_data.get("external_hostname")
+# self.instance.external_container = self.cleaned_data.get("external_container")
return super(ONOSServiceForm, self).save(commit=commit)
class Meta:
@@ -40,7 +52,7 @@
verbose_name_plural = "ONOS Services"
list_display = ("backend_status_icon", "name", "enabled")
list_display_links = ('backend_status_icon', 'name', )
- fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "use_external_host" ], 'classes':['suit-tab suit-tab-general']})]
+ fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "rest_hostname", "rest_port", "no_container" ], 'classes':['suit-tab suit-tab-general']})]
readonly_fields = ('backend_status_text', )
inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
form = ONOSServiceForm
diff --git a/xos/services/onos/models.py b/xos/services/onos/models.py
index 1e869d1..4be2c1b 100644
--- a/xos/services/onos/models.py
+++ b/xos/services/onos/models.py
@@ -21,15 +21,34 @@
verbose_name = "ONOS Service"
proxy = True
- default_attributes = {"use_external_host": ""}
+ default_attributes = {"rest_hostname": "",
+ "rest_port": "8181",
+ "no_container": False}
@property
- def use_external_host(self):
- return self.get_attribute("use_external_host", self.default_attributes["use_external_host"])
+ def rest_hostname(self):
+ return self.get_attribute("rest_hostname", self.default_attributes["rest_hostname"])
- @use_external_host.setter
- def use_external_host(self, value):
- self.set_attribute("use_external_host", value)
+ @rest_hostname.setter
+ def rest_hostname(self, value):
+ self.set_attribute("rest_hostname", value)
+
+ @property
+ def rest_port(self):
+ return self.get_attribute("rest_port", self.default_attributes["rest_port"])
+
+ @rest_port.setter
+ def rest_port(self, value):
+ self.set_attribute("rest_port", value)
+
+ @property
+ def no_container(self):
+ return self.get_attribute("no_container", self.default_attributes["no_container"])
+
+ @no_container.setter
+ def no_container(self, value):
+ self.set_attribute("no_container", value)
+
class ONOSApp(Tenant): # aka 'ONOSTenant'
class Meta:
@@ -93,19 +112,6 @@
def install_dependencies(self, value):
self.set_attribute("install_dependencies", value)
- #@property
- #def instance(self):
- # instance_id = self.get_attribute("instance_id", self.default_attributes["instance_id"])
- # if instance_id:
- # instances = Instance.objects.filter(id=instance_id)
- # if instances:
- # return instances[0]
- # return None
-
- #@instance.setter
- #def instance(self, value):
- # self.set_attribute("instance_id", value.id)
-
def save(self, *args, **kwargs):
if not self.creator:
if not getattr(self, "caller", None):
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
index 335932f..95c7b22 100644
--- a/xos/synchronizers/base/SyncInstanceUsingAnsible.py
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -26,6 +26,12 @@
def __init__(self, **args):
SyncStep.__init__(self, **args)
+ def skip_ansible_fields(self, o):
+ # Return True if the instance processing and get_ansible_fields stuff
+ # should be skipped. This hook is primarily for the OnosApp
+ # sync step, so it can do its external REST API sync thing.
+ return False
+
def defer_sync(self, o, reason):
logger.info("defer object %s due to %s" % (str(o), reason))
raise Exception("defer object %s due to %s" % (str(o), reason))
@@ -44,6 +50,14 @@
return o.instance
+ def get_external_sync(self, o):
+ hostname = getattr(o, "external_hostname", None)
+ container = getattr(o, "external_container", None)
+ if hostname and container:
+ return (hostname, container)
+ else:
+ return None
+
def run_playbook(self, o, fields, template_name=None):
if not template_name:
template_name = self.template_name
@@ -142,30 +156,43 @@
self.prepare_record(o)
- instance = self.get_instance(o)
-
- if isinstance(instance, basestring):
- # sync to some external host
-
- # XXX - this probably needs more work...
-
- fields = { "hostname": instance,
- "instance_id": "ubuntu", # this is the username to log into
- "private_key": service.key,
- }
+ if self.skip_ansible_fields(o):
+ fields = {}
else:
- # sync to an XOS instance
- if not instance:
- self.defer_sync(o, "waiting on instance")
- return
+ if self.get_external_sync(o):
+ # sync to some external host
- if not instance.instance_name:
- self.defer_sync(o, "waiting on instance.instance_name")
- return
+ # UNTESTED
- fields = self.get_ansible_fields(instance)
+ (hostname, container_name) = self.get_external_sync(o)
+ fields = { "hostname": hostname,
+ "baremetal_ssh": True,
+ "instance_name": "rootcontext",
+ "username": "root",
+ "container_name": container_name
+ }
+ key_name = self.get_node_key(node)
+ if not os.path.exists(key_name):
+ raise Exception("Node key %s does not exist" % key_name)
- fields["ansible_tag"] = o.__class__.__name__ + "_" + str(o.id)
+ key = file(key_name).read()
+
+ fields["private_key"] = key
+ # TO DO: Ceilometer stuff
+ else:
+ instance = self.get_instance(o)
+ # sync to an XOS instance
+ if not instance:
+ self.defer_sync(o, "waiting on instance")
+ return
+
+ if not instance.instance_name:
+ self.defer_sync(o, "waiting on instance.instance_name")
+ return
+
+ fields = self.get_ansible_fields(instance)
+
+ fields["ansible_tag"] = o.__class__.__name__ + "_" + str(o.id)
# If 'o' defines a 'sync_attributes' list, then we'll copy those
# attributes into the Ansible recipe's field list automatically.
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 8942e59..c55a0d6 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -9,6 +9,7 @@
import json
from django.db.models import F, Q
from xos.config import Config
+from synchronizers.base.ansible import run_template
from synchronizers.base.syncstep import SyncStep
from synchronizers.base.ansible import run_template_ssh
from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
@@ -46,8 +47,8 @@
serv = self.get_onos_service(o)
- if serv.use_external_host:
- return serv.use_external_host
+ if serv.no_container:
+ raise Exception("get_instance() was called on a service that was marked no_container")
if serv.slices.exists():
slice = serv.slices.all()[0]
@@ -66,6 +67,12 @@
return onoses[0]
+ def is_no_container(self, o):
+ return self.get_onos_service(o).no_container
+
+ def skip_ansible_fields(self, o):
+ return self.is_no_container(o)
+
def get_files_dir(self, o):
if not hasattr(Config(), "observer_steps_dir"):
# make steps_dir mandatory; there's no valid reason for it to not
@@ -126,7 +133,7 @@
ordered_attrs = attrs.keys()
o.early_rest_configs=[]
- if ("cordvtn" in o.dependencies):
+ if ("cordvtn" in o.dependencies) and (not self.is_no_container(o)):
# For VTN, since it's running in a docker host container, we need
# to make sure it configures the cluster using the right ip addresses.
# NOTE: rest_onos/v1/cluster/configuration/ will reboot the cluster and
@@ -172,22 +179,37 @@
def prepare_record(self, o):
self.write_configs(o)
- def get_extra_attributes(self, o):
- instance = self.get_instance(o)
+ def get_extra_attributes_common(self, o):
+ fields = {}
- fields={}
+ # These are attributes that are not dependent on Instance. For example,
+ # REST API stuff.
+
+ onos = self.get_onos_service(o)
+
fields["files_dir"] = o.files_dir
fields["appname"] = o.name
- fields["nat_ip"] = instance.get_ssh_ip()
- fields["config_fns"] = o.config_fns
fields["rest_configs"] = o.rest_configs
- fields["early_rest_configs"] = o.early_rest_configs
- fields["component_configs"] = o.component_configs
+ fields["rest_hostname"] = onos.rest_hostname
+ fields["rest_port"] = onos.rest_port
+
if o.dependencies:
fields["dependencies"] = [x.strip() for x in o.dependencies.split(",")]
else:
fields["dependencies"] = []
+ return fields
+
+ def get_extra_attributes_full(self, o):
+ instance = self.get_instance(o)
+
+ fields = self.get_extra_attributes_common(o)
+
+ fields["nat_ip"] = instance.get_ssh_ip()
+ fields["config_fns"] = o.config_fns
+ fields["early_rest_configs"] = o.early_rest_configs
+ fields["component_configs"] = o.component_configs
+
if o.install_dependencies:
fields["install_dependencies"] = [x.strip() for x in o.install_dependencies.split(",")]
else:
@@ -199,12 +221,23 @@
fields["ONOS_container"] = "ONOS"
return fields
+ def get_extra_attributes(self, o):
+ if self.is_no_container(o):
+ return self.get_extra_attributes_common(o)
+ else:
+ return self.get_extra_attributes_full(o)
+
def sync_fields(self, o, fields):
# the super causes the playbook to be run
super(SyncONOSApp, self).sync_fields(o, fields)
def run_playbook(self, o, fields):
- super(SyncONOSApp, self).run_playbook(o, fields)
+ if self.is_no_container(o):
+ # There is no machine to SSH to, so use the synchronizer's
+ # run_template method directly.
+ run_template("sync_onosapp_nocontainer.yaml", fields)
+ else:
+ super(SyncONOSApp, self).run_playbook(o, fields)
def delete_record(self, m):
pass
diff --git a/xos/synchronizers/onos/steps/sync_onosservice.py b/xos/synchronizers/onos/steps/sync_onosservice.py
index e70be0c..2e9bb38 100644
--- a/xos/synchronizers/onos/steps/sync_onosservice.py
+++ b/xos/synchronizers/onos/steps/sync_onosservice.py
@@ -43,9 +43,6 @@
serv = o
- if serv.use_external_host:
- return serv.use_external_host
-
if serv.slices.exists():
slice = serv.slices.all()[0]
if slice.instances.exists():
@@ -61,6 +58,13 @@
fields["ONOS_container"] = "ONOS"
return fields
+ def sync_record(self, o):
+ if o.no_container:
+ logger.info("no work to do for onos service, because o.no_container is set")
+ o.save()
+ else:
+ super(SyncONOSService, self).sync_record(o)
+
def sync_fields(self, o, fields):
# the super causes the playbook to be run
super(SyncONOSService, self).sync_fields(o, fields)