[SEBA-512]
Fix xosgenx's handling of optional/required modifiers in relation to
the null and blank options, which was nondeterministic depending on the
order of items iterated over in the options dictionary.
Don't allow 'Null' booleans
Change-Id: I3f21180ec11c7e43794c04ebe479d50c11f6271c
diff --git a/VERSION b/VERSION
index 5859406..530cdd9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.3
+2.2.4
diff --git a/containers/chameleon/Dockerfile.chameleon b/containers/chameleon/Dockerfile.chameleon
index 90ae1e1..33f64b0 100644
--- a/containers/chameleon/Dockerfile.chameleon
+++ b/containers/chameleon/Dockerfile.chameleon
@@ -13,8 +13,7 @@
# limitations under the License.
# xosproject/chameleon
-
-FROM xosproject/xos-base:2.2.3
+FROM xosproject/xos-base:2.2.4
# xos-base already has protoc and dependencies installed
diff --git a/containers/xos/Dockerfile.client b/containers/xos/Dockerfile.client
index 331f503..ea54ab0 100644
--- a/containers/xos/Dockerfile.client
+++ b/containers/xos/Dockerfile.client
@@ -13,8 +13,7 @@
# limitations under the License.
# xosproject/xos-client
-
-FROM xosproject/xos-libraries:2.2.3
+FROM xosproject/xos-libraries:2.2.4
# Install XOS client
COPY lib/xos-api /tmp/xos-api
diff --git a/containers/xos/Dockerfile.libraries b/containers/xos/Dockerfile.libraries
index 3b87c5a..6a58d7d 100644
--- a/containers/xos/Dockerfile.libraries
+++ b/containers/xos/Dockerfile.libraries
@@ -13,8 +13,7 @@
# limitations under the License.
# xosproject/xos-libraries
-
-FROM xosproject/xos-base:2.2.3
+FROM xosproject/xos-base:2.2.4
# Add libraries
COPY lib /opt/xos/lib
diff --git a/containers/xos/Dockerfile.synchronizer-base b/containers/xos/Dockerfile.synchronizer-base
index b27815a..042f7c6 100644
--- a/containers/xos/Dockerfile.synchronizer-base
+++ b/containers/xos/Dockerfile.synchronizer-base
@@ -13,8 +13,7 @@
# limitations under the License.
# xosproject/xos-synchronizer-base
-
-FROM xosproject/xos-client:2.2.3
+FROM xosproject/xos-client:2.2.4
COPY xos/synchronizers/new_base /opt/xos/synchronizers/new_base
COPY xos/xos/logger.py /opt/xos/xos/logger.py
diff --git a/containers/xos/Dockerfile.xos-core b/containers/xos/Dockerfile.xos-core
index 431f002..d0d7605 100644
--- a/containers/xos/Dockerfile.xos-core
+++ b/containers/xos/Dockerfile.xos-core
@@ -13,8 +13,7 @@
# limitations under the License.
# xosproject/xos-core
-
-FROM xosproject/xos-libraries:2.2.3
+FROM xosproject/xos-libraries:2.2.4
# Install XOS
ADD xos /opt/xos
diff --git a/containers/xos/pip_requested.txt b/containers/xos/pip_requested.txt
index c3a3098..889110e 100644
--- a/containers/xos/pip_requested.txt
+++ b/containers/xos/pip_requested.txt
@@ -28,7 +28,7 @@
oslo.serialization==2.25.0
oslo.utils==3.36.0
ply==3.11
-plyxproto==3.1.0
+plyxproto==4.0.0
protobuf==3.5.2
prometheus_client==0.4.0
# Avoids a warning, see http://initd.org/psycopg/docs/faq.html#faq-compile
diff --git a/containers/xos/pip_requirements.txt b/containers/xos/pip_requirements.txt
index f8e4ec4..cb62170 100644
--- a/containers/xos/pip_requirements.txt
+++ b/containers/xos/pip_requirements.txt
@@ -86,7 +86,7 @@
pika-pool==0.1.3
pipdeptree==0.13.0
ply==3.11
-plyxproto==3.1.0
+plyxproto==4.0.0
prettytable==0.7.2
prometheus-client==0.4.0
protobuf==3.5.2
diff --git a/lib/xos-genx/xos-genx-tests/test_jinja2_django.py b/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
index 108ae4e..d5da2d3 100644
--- a/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
+++ b/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
import unittest
from xosgenx.jinja2_extensions.django import *
@@ -33,13 +32,13 @@
field = {"name": "foo", "options": {"modifier": "required"}}
res = map_xproto_to_django(field)
- self.assertEqual(res, {"blank": False, "null": False})
+ self.assertEqual(res, {"blank": "False", "null": "False"})
def test_xproto_optional_to_django(self):
field = {"name": "foo", "options": {"modifier": "optional"}}
res = map_xproto_to_django(field)
- self.assertEqual(res, {"blank": True, "null": True})
+ self.assertEqual(res, {"blank": "True", "null": "True"})
def test_map_xproto_to_django(self):
diff --git a/lib/xos-genx/xosgenx/jinja2_extensions/django.py b/lib/xos-genx/xosgenx/jinja2_extensions/django.py
index 724b85d..3909c00 100644
--- a/lib/xos-genx/xosgenx/jinja2_extensions/django.py
+++ b/lib/xos-genx/xosgenx/jinja2_extensions/django.py
@@ -12,10 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
+from __future__ import print_function
from base import *
import pdb
import re
+import sys
def django_content_type_string(xptags):
@@ -83,48 +84,75 @@
def map_xproto_to_django(f):
+
allowed_keys = [
- "help_text",
- "default",
- "max_length",
- "modifier",
+ "auto_now_add",
"blank",
"choices",
"db_index",
- "null",
+ "default",
"editable",
- "on_delete",
- "verbose_name",
- "auto_now_add",
- "unique",
- "min_value",
+ "help_text",
+ "max_length",
"max_value",
+ "min_value",
+ "null",
+ "on_delete",
+ "unique",
+ "verbose_name",
]
- if f.get("link_type") == "manytomany":
- # map for fields that do not support null
- m = {
- "modifier": {"optional": True, "required": False, "_targets": ["blank"]}
- }
- else:
- # map for fields that do support null
- # TODO evaluate if setting Null = False for all strings
- m = {
- "modifier": {"optional": True, "required": False, "_targets": ["null", "blank"]}
- }
+ out = {} # output dictionary
- out = {}
-
+ # filter options dict to only have allowed keys
for k, v in f["options"].items():
if k in allowed_keys:
- try:
- # NOTE this will be used to parse xproto optional/required field prefix
- # and apply it to the null and blank fields
- kv2 = m[k]
- for t in kv2["_targets"]:
- out[t] = kv2[v]
- except BaseException:
- out[k] = v
+ out[k] = v
+
+ # deal with optional/required modifier fields, and manytomany links
+ # modifier is not added to "out" dict, but affects blank/null truth
+ modifier = f["options"].get('modifier')
+ link_type = f.get("link_type")
+
+ # in some tests, there is no field type
+ if "type" in f:
+ field_type = f["type"]
+ else:
+ field_type = None
+
+ mod_out = {}
+
+ if modifier == "required":
+
+ if field_type == "string":
+ if "blank" not in out: # if blank is already set, honor that value
+ mod_out["blank"] = 'True' # by default, required strings can be blank
+ else:
+ mod_out["blank"] = 'False' # but other required fields can't be blank
+
+ if link_type != "manytomany":
+ mod_out["null"] = 'False'
+
+ elif modifier == "optional":
+
+ mod_out["blank"] = 'True'
+
+ # set defaults on link types
+ if link_type != "manytomany" and field_type != "bool":
+ mod_out["null"] = 'True'
+
+ else:
+ print("map_xproto_to_django - unknown modifier type: %s on %s" % (modifier, f), file=sys.stderr)
+
+ # print an error if there's a field conflict
+ for kmo in mod_out.keys():
+ if kmo in out:
+ if out[kmo] != mod_out[kmo]:
+ print("Option '%s' is manually set to value '%s', which "
+ "conflicts with value '%s' set automatically by modifier on field: %s" %
+ (kmo, out[kmo], mod_out[kmo], f), file=sys.stderr)
+
+ out.update(mod_out) # overwrite out keys with mod_out
return out
diff --git a/scripts/xos_dev_reqs.txt b/scripts/xos_dev_reqs.txt
index 4a4abdb..ff3c3ac 100644
--- a/scripts/xos_dev_reqs.txt
+++ b/scripts/xos_dev_reqs.txt
@@ -12,7 +12,8 @@
netaddr==0.7.19
networkx==1.11
nose2==0.7.4
-plyxproto==3.1.0
+ply==3.11
+plyxproto==4.0.0
pykwalify==1.6.1
requests-mock==1.5.0
tosca-parser==0.9.0
diff --git a/xos/core/migrations/0003_auto_20190304_1358.py b/xos/core/migrations/0003_auto_20190304_1358.py
new file mode 100644
index 0000000..04840af
--- /dev/null
+++ b/xos/core/migrations/0003_auto_20190304_1358.py
@@ -0,0 +1,781 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.11 on 2019-03-04 18:58
+from __future__ import unicode_literals
+
+import core.models.xosbase_header
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0002_initial_data'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='cidr',
+ field=models.CharField(blank=True, help_text=b'Subnet for this AddressPool', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='gateway_ip',
+ field=models.CharField(blank=True, help_text=b'Gateway IP address for this AddressPool', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='gateway_mac',
+ field=models.CharField(blank=True, help_text=b'Gateway MAC address for this AddressPool', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='addresspool_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controller_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controller_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controller_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllerimages_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerimages_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerimages_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllernetwork_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllernetwork_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllernetwork_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllerrole_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerrole_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerrole_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllersite_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersite_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersite_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllersiteprivilege_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersiteprivilege_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersiteprivilege_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllerslice_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerslice_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllerslice_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controllersliceprivilege_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersliceprivilege_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controllersliceprivilege_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='controlleruser_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controlleruser_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='controlleruser_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='deployment_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='deployment_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='deployment_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='flavor_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='flavor_decl',
+ name='flavor',
+ field=core.models.xosbase_header.StrippedCharField(blank=True, help_text=b'flavor string used to configure deployments', max_length=32),
+ ),
+ migrations.AlterField(
+ model_name='flavor_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='flavor_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='image_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='image_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='image_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='imagedeployments_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='imagedeployments_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='imagedeployments_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='instance_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='instance_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='instance_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='interfacetype_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='interfacetype_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='interfacetype_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='network_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='network_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='network_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='networkparameter_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkparameter_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkparameter_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='networkparametertype_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkparametertype_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkparametertype_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='networkslice_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkslice_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networkslice_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='networktemplate_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networktemplate_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='networktemplate_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='node_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='node_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='node_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='nodelabel_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='nodelabel_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='nodelabel_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='port_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='port_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='port_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='principal_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='principal_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='principal_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='privilege_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='privilege_decl',
+ name='expires',
+ field=models.DateTimeField(blank=True, max_length=1024, null=True),
+ ),
+ migrations.AlterField(
+ model_name='privilege_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='privilege_decl',
+ name='permission',
+ field=models.CharField(blank=True, default=b'all', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='privilege_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='role_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='role_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='role_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='service_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='service_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='service_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceattribute_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceattribute_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceattribute_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='servicedependency_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='servicedependency_decl',
+ name='connect_method',
+ field=models.CharField(blank=True, choices=[(b'none', b'None'), (b'private', b'Private'), (b'public', b'Public')], default=b'none', help_text=b'method to connect the two services', max_length=30),
+ ),
+ migrations.AlterField(
+ model_name='servicedependency_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='servicedependency_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='servicegraphconstraint_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='servicegraphconstraint_decl',
+ name='constraints',
+ field=core.models.xosbase_header.StrippedCharField(blank=True, help_text=b'A composite array defining positions, eg [volt, vsg, [address_manager, vrouter]]', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='servicegraphconstraint_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='servicegraphconstraint_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstance_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstance_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstance_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstanceattribute_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstanceattribute_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstanceattribute_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstancelink_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstancelink_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinstancelink_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceinterface_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinterface_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceinterface_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='serviceport_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceport_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='serviceport_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='site_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='site_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='site_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='sitedeployment_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='sitedeployment_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='sitedeployment_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='siteprivilege_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='siteprivilege_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='siteprivilege_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='siterole_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='siterole_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='siterole_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='slice_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='slice_decl',
+ name='controller_replica_count',
+ field=models.IntegerField(blank=True, default=0, help_text=b'Replica count, controller-dependent', null=True),
+ ),
+ migrations.AlterField(
+ model_name='slice_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='slice_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='sliceprivilege_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='sliceprivilege_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='sliceprivilege_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='slicerole_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='slicerole_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='slicerole_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='tag_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='tag_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='tag_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='trustdomain_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='trustdomain_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='trustdomain_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='xoscore_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='xoscore_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='xoscore_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ migrations.AlterField(
+ model_name='xosguiextension_decl',
+ name='backend_status',
+ field=models.CharField(blank=True, default=b'Provisioning in progress', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='xosguiextension_decl',
+ name='leaf_model_name',
+ field=models.CharField(blank=True, help_text=b'The most specialized model in this chain of inheritance, often defined by a service developer', max_length=1024),
+ ),
+ migrations.AlterField(
+ model_name='xosguiextension_decl',
+ name='updated',
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now, help_text=b'Time this model was changed by a non-synchronizer'),
+ ),
+ ]
diff --git a/xos/core/models/core.xproto b/xos/core/models/core.xproto
index 7f30600..fbb945e 100644
--- a/xos/core/models/core.xproto
+++ b/xos/core/models/core.xproto
@@ -17,7 +17,7 @@
optional string backend_register = 6 [default = "{}", max_length = 1024, feedback_state = True];
required bool backend_need_delete = 7 [default = False, blank = True];
required bool backend_need_reap = 8 [default = False, blank = True];
- required string backend_status = 9 [default = "Provisioning in progress", max_length = 1024, null = True, feedback_state = True];
+ required string backend_status = 9 [default = "Provisioning in progress", max_length = 1024, feedback_state = True];
required int32 backend_code = 10 [default = 0, feedback_state = True];
required bool deleted = 11 [default = False, blank = True];
required bool write_protect = 12 [default = False, blank = True];
@@ -69,8 +69,8 @@
optional string login_page = 18 [max_length = 200, content_type = "stripped", blank = True, help_text = "send this user to a specific page on login", null = True, db_index = False];
required string created = 19 [db_index = False, null = False, content_type = "date", blank = True];
required string updated = 20 [db_index = False, null = False, content_type = "date", blank = True];
- optional string enacted = 21 [db_index = False, null = True, content_type = "date", blank = False];
- optional string policed = 22 [db_index = False, null = True, content_type = "date", blank = False];
+ optional string enacted = 21 [db_index = False, null = True, content_type = "date"];
+ optional string policed = 22 [db_index = False, null = True, content_type = "date"];
required string backend_status = 23 [default = "Provisioning in progress", max_length = 1024, content_type = "stripped", blank = False, null = False, db_index = False];
required int32 backend_code = 24 [default = 0];
required bool backend_need_delete = 25 [default = False, null = False, db_index = False, blank = True];
@@ -107,7 +107,7 @@
required string object_type = 5 [null = False, max_length=1024, blank = False];
required string permission = 6 [null = False, default = "all", max_length=1024, tosca_key=True];
required string granted = 7 [content_type = "date", auto_now_add = True, max_length=1024];
- required string expires = 8 [content_type = "date", null = True, max_length=1024];
+ optional string expires = 8 [content_type = "date", max_length=1024];
}
message AddressPool (XOSBase) {
@@ -126,12 +126,12 @@
}
// Admins at a deployment have access to controllers at those deployments
-policy controller_policy
- < ctx.user.is_admin
- | exists Privilege:
- Privilege.accessor_id = ctx.user.id
- & Privilege.object_type = "Deployment"
- & Privilege.permission = "role:admin"
+policy controller_policy
+ < ctx.user.is_admin
+ | exists Privilege:
+ Privilege.accessor_id = ctx.user.id
+ & Privilege.object_type = "Deployment"
+ & Privilege.permission = "role:admin"
& Privilege.object_id = obj.id >
message Controller::controller_policy (XOSBase) {
@@ -168,7 +168,7 @@
policy slice_policy <
ctx.user.is_admin
| (*site_policy(site)
- & (ctx.user = obj.creator
+ & (ctx.user = obj.creator
| (exists Privilege:
Privilege.accessor_id = ctx.user.id
& Privilege.accessor_type = "User"
@@ -279,7 +279,7 @@
}
policy image_deployment_policy <
- *deployment_policy(deployment)
+ *deployment_policy(deployment)
>
message ImageDeployments (XOSBase) {
@@ -619,15 +619,15 @@
optional manytoone service->Service:slices = 8:1006 [db_index = True, null = True, blank = True];
optional string network = 9 [blank = True, max_length = 256, null = True, db_index = False, choices = "((None, 'Default'), ('host', 'Host'), ('bridged', 'Bridged'), ('noauto', 'No Automatic Networks'))"];
optional string exposed_ports = 10 [db_index = False, max_length = 256, null = True, blank = True];
- optional manytoone creator->User:slices = 12:1004 [db_index = True, null = False, blank = False];
+ optional manytoone creator->User:slices = 12:1004 [db_index = True];
optional manytoone default_flavor->Flavor:slices = 13:1002 [db_index = True, null = True, blank = True];
optional manytoone default_image->Image:slices = 14:1005 [db_index = True, null = True, blank = True];
optional manytoone default_node->Node:slices = 15:1003 [db_index = True, null = True, blank = True];
optional string mount_data_sets = 16 [default = "GenBank", max_length = 256, content_type = "stripped", blank = True, null = True, db_index = False];
required string default_isolation = 17 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))", max_length = 30, blank = False, null = False, db_index = False];
- optional manytoone trust_domain->TrustDomain:slices = 18:1002 [db_index = True, null = False, blank = False, help_text = "Trust domain this slice resides in"];
- optional manytoone principal->Principal:slices = 19:1001 [db_index = True, null = False, blank = False, help_text = "Principal this slice may use to interact with other components"];
- optional int32 controller_replica_count = 20 [default = 0, null = False, db_index = False, blank = False, help_text = "Replica count, controller-dependent"];
+ optional manytoone trust_domain->TrustDomain:slices = 18:1002 [db_index = True, help_text = "Trust domain this slice resides in"];
+ optional manytoone principal->Principal:slices = 19:1001 [db_index = True, help_text = "Principal this slice may use to interact with other components"];
+ optional int32 controller_replica_count = 20 [default = 0, db_index = False, help_text = "Replica count, controller-dependent"];
optional string controller_kind = 21 [max_length = 256, content_type = "stripped", blank = True, help_text = "Type of controller, vim-dependent", null = True, db_index = False];
}
diff --git a/xos/synchronizers/new_base/tests/test_payload.py b/xos/synchronizers/new_base/tests/test_payload.py
deleted file mode 100644
index 308133b..0000000
--- a/xos/synchronizers/new_base/tests/test_payload.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import json
-import unittest
-from mock import patch
-import mock
-import pdb
-import networkx as nx
-
-import os
-import sys
-
-test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-xos_dir = os.path.join(test_path, "..", "..", "..")
-
-ANSIBLE_FILE = "/tmp/payload_test"
-
-log = None
-
-
-def run_fake_ansible_template(*args, **kwargs):
- opts = args[1]
- open(ANSIBLE_FILE, "w").write(json.dumps(opts))
- return [{"rc": 0}]
-
-
-def run_fake_ansible_template_fail(*args, **kwargs):
- opts = args[1]
- open(ANSIBLE_FILE, "w").write(json.dumps(opts))
- return [{"rc": 1}]
-
-
-def get_ansible_output():
- ansible_str = open(ANSIBLE_FILE).read()
- return json.loads(ansible_str)
-
-
-class TestPayload(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
-
- global log
-
- config = os.path.join(test_path, "test_config.yaml")
- from xosconfig import Config
-
- Config.clear()
- Config.init(config, "synchronizer-config-schema.yaml")
-
- if not log:
- from multistructlog import create_logger
-
- log = create_logger(Config().get("logging"))
-
- def setUp(self):
-
- global log, steps, event_loop
-
- self.sys_path_save = sys.path
- self.cwd_save = os.getcwd()
- sys.path.append(xos_dir)
- sys.path.append(os.path.join(xos_dir, "synchronizers", "new_base"))
- sys.path.append(
- os.path.join(xos_dir, "synchronizers", "new_base", "tests", "steps")
- )
-
- config = os.path.join(test_path, "test_config.yaml")
- from xosconfig import Config
-
- Config.clear()
- Config.init(config, "synchronizer-config-schema.yaml")
-
- from synchronizers.new_base.mock_modelaccessor_build import (
- build_mock_modelaccessor,
- )
-
- build_mock_modelaccessor(xos_dir, services_dir=None, service_xprotos=[])
-
- os.chdir(os.path.join(test_path, "..")) # config references tests/model-deps
-
- import event_loop
-
- reload(event_loop)
- import backend
-
- reload(backend)
- import steps.sync_instances
- import steps.sync_controller_slices
- from modelaccessor import model_accessor
-
- # import all class names to globals
- for (k, v) in model_accessor.all_model_classes.items():
- globals()[k] = v
- b = backend.Backend()
- steps_dir = Config.get("steps_dir")
- self.steps = b.load_sync_step_modules(steps_dir)
- self.synchronizer = event_loop.XOSObserver(self.steps)
-
- def tearDown(self):
- sys.path = self.sys_path_save
- os.chdir(self.cwd_save)
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_delete_record(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save:
- o = Instance()
- o.name = "Sisi Pascal"
-
- o.synchronizer_step = steps.sync_instances.SyncInstances()
- self.synchronizer.delete_record(o, log)
-
- a = get_ansible_output()
- self.assertDictContainsSubset({"delete": True, "name": o.name}, a)
- o.save.assert_called_with(update_fields=["backend_need_reap"])
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template_fail,
- )
- @mock.patch("event_loop.model_accessor")
- def test_delete_record_fail(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save:
- o = Instance()
- o.name = "Sisi Pascal"
-
- o.synchronizer_step = steps.sync_instances.SyncInstances()
-
- with self.assertRaises(Exception) as e:
- self.synchronizer.delete_record(o, log)
-
- self.assertEqual(
- e.exception.message, "Nonzero rc from Ansible during delete_record"
- )
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_sync_record(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save:
- o = Instance()
- o.name = "Sisi Pascal"
-
- o.synchronizer_step = steps.sync_instances.SyncInstances()
- self.synchronizer.sync_record(o, log)
-
- a = get_ansible_output()
- self.assertDictContainsSubset({"delete": False, "name": o.name}, a)
- o.save.assert_called_with(
- update_fields=[
- "enacted",
- "backend_status",
- "backend_register",
- "backend_code",
- ]
- )
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_sync_cohort(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save, mock.patch.object(
- ControllerSlice, "save"
- ) as controllerslice_save:
- cs = ControllerSlice()
- s = Slice(name="SP SP")
- cs.slice = s
-
- o = Instance()
- o.name = "Sisi Pascal"
- o.slice = s
-
- cohort = [cs, o]
- o.synchronizer_step = steps.sync_instances.SyncInstances()
- cs.synchronizer_step = steps.sync_controller_slices.SyncControllerSlices()
-
- self.synchronizer.sync_cohort(cohort, False)
-
- a = get_ansible_output()
- self.assertDictContainsSubset({"delete": False, "name": o.name}, a)
- o.save.assert_called_with(
- update_fields=[
- "enacted",
- "backend_status",
- "backend_register",
- "backend_code",
- ]
- )
- cs.save.assert_called_with(
- update_fields=[
- "enacted",
- "backend_status",
- "backend_register",
- "backend_code",
- ]
- )
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_deferred_exception(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save:
- cs = ControllerSlice()
- s = Slice(name="SP SP")
- cs.slice = s
- cs.force_defer = True
-
- o = Instance()
- o.name = "Sisi Pascal"
- o.slice = s
-
- cohort = [cs, o]
- o.synchronizer_step = steps.sync_instances.SyncInstances()
- cs.synchronizer_step = steps.sync_controller_slices.SyncControllerSlices()
-
- self.synchronizer.sync_cohort(cohort, False)
- o.save.assert_called_with(
- always_update_timestamp=True,
- update_fields=["backend_status", "backend_register"],
- )
- self.assertEqual(cs.backend_code, 0)
-
- self.assertIn("Force", cs.backend_status)
- self.assertIn("Failed due to", o.backend_status)
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_backend_status(self, mock_run_template, mock_modelaccessor):
- with mock.patch.object(Instance, "save") as instance_save:
- cs = ControllerSlice()
- s = Slice(name="SP SP")
- cs.slice = s
- cs.force_fail = True
-
- o = Instance()
- o.name = "Sisi Pascal"
- o.slice = s
-
- cohort = [cs, o]
- o.synchronizer_step = steps.sync_instances.SyncInstances()
- cs.synchronizer_step = steps.sync_controller_slices.SyncControllerSlices()
-
- self.synchronizer.sync_cohort(cohort, False)
- o.save.assert_called_with(
- always_update_timestamp=True,
- update_fields=["backend_status", "backend_register"],
- )
- self.assertIn("Force", cs.backend_status)
- self.assertIn("Failed due to", o.backend_status)
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_fetch_pending(self, mock_run_template, mock_accessor, *_other_accessors):
- pending_objects, pending_steps = self.synchronizer.fetch_pending()
- pending_objects2 = list(pending_objects)
-
- any_cs = next(
- obj for obj in pending_objects if obj.leaf_model_name == "ControllerSlice"
- )
- any_instance = next(
- obj for obj in pending_objects2 if obj.leaf_model_name == "Instance"
- )
-
- slice = Slice()
- any_instance.slice = slice
- any_cs.slice = slice
-
- self.synchronizer.external_dependencies = []
- cohorts = self.synchronizer.compute_dependent_cohorts(pending_objects, False)
- flat_objects = [item for cohort in cohorts for item in cohort]
-
- self.assertEqual(set(flat_objects), set(pending_objects))
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_fetch_pending_with_external_dependencies(
- self, mock_run_template, mock_accessor, *_other_accessors
- ):
- pending_objects, pending_steps = self.synchronizer.fetch_pending()
- pending_objects2 = list(pending_objects)
-
- self.synchronizer = event_loop.XOSObserver(self.steps)
-
- any_cn = next(
- obj for obj in pending_objects if obj.leaf_model_name == "ControllerNetwork"
- )
- any_user = next(
- obj for obj in pending_objects2 if obj.leaf_model_name == "User"
- )
-
- cohorts = self.synchronizer.compute_dependent_cohorts(pending_objects, False)
-
- flat_objects = [item for cohort in cohorts for item in cohort]
- self.assertEqual(set(flat_objects), set(pending_objects))
-
- # These cannot be None, but for documentation purposes
- self.assertIsNotNone(any_cn)
- self.assertIsNotNone(any_user)
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_external_dependency_exception(self, mock_run_template, mock_modelaccessor):
- cs = ControllerSlice()
- s = Slice(name="SP SP")
- cs.slice = s
-
- o = Instance()
- o.name = "Sisi Pascal"
- o.slice = s
-
- cohort = [cs, o]
- o.synchronizer_step = None
- o.synchronizer_step = steps.sync_instances.SyncInstances()
-
- self.synchronizer.sync_cohort(cohort, False)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/xos/synchronizers/new_base/tests/test_run.py b/xos/synchronizers/new_base/tests/test_run.py
deleted file mode 100644
index 863bc0f..0000000
--- a/xos/synchronizers/new_base/tests/test_run.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import json
-import unittest
-from mock import patch
-import mock
-import pdb
-import networkx as nx
-
-import os
-import sys
-
-test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-xos_dir = os.path.join(test_path, "..", "..", "..")
-
-ANSIBLE_FILE = "/tmp/payload_test"
-
-
-def run_fake_ansible_template(*args, **kwargs):
- opts = args[1]
- open(ANSIBLE_FILE, "w").write(json.dumps(opts))
-
-
-def get_ansible_output():
- ansible_str = open(ANSIBLE_FILE).read()
- return json.loads(ansible_str)
-
-
-class TestRun(unittest.TestCase):
- def setUp(self):
- self.sys_path_save = sys.path
- self.cwd_save = os.getcwd()
- sys.path.append(xos_dir)
- sys.path.append(os.path.join(xos_dir, "synchronizers", "new_base"))
- sys.path.append(
- os.path.join(xos_dir, "synchronizers", "new_base", "tests", "steps")
- )
-
- config = os.path.join(test_path, "test_config.yaml")
- from xosconfig import Config
-
- Config.clear()
- Config.init(config, "synchronizer-config-schema.yaml")
-
- from synchronizers.new_base.mock_modelaccessor_build import (
- build_mock_modelaccessor,
- )
-
- build_mock_modelaccessor(xos_dir, services_dir=None, service_xprotos=[])
-
- os.chdir(os.path.join(test_path, "..")) # config references tests/model-deps
-
- import event_loop
-
- reload(event_loop)
- import backend
-
- reload(backend)
- from modelaccessor import model_accessor
-
- # import all class names to globals
- for (k, v) in model_accessor.all_model_classes.items():
- globals()[k] = v
-
- b = backend.Backend()
- steps_dir = Config.get("steps_dir")
- self.steps = b.load_sync_step_modules(steps_dir)
- self.synchronizer = event_loop.XOSObserver(self.steps)
- try:
- os.remove("/tmp/sync_ports")
- except OSError:
- pass
- try:
- os.remove("/tmp/delete_ports")
- except OSError:
- pass
-
- def tearDown(self):
- sys.path = self.sys_path_save
- os.chdir(self.cwd_save)
-
- @mock.patch(
- "steps.sync_instances.syncstep.run_template",
- side_effect=run_fake_ansible_template,
- )
- @mock.patch("event_loop.model_accessor")
- def test_run_once(self, mock_run_template, mock_accessor, *_other_accessors):
-
- pending_objects, pending_steps = self.synchronizer.fetch_pending()
- pending_objects2 = list(pending_objects)
-
- any_cs = next(
- obj for obj in pending_objects if obj.leaf_model_name == "ControllerSlice"
- )
- any_instance = next(
- obj for obj in pending_objects2 if obj.leaf_model_name == "Instance"
- )
-
- slice = Slice()
- any_instance.slice = slice
- any_cs.slice = slice
-
- self.synchronizer.run_once()
-
- sync_ports = open("/tmp/sync_ports").read()
- delete_ports = open("/tmp/delete_ports").read()
-
- self.assertIn("successful", sync_ports)
- self.assertIn("successful", delete_ports)
-
-
-if __name__ == "__main__":
- unittest.main()