Library support
Change-Id: I25c37cb3aeea767896fab87e4b1fb11449abe8a0
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 83492ab..fa33a7f 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1051,8 +1051,8 @@
('serviceprivileges', 'Privileges')
)
-class ServiceControllerResourceInline(XOSTabularInline):
- model = ServiceControllerResource
+class LoadableModuleResourceInline(XOSTabularInline):
+ model = LoadableModuleResource
fields = ['name', 'kind', 'format', 'url']
extra = 0
suit_classes = 'suit-tab suit-tab-resources'
@@ -1063,12 +1063,27 @@
fieldList = ["backend_status_text", "name", "xos", "version", "provides", "requires", "base_url", "synchronizer_run", "synchronizer_config", "no_start"]
fieldsets = [
(None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
- inlines = [ServiceControllerResourceInline]
+ inlines = [LoadableModuleResourceInline]
readonly_fields = ('backend_status_text', )
user_readonly_fields = fieldList
- suit_form_tabs = (('general', 'Service Details'),
+ suit_form_tabs = (('general', 'Service Controller Details'),
+ ('resources', 'Resources'),
+ )
+
+class LibraryAdmin(XOSBaseAdmin):
+ list_display = ("backend_status_icon", "name",)
+ list_display_links = ('backend_status_icon', 'name',)
+ fieldList = ["backend_status_text", "name", "xos", "version", "provides", "requires", "base_url"]
+ fieldsets = [
+ (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+ inlines = [LoadableModuleResourceInline]
+ readonly_fields = ('backend_status_text', )
+
+ user_readonly_fields = fieldList
+
+ suit_form_tabs = (('general', 'Library Details'),
('resources', 'Resources'),
)
@@ -2451,6 +2466,7 @@
admin.site.register(Slice, SliceAdmin)
admin.site.register(Service, ServiceAdmin)
admin.site.register(ServiceController, ServiceControllerAdmin)
+admin.site.register(Library, LibraryAdmin)
admin.site.register(XOS, XosModelAdmin)
admin.site.register(Network, NetworkAdmin)
admin.site.register(Port, PortAdmin)
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index abf8da2..4138b22 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -4,7 +4,7 @@
from .xosmodel import XOS, XOSVolume
from .service import Service, Tenant, TenantWithContainer, CoarseTenant, ServicePrivilege, TenantRoot, TenantRootPrivilege, TenantRootRole, TenantPrivilege, TenantRole, Subscriber, Provider
from .service import ServiceAttribute, TenantAttribute, ServiceRole
-from .service import ServiceController, ServiceControllerResource, LoadableModule, LoadableModuleResource
+from .service import ServiceController, ServiceControllerResource, LoadableModule, LoadableModuleResource, Library
from .tag import Tag
from .role import Role
from .site import Site, Deployment, DeploymentRole, DeploymentPrivilege, Controller, ControllerRole, ControllerSite, SiteDeployment,Diag
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index 2685fe4..a6ee7a8 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -187,6 +187,10 @@
else:
return self.url
+class Library(LoadableModule):
+ # for now, it's exactly like a LoadableModule
+ pass
+
class ServiceController(LoadableModule):
synchronizer_run = StrippedCharField(max_length=1024, help_text="synchronizer run command", null=True, blank=True)
synchronizer_config = StrippedCharField(max_length=1024, help_text="synchronizer config file", null=True, blank=True)
diff --git a/xos/synchronizers/onboarding/model-deps b/xos/synchronizers/onboarding/model-deps
index 4aa86c7..e887a31 100644
--- a/xos/synchronizers/onboarding/model-deps
+++ b/xos/synchronizers/onboarding/model-deps
@@ -1,8 +1,12 @@
{
"XOS": [
- "ServiceController"
+ "ServiceController",
+ "Library"
],
"ServiceController": [
"ServiceControllerResource"
+ ],
+ "Library": [
+ "ServiceControllerResource"
]
}
diff --git a/xos/synchronizers/onboarding/steps/sync_library.py b/xos/synchronizers/onboarding/steps/sync_library.py
new file mode 100644
index 0000000..5a8a4c1
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_library.py
@@ -0,0 +1,47 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from core.models import XOS, Library
+from xos.logger import Logger, logging
+from synchronizers.base.ansible import run_template
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncLibrary(SyncStep, XOSBuilder):
+ provides=[Library]
+ observes=Library
+ requested_interval=0
+
+ def __init__(self, **args):
+ SyncStep.__init__(self, **args)
+ XOSBuilder.__init__(self)
+
+ def sync_record(self, sc):
+ logger.info("Sync'ing Library %s" % sc)
+
+ if sc.xos and (not sc.xos.enable_build):
+ raise DeferredException("XOS build is currently disabled")
+
+ unready = self.check_controller_unready(sc)
+ if unready:
+ raise Exception("Controller %s has unready resources: %s" % (str(sc), ",".join([str(x) for x in unready])))
+
+ # There's nothing to actually do, since there's no synchronizer
+ # container for libraries.
+
+ def delete_record(self, m):
+ pass
+
+ def fetch_pending(self, deleted=False):
+ pend = super(SyncLibrary, self).fetch_pending(deleted)
+ return pend
+
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 6372f9c..f500ca7 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -164,6 +164,69 @@
required: false
description: url of resource, may be relative to base_url or absolute
+ tosca.nodes.Library:
+ derived_from: tosca.nodes.Root
+ description: >
+ An XOS Library.
+ properties:
+ xos_base_props
+ base_url:
+ type: string
+ required: false
+ description: Base url, to allow resources to use relative URLs
+ version:
+ type: string
+ required: false
+ description: Version number of this Service Controller
+ provides:
+ type: string
+ required: false
+ description: Comma-separated list of things provided
+ requires:
+ type: string
+ required: false
+ description: Comma-separated list of requirements
+ models:
+ type: string
+ required: false
+ description: url of models.py
+ admin:
+ type: string
+ required: false
+ description: url of admin.py
+ django_library:
+ type: string
+ required: false
+ description: libraries used by admin or models
+ admin_template:
+ type: string
+ required: false
+ description: url of admin html template
+ tosca_custom_types:
+ type: string
+ required: false
+ description: url of tosca custom_types
+ tosca_resource:
+ type: string
+ required: false
+ description: url of tosca resource
+ rest_service:
+ type: string
+ required: false
+ description: url of REST API service file
+ rest_tenant:
+ type: string
+ required: false
+ description: url of REST API tenant file
+ private_key:
+ type: string
+ required: false
+ description: private key
+ public_key:
+ type: string
+ required: false
+ description: public key
+
tosca.nodes.Tenant:
derived_from: tosca.nodes.Root
description: >
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 44ade1f..9c79786 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -287,6 +287,84 @@
required: false
description: url of resource, may be relative to base_url or absolute
+ tosca.nodes.Library:
+ derived_from: tosca.nodes.Root
+ description: >
+ An XOS Library.
+ properties:
+ no-delete:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to delete this object
+ no-create:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to create this object
+ no-update:
+ type: boolean
+ default: false
+ description: Do not allow Tosca to update this object
+ replaces:
+ type: string
+ required: false
+ descrption: Replaces/renames this object
+ base_url:
+ type: string
+ required: false
+ description: Base url, to allow resources to use relative URLs
+ version:
+ type: string
+ required: false
+ description: Version number of this Service Controller
+ provides:
+ type: string
+ required: false
+ description: Comma-separated list of things provided
+ requires:
+ type: string
+ required: false
+ description: Comma-separated list of requirements
+ models:
+ type: string
+ required: false
+ description: url of models.py
+ admin:
+ type: string
+ required: false
+ description: url of admin.py
+ django_library:
+ type: string
+ required: false
+ description: libraries used by admin or models
+ admin_template:
+ type: string
+ required: false
+ description: url of admin html template
+ tosca_custom_types:
+ type: string
+ required: false
+ description: url of tosca custom_types
+ tosca_resource:
+ type: string
+ required: false
+ description: url of tosca resource
+ rest_service:
+ type: string
+ required: false
+ description: url of REST API service file
+ rest_tenant:
+ type: string
+ required: false
+ description: url of REST API tenant file
+ private_key:
+ type: string
+ required: false
+ description: private key
+ public_key:
+ type: string
+ required: false
+ description: public key
+
tosca.nodes.Tenant:
derived_from: tosca.nodes.Root
description: >
diff --git a/xos/tosca/resources/library.py b/xos/tosca/resources/library.py
new file mode 100644
index 0000000..777fc3a
--- /dev/null
+++ b/xos/tosca/resources/library.py
@@ -0,0 +1,16 @@
+from core.models import LoadableModule, LoadableModuleResource, Library
+
+from loadablemodule import XOSLoadableModule
+
+# This is like ServiceController, but with the synchronizer stuff removed
+
+class XOSLibrary(XOSLoadableModule):
+ provides = "tosca.nodes.Library"
+ xos_model = Library
+ copyin_props = ["version", "provides", "requires", "base_url"]
+
+ def postprocess(self, obj):
+ super(XOSLibrary, self).postprocess(obj)
+
+
+
diff --git a/xos/tosca/resources/loadablemodule.py b/xos/tosca/resources/loadablemodule.py
new file mode 100644
index 0000000..92e3ebb
--- /dev/null
+++ b/xos/tosca/resources/loadablemodule.py
@@ -0,0 +1,68 @@
+from core.models import LoadableModule, LoadableModuleResource
+
+from xosresource import XOSResource
+
+class XOSLoadableModule(XOSResource):
+
+ # This doesn't provide anything. It's a base class for XOSLibrary and XOSServiceController
+
+ def postprocess_resource_prop(self, obj, kind, format):
+ values = self.get_property(kind)
+ if values:
+ for i,value in enumerate(values.split(",")):
+ value = value.strip()
+ subdirectory = None
+
+ name=kind
+ if i>0:
+ name = "%s_%d" %( name, i)
+
+ if (" " in value):
+ parts=value.split()
+ for part in parts[:-1]:
+ if ":" in part:
+ (lhs, rhs) = part.split(":", 1)
+ if lhs=="subdirectory":
+ subdirectory=rhs
+ else:
+ raise Exception("Malformed value %s" % value)
+ else:
+ raise Exception("Malformed value %s" % value)
+ value = parts[-1]
+
+
+ scr = LoadableModuleResource.objects.filter(loadable_module=obj, name=name, kind=kind, format=format)
+ if scr:
+ scr=scr[0]
+ if (scr.url != value) or (scr.subdirectory!=subdirectory):
+ self.info("updating resource %s" % kind)
+ scr.url = value
+ scr.subdirectory = subdirectory
+ scr.save()
+ else:
+ self.info("adding resource %s" % kind)
+ scr = LoadableModuleResource(loadable_module=obj, name=name, kind=kind, format=format, url=value, subdirectory=subdirectory)
+ scr.save()
+
+ def postprocess(self, obj):
+ # allow these common resource to be specified directly by the LoadableModule tosca object and its descendents
+ self.postprocess_resource_prop(obj, "models", "python")
+ self.postprocess_resource_prop(obj, "admin", "python")
+ self.postprocess_resource_prop(obj, "django_library", "python")
+ self.postprocess_resource_prop(obj, "admin_template", "raw")
+ self.postprocess_resource_prop(obj, "tosca_custom_types", "yaml")
+ self.postprocess_resource_prop(obj, "tosca_resource", "python")
+ self.postprocess_resource_prop(obj, "private_key", "raw")
+ self.postprocess_resource_prop(obj, "public_key", "raw")
+ self.postprocess_resource_prop(obj, "rest_service", "python")
+ self.postprocess_resource_prop(obj, "rest_tenant", "python")
+
+ def save_created_obj(self, xos_obj):
+ if xos_obj.requires and xos_obj.requires.strip():
+ (satisfied, missing) = LoadableModule.dependency_check([x.strip() for x in xos_obj.requires.split(",")])
+ if missing:
+ raise Exception("missing dependencies for Loadable Module %s: %s" % (xos_obj.name, ", ".join(missing)))
+
+ super(XOSLoadableModule, self).save_created_obj(xos_obj)
+
+
diff --git a/xos/tosca/resources/servicecontroller.py b/xos/tosca/resources/servicecontroller.py
index e14c604..e5fa6e2 100644
--- a/xos/tosca/resources/servicecontroller.py
+++ b/xos/tosca/resources/servicecontroller.py
@@ -1,77 +1,15 @@
-import os
-import pdb
-import sys
-import tempfile
-sys.path.append("/opt/tosca")
-from translator.toscalib.tosca_template import ToscaTemplate
-
from core.models import ServiceController, ServiceControllerResource, LoadableModule, LoadableModuleResource
-from xosresource import XOSResource
+from loadablemodule import XOSLoadableModule
-class XOSServiceController(XOSResource):
+class XOSServiceController(XOSLoadableModule):
provides = "tosca.nodes.ServiceController"
xos_model = ServiceController
copyin_props = ["version", "provides", "requires", "base_url", "synchronizer_run", "synchronizer_config"]
- def postprocess_resource_prop(self, obj, kind, format):
- values = self.get_property(kind)
- if values:
- for i,value in enumerate(values.split(",")):
- value = value.strip()
- subdirectory = None
-
- name=kind
- if i>0:
- name = "%s_%d" %( name, i)
-
- if (" " in value):
- parts=value.split()
- for part in parts[:-1]:
- if ":" in part:
- (lhs, rhs) = part.split(":", 1)
- if lhs=="subdirectory":
- subdirectory=rhs
- else:
- raise Exception("Malformed value %s" % value)
- else:
- raise Exception("Malformed value %s" % value)
- value = parts[-1]
-
-
- scr = LoadableModuleResource.objects.filter(loadable_module=obj, name=name, kind=kind, format=format)
- if scr:
- scr=scr[0]
- if (scr.url != value) or (scr.subdirectory!=subdirectory):
- self.info("updating resource %s" % kind)
- scr.url = value
- scr.subdirectory = subdirectory
- scr.save()
- else:
- self.info("adding resource %s" % kind)
- scr = LoadableModuleResource(loadable_module=obj, name=name, kind=kind, format=format, url=value, subdirectory=subdirectory)
- scr.save()
-
def postprocess(self, obj):
# allow these common resource to be specified directly by the ServiceController tosca object
- self.postprocess_resource_prop(obj, "models", "python")
- self.postprocess_resource_prop(obj, "admin", "python")
- self.postprocess_resource_prop(obj, "django_library", "python")
- self.postprocess_resource_prop(obj, "admin_template", "raw")
- self.postprocess_resource_prop(obj, "tosca_custom_types", "yaml")
- self.postprocess_resource_prop(obj, "tosca_resource", "python")
+ super(XOSServiceController, self).postprocess(obj)
self.postprocess_resource_prop(obj, "synchronizer", "manifest")
- self.postprocess_resource_prop(obj, "private_key", "raw")
- self.postprocess_resource_prop(obj, "public_key", "raw")
- self.postprocess_resource_prop(obj, "rest_service", "python")
- self.postprocess_resource_prop(obj, "rest_tenant", "python")
-
- def save_created_obj(self, xos_obj):
- if xos_obj.requires and xos_obj.requires.strip():
- (satisfied, missing) = ServiceController.dependency_check([x.strip() for x in xos_obj.requires.split(",")])
- if missing:
- raise Exception("missing dependencies for ServiceController %s: %s" % (xos_obj.name, ", ".join(missing)))
-
- super(XOSServiceController, self).save_created_obj(xos_obj)
diff --git a/xos/tosca/samples/library-onboard.yaml b/xos/tosca/samples/library-onboard.yaml
new file mode 100644
index 0000000..30e20c9
--- /dev/null
+++ b/xos/tosca/samples/library-onboard.yaml
@@ -0,0 +1,18 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Sample library onboard
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+ library#sample:
+ type: tosca.nodes.Library
+ properties:
+ base_url: file:///opt/xos/
+ tosca_resource: tosca/samples/samplelibrary.py
+ requires: vsg, vtn, onos
+
+
+
diff --git a/xos/tosca/samples/samplelibrary.py b/xos/tosca/samples/samplelibrary.py
new file mode 100644
index 0000000..7a6030a
--- /dev/null
+++ b/xos/tosca/samples/samplelibrary.py
@@ -0,0 +1,3 @@
+# some empty file used to test library onboarding
+
+pass