Merge branch 'master' of github.com:open-cloud/xos
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index 89ef49a..994ab3e 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -61,6 +61,9 @@
     mysite:
       type: tosca.nodes.Site
 
+    label_vsg:
+      type: tosca.nodes.NodeLabel
+
     # Networks required by the CORD setup
     mysite_vsg-access:
       type: tosca.nodes.network.Network
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index 07d4b68..aa2673b 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -270,6 +270,8 @@
     mysite:
       type: tosca.nodes.Site
 
+    label_vsg:
+      type: tosca.nodes.NodeLabel
 
     # CORD Slices
     mysite_vsg:
diff --git a/xos/configurations/vtn/cord-vtn-vsg.yaml b/xos/configurations/vtn/cord-vtn-vsg.yaml
index 1b26bba..c4332e2 100644
--- a/xos/configurations/vtn/cord-vtn-vsg.yaml
+++ b/xos/configurations/vtn/cord-vtn-vsg.yaml
@@ -21,7 +21,7 @@
     public_addresses:
       type: tosca.nodes.AddressPool
       properties:
-          addresses: 10.123.0.0/24 10.124.0.0/24
+          addresses: 10.123.0.128/25
 
     service_vsg:
       type: tosca.nodes.VSGService
@@ -62,6 +62,9 @@
     mysite:
       type: tosca.nodes.Site
 
+    label_vsg:
+      type: tosca.nodes.NodeLabel
+
     # Networks required by the CORD setup
     mysite_vsg-access:
       type: tosca.nodes.network.Network
diff --git a/xos/configurations/vtn/docker-compose.yml b/xos/configurations/vtn/docker-compose.yml
index 0fa718b..1839f78 100644
--- a/xos/configurations/vtn/docker-compose.yml
+++ b/xos/configurations/vtn/docker-compose.yml
@@ -17,7 +17,7 @@
         - ../setup:/root/setup:ro
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
         - ./files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
-
+        - ./images:/opt/xos/images:ro
 
 xos_synchronizer_onos:
     image: xosproject/xos-synchronizer-openstack
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 28d99fd..910ee97 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1266,6 +1266,14 @@
     list_display_links = ('backend_status_icon', 'name', )
 
 class NodeForm(forms.ModelForm):
+    labels = forms.ModelMultipleChoiceField(
+        queryset=NodeLabel.objects.all(),
+        required=False,
+        help_text="Select which labels apply to this node",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Labels'), is_stacked=False
+        )
+    )
     class Meta:
         model = Node
         widgets = {
@@ -1273,6 +1281,31 @@
             'deployment': LinkedSelect
         }
 
+    def __init__(self, *args, **kwargs):
+      request = kwargs.pop('request', None)
+      super(NodeForm, self).__init__(*args, **kwargs)
+
+      if self.instance and self.instance.pk:
+        self.fields['labels'].initial = self.instance.labels.all()
+
+    def save(self, commit=True):
+      node = super(NodeForm, self).save(commit=False)
+
+      node.labels = self.cleaned_data['labels']
+
+      if commit:
+        node.save()
+
+      return node
+
+
+class NodeLabelAdmin(XOSBaseAdmin):
+    list_display = ('name',)
+    list_display_links = ('name', )
+
+    fields = ('name', )
+
+
 class NodeAdmin(XOSBaseAdmin):
     form = NodeForm
     list_display = ('backend_status_icon', 'name', 'site_deployment')
@@ -1280,13 +1313,14 @@
     list_filter = ('site_deployment',)
 
     inlines = [TagInline,InstanceInline]
-    fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name', 'site_deployment'], 'classes':['suit-tab suit-tab-details']})]
+    fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name', 'site_deployment'], 'classes':['suit-tab suit-tab-details']}),
+                 ('Labels', {'fields': ['labels'], 'classes':['suit-tab suit-tab-labels']})]
     readonly_fields = ('backend_status_text', )
 
     user_readonly_fields = ['name','site_deployment']
     user_readonly_inlines = [TagInline,InstanceInline]
 
-    suit_form_tabs =(('details','Node Details'),('instances','Instances'))
+    suit_form_tabs =(('details','Node Details'),('instances','Instances'), ('labels', 'Labels'))
 
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
         if db_field.name == 'site':
@@ -2107,6 +2141,7 @@
     admin.site.register(SiteRole)
     admin.site.register(SliceRole)
     admin.site.register(Node, NodeAdmin)
+    admin.site.register(NodeLabel, NodeLabelAdmin)
     #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
     #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
     admin.site.register(Instance, InstanceAdmin)
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index 628a3bb..2ee6b94 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -21,7 +21,7 @@
 from .credential import UserCredential,SiteCredential,SliceCredential
 from .site import SiteRole
 from .site import SitePrivilege
-from .node import Node
+from .node import Node, NodeLabel
 from .slicetag import SliceTag
 from .instance import Instance
 from .reservation import ReservedResource
diff --git a/xos/core/models/node.py b/xos/core/models/node.py
index 5496d6b..b825787 100644
--- a/xos/core/models/node.py
+++ b/xos/core/models/node.py
@@ -28,3 +28,9 @@
 
     def can_update(self, user):
         return user.can_update_site(self.site, allow=['tech'])
+
+class NodeLabel(PlCoreBase):
+    name = StrippedCharField(max_length=200, help_text="label name", unique=True)
+    node = models.ManyToManyField(Node, related_name="labels", blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 15e9710..dd96d03 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -715,6 +715,16 @@
             node:
                 type: tosca.capabilities.xos.Node
 
+    tosca.nodes.NodeLabel:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS NodeLabel.
+        properties:
+            xos_base_props
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.NodeLabel
+
     tosca.nodes.DashboardView:
         derived_from: tosca.nodes.Root
         description: >
@@ -893,6 +903,10 @@
         derived_from: tosca.capabilities.Root
         description: An XOS Node
 
+    tosca.capabilities.xos.NodeLabel:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NodeLabel
+
     tosca.capabilities.xos.Image:
         derived_from: tosca.capabilities.Root
         description: An XOS Image
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 88b3388..cf930b3 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -1005,6 +1005,27 @@
             node:
                 type: tosca.capabilities.xos.Node
 
+    tosca.nodes.NodeLabel:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS NodeLabel.
+        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
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.NodeLabel
+
     tosca.nodes.DashboardView:
         derived_from: tosca.nodes.Root
         description: >
@@ -1194,6 +1215,10 @@
         derived_from: tosca.capabilities.Root
         description: An XOS Node
 
+    tosca.capabilities.xos.NodeLabel:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NodeLabel
+
     tosca.capabilities.xos.Image:
         derived_from: tosca.capabilities.Root
         description: An XOS Image
diff --git a/xos/tosca/resources/nodelabel.py b/xos/tosca/resources/nodelabel.py
new file mode 100644
index 0000000..9a8df3e
--- /dev/null
+++ b/xos/tosca/resources/nodelabel.py
@@ -0,0 +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 NodeLabel
+
+from xosresource import XOSResource
+
+class XOSNodeLabel(XOSResource):
+    provides = "tosca.nodes.NodeLabel"
+    xos_model = NodeLabel
+