From 3ce698ee20cca69104874d42e64300abe641a27c Mon Sep 17 00:00:00 2001 From: Bertrand Souville Date: Mon, 27 Nov 2017 17:15:54 +0100 Subject: Proposal to move Promise shim-layer code to a new deprecated folder Promise test cases have been disabled in Functest Promise shim-layer has been marked as DEPRECATED in Euphrates Change-Id: I98ecd9ae2b25c102f478fc3869f23e6c70d32d8d Signed-off-by: Bertrand Souville --- .../promise/test/functest/run_promise_tests.py | 236 ++ deprecated/requirements.txt | 1 + deprecated/setup.cfg | 8 + deprecated/setup.py | 22 + deprecated/source/LICENSE | 202 + deprecated/source/README.md | 144 + .../config/custom-environment-variables.yaml | 25 + deprecated/source/config/default.yaml | 11 + deprecated/source/config/demo.json | 118 + deprecated/source/config/functest.yaml | 9 + deprecated/source/config/test-intercloud.yaml | 21 + deprecated/source/forge.yaml | 51 + deprecated/source/index.yaml | 4120 ++++++++++++++++++++ deprecated/source/openstack.yaml | 22 + deprecated/source/package.json | 41 + deprecated/source/promise.yaml | 299 ++ .../source/schema/access-control-models.yang | 92 + deprecated/source/schema/nfv-infrastructure.yang | 322 ++ deprecated/source/schema/nfv-mano.yang | 149 + deprecated/source/schema/openstack-compute.yang | 72 + deprecated/source/schema/openstack-identity.yang | 84 + deprecated/source/schema/openstack.yang | 74 + deprecated/source/schema/opnfv-promise.yang | 642 +++ deprecated/source/spec/openstack-intents.coffee | 14 + deprecated/source/spec/promise-intents.coffee | 379 ++ deprecated/source/spec/promise-module.coffee | 80 + deprecated/source/test/mocha.opts | 2 + deprecated/source/test/promise-intents.coffee | 445 +++ promise/test/functest/run_promise_tests.py | 236 -- requirements.txt | 1 - setup.cfg | 8 - setup.py | 22 - source/.gitignore | 16 - source/.npmignore | 2 - source/LICENSE | 202 - source/README.md | 144 - source/config/custom-environment-variables.yaml | 25 - source/config/default.yaml | 11 - source/config/demo.json | 118 - source/config/functest.yaml | 9 - source/config/test-intercloud.yaml | 21 - source/forge.yaml | 51 - source/index.yaml | 4120 -------------------- source/openstack.yaml | 22 - source/package.json | 41 - source/promise.yaml | 299 -- source/schema/access-control-models.yang | 92 - source/schema/nfv-infrastructure.yang | 322 -- source/schema/nfv-mano.yang | 149 - source/schema/openstack-compute.yang | 72 - source/schema/openstack-identity.yang | 84 - source/schema/openstack.yang | 74 - source/schema/opnfv-promise.yang | 642 --- source/spec/openstack-intents.coffee | 14 - source/spec/promise-intents.coffee | 379 -- source/spec/promise-module.coffee | 80 - source/test/mocha.opts | 2 - source/test/promise-intents.coffee | 445 --- 58 files changed, 7685 insertions(+), 7703 deletions(-) create mode 100644 deprecated/promise/test/functest/run_promise_tests.py create mode 100644 deprecated/requirements.txt create mode 100644 deprecated/setup.cfg create mode 100644 deprecated/setup.py create mode 100644 deprecated/source/LICENSE create mode 100644 deprecated/source/README.md create mode 100644 deprecated/source/config/custom-environment-variables.yaml create mode 100644 deprecated/source/config/default.yaml create mode 100644 deprecated/source/config/demo.json create mode 100644 deprecated/source/config/functest.yaml create mode 100644 deprecated/source/config/test-intercloud.yaml create mode 100644 deprecated/source/forge.yaml create mode 100644 deprecated/source/index.yaml create mode 100644 deprecated/source/openstack.yaml create mode 100644 deprecated/source/package.json create mode 100644 deprecated/source/promise.yaml create mode 100644 deprecated/source/schema/access-control-models.yang create mode 100644 deprecated/source/schema/nfv-infrastructure.yang create mode 100644 deprecated/source/schema/nfv-mano.yang create mode 100644 deprecated/source/schema/openstack-compute.yang create mode 100644 deprecated/source/schema/openstack-identity.yang create mode 100644 deprecated/source/schema/openstack.yang create mode 100644 deprecated/source/schema/opnfv-promise.yang create mode 100644 deprecated/source/spec/openstack-intents.coffee create mode 100644 deprecated/source/spec/promise-intents.coffee create mode 100644 deprecated/source/spec/promise-module.coffee create mode 100644 deprecated/source/test/mocha.opts create mode 100644 deprecated/source/test/promise-intents.coffee delete mode 100644 promise/test/functest/run_promise_tests.py delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 source/.gitignore delete mode 100644 source/.npmignore delete mode 100644 source/LICENSE delete mode 100644 source/README.md delete mode 100644 source/config/custom-environment-variables.yaml delete mode 100644 source/config/default.yaml delete mode 100644 source/config/demo.json delete mode 100644 source/config/functest.yaml delete mode 100644 source/config/test-intercloud.yaml delete mode 100644 source/forge.yaml delete mode 100644 source/index.yaml delete mode 100644 source/openstack.yaml delete mode 100644 source/package.json delete mode 100644 source/promise.yaml delete mode 100644 source/schema/access-control-models.yang delete mode 100644 source/schema/nfv-infrastructure.yang delete mode 100644 source/schema/nfv-mano.yang delete mode 100644 source/schema/openstack-compute.yang delete mode 100644 source/schema/openstack-identity.yang delete mode 100644 source/schema/openstack.yang delete mode 100644 source/schema/opnfv-promise.yang delete mode 100644 source/spec/openstack-intents.coffee delete mode 100644 source/spec/promise-intents.coffee delete mode 100644 source/spec/promise-module.coffee delete mode 100644 source/test/mocha.opts delete mode 100644 source/test/promise-intents.coffee diff --git a/deprecated/promise/test/functest/run_promise_tests.py b/deprecated/promise/test/functest/run_promise_tests.py new file mode 100644 index 0000000..a57918c --- /dev/null +++ b/deprecated/promise/test/functest/run_promise_tests.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# +# Copyright (c) 2015 All rights reserved +# This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +import argparse +import json +import logging +import os +import re +import subprocess +import sys +import time + +import functest.utils.openstack_utils as os_utils +from functest.utils.constants import CONST + +parser = argparse.ArgumentParser() + +parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") +parser.add_argument("-r", "--report", + help="Create json result file", + action="store_true") +args = parser.parse_args() + + +PROMISE_REPO_DIR = '/src/promise' +RESULTS_DIR = CONST.dir_results + +PROMISE_TENANT_NAME = CONST.promise_tenant_name +PROMISE_PROJECT_NAME = CONST.promise_tenant_name +PROMISE_PROJECT_DESCRIPTION = CONST.promise_tenant_description +PROMISE_USER_NAME = CONST.promise_user_name +PROMISE_USER_PWD = CONST.promise_user_pwd +PROMISE_IMAGE_NAME = CONST.promise_image_name +PROMISE_FLAVOR_NAME = CONST.promise_flavor_name +PROMISE_FLAVOR_VCPUS = CONST.promise_flavor_vcpus +PROMISE_FLAVOR_RAM = CONST.promise_flavor_ram +PROMISE_FLAVOR_DISK = CONST.promise_flavor_disk + + +GLANCE_IMAGE_FILENAME = CONST.openstack_image_file_name +GLANCE_IMAGE_FORMAT = CONST.openstack_image_disk_format +GLANCE_IMAGE_NAME = CONST.openstack_image_file_name +GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_images, + GLANCE_IMAGE_FILENAME) + +PROMISE_NET_NAME = CONST.promise_network_name +PROMISE_SUBNET_NAME = CONST.promise_subnet_name +PROMISE_SUBNET_CIDR = CONST.promise_subnet_cidr +PROMISE_ROUTER_NAME = CONST.promise_router_name + + +""" logging configuration """ +logger = logging.getLogger('promise') + + +def main(): + return_code = -1 + os_auth = os.environ["OS_AUTH_URL"] + + creds = os_utils.get_credentials() + + try: + logger.info("Env variables") + logger.info("OS_AUTH_URL: %s" % os.environ["OS_AUTH_URL"]) + logger.info("OS_IDENTITY_API_VERSION: %s " % + os.environ["OS_IDENTITY_API_VERSION"]) + logger.info("OS_USER_DOMAIN_NAME: %s" % + os.environ["OS_USER_DOMAIN_NAME"]) + logger.info("OS_PROJECT_DOMAIN_NAME: %s" % + os.environ["OS_PROJECT_DOMAIN_NAME"]) + except KeyError: + logger.error("Please set the OS environment variables") + + keystone_client = os_utils.get_keystone_client() + + logger.info("Creating project '%s'..." % PROMISE_PROJECT_NAME) + project_id = os_utils.create_tenant( + keystone_client, PROMISE_PROJECT_NAME, PROMISE_PROJECT_DESCRIPTION) + if not project_id: + logger.error("Error : Failed to create %s project" + % PROMISE_PROJECT_NAME) + return return_code + logger.debug("Project '%s' created successfully." % PROMISE_PROJECT_NAME) + + roles_name = ["_member_", "Member"] + role_id = '' + for role_name in roles_name: + if role_id == '': + role_id = os_utils.get_role_id(keystone_client, role_name) + + if role_id == '': + logger.error("Error : Failed to get id for %s role" % role_name) + return return_code + + domain_id = '' + domain_id = os_utils.get_domain_id(keystone_client, + os.environ["OS_USER_DOMAIN_NAME"]) + if domain_id == '': + logger.error("Error: Failed to get id for %s domain" % + os.environ["OS_USER_DOMAIN_NAME"]) + return return_code + + logger.info("Creating user '%s'..." % PROMISE_USER_NAME) + try: + user = keystone_client.users.create(name=PROMISE_USER_NAME, + domain=domain_id, + password=PROMISE_USER_PWD) + except Exception as e: + logger.error("Error : Failed to create %s user" % PROMISE_USER_NAME) + return return_code + logger.debug("User '%s' created successfully." % PROMISE_USER_NAME) + + try: + keystone_client.roles.grant(role=role_id, user=user.id, + project=project_id) + except Exception as e: + logger.error("Error: Failed to grant member role on project %s" % + project_id) + return return_code + + nova_client = os_utils.get_nova_client() + glance_client = os_utils.get_glance_client() + + logger.info("Creating image '%s' from '%s'..." % (PROMISE_IMAGE_NAME, + GLANCE_IMAGE_PATH)) + + logger.info("Upload some OS images if it doesn't exist") + + image_id = os_utils.get_image_id(glance_client, GLANCE_IMAGE_NAME) + + if image_id == '': + logger.info("%s image doesn't exist on glance repo" % GLANCE_IMAGE_NAME) + logger.info("Try downloading this image and upload on glance !") + image_id = os_utils.create_glance_image( + glance_client, GLANCE_IMAGE_NAME, GLANCE_IMAGE_PATH) + + if image_id == '': + logger.error("Failed to create the Glance image...") + return return_code + + logger.debug("Image '%s' with ID '%s' created successfully." + % (PROMISE_IMAGE_NAME, image_id)) + flavor_id = os_utils.get_flavor_id(nova_client, PROMISE_FLAVOR_NAME) + if flavor_id == '': + logger.info("Creating flavor '%s'..." % PROMISE_FLAVOR_NAME) + flavor_id = os_utils.create_flavor(nova_client, + PROMISE_FLAVOR_NAME, + PROMISE_FLAVOR_RAM, + PROMISE_FLAVOR_DISK, + PROMISE_FLAVOR_VCPUS) + if not flavor_id: + logger.error("Failed to create the Flavor...") + return return_code + logger.debug("Flavor '%s' with ID '%s' created successfully." % + (PROMISE_FLAVOR_NAME, flavor_id)) + else: + logger.debug("Using existing flavor '%s' with ID '%s'..." + % (PROMISE_FLAVOR_NAME, flavor_id)) + + network_dic = os_utils.create_shared_network_full(PROMISE_NET_NAME, + PROMISE_SUBNET_NAME, + PROMISE_ROUTER_NAME, + PROMISE_SUBNET_CIDR) + if not network_dic: + logger.error("Failed to create the private network...") + return return_code + + logger.info("Exporting environment variables...") + os.environ["NODE_ENV"] = "functest" + os.environ["OS_PASSWORD"] = PROMISE_USER_PWD + os.environ["OS_TEST_IMAGE"] = image_id + os.environ["OS_TEST_FLAVOR"] = flavor_id + os.environ["OS_TEST_NETWORK"] = network_dic["net_id"] + os.environ["OS_PROJECT_NAME"] = PROMISE_PROJECT_NAME + os.environ["OS_USERNAME"] = PROMISE_USER_NAME + + os.chdir(PROMISE_REPO_DIR + '/source/') + results_file_name = os.path.join(RESULTS_DIR, 'promise-results.json') + results_file = open(results_file_name, 'w+') + cmd = 'npm run -s test -- --reporter json' + + logger.info("Running command: %s" % cmd) + ret = subprocess.call(cmd, shell=True, stdout=results_file, + stderr=subprocess.STDOUT) + results_file.close() + + if ret == 0: + logger.info("The test succeeded.") + return_code = 0 + else: + logger.info("The command '%s' failed." % cmd) + + # Print output of file + with open(results_file_name, 'r') as results_file: + data = results_file.read() + logger.debug("\n%s" % data) + json_data = json.loads(data) + + suites = json_data["stats"]["suites"] + tests = json_data["stats"]["tests"] + passes = json_data["stats"]["passes"] + pending = json_data["stats"]["pending"] + failures = json_data["stats"]["failures"] + start_time_json = json_data["stats"]["start"] + end_time = json_data["stats"]["end"] + duration = float(json_data["stats"]["duration"]) / float(1000) + + logger.info("\n" + "****************************************\n" + " Promise test report\n\n" + "****************************************\n" + " Suites: \t%s\n" + " Tests: \t%s\n" + " Passes: \t%s\n" + " Pending: \t%s\n" + " Failures:\t%s\n" + " Start: \t%s\n" + " End: \t%s\n" + " Duration:\t%s\n" + "****************************************\n\n" + % (suites, tests, passes, pending, failures, + start_time_json, end_time, duration)) + end_time = time.time() + + return return_code + + +if __name__ == '__main__': + logging.basicConfig(level=logging.INFO) + sys.exit(main()) diff --git a/deprecated/requirements.txt b/deprecated/requirements.txt new file mode 100644 index 0000000..d39c387 --- /dev/null +++ b/deprecated/requirements.txt @@ -0,0 +1 @@ +functest diff --git a/deprecated/setup.cfg b/deprecated/setup.cfg new file mode 100644 index 0000000..dcdaa25 --- /dev/null +++ b/deprecated/setup.cfg @@ -0,0 +1,8 @@ +[metadata] +name = promise +version = 2017.9.0 +home-page = https://wiki.opnfv.org/display/promise/Promise + +[files] +packages = promise/test/functest +scripts = promise/test/functest/run_promise_tests.py diff --git a/deprecated/setup.py b/deprecated/setup.py new file mode 100644 index 0000000..a1e9b3b --- /dev/null +++ b/deprecated/setup.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# Copyright (c) 2017 Orange and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +import setuptools + +# In python < 2.7.4, a lazy loading of package `pbr` will break +# setuptools if some other modules registered functions in `atexit`. +# solution from: http://bugs.python.org/issue15881#msg170215 +try: + import multiprocessing # noqa +except ImportError: + pass + +setuptools.setup( + setup_requires=['pbr>=1.8'], + pbr=True) diff --git a/deprecated/source/LICENSE b/deprecated/source/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/deprecated/source/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/deprecated/source/README.md b/deprecated/source/README.md new file mode 100644 index 0000000..681e2b9 --- /dev/null +++ b/deprecated/source/README.md @@ -0,0 +1,144 @@ +# Resource Management for Virtual Infrastructure + +**Promise** is a resource reservation and management project to identify NFV related requirements and realize resource reservation for future usage by capacity management of resource pools regarding compute, network and storage. + +The following are the key features provided by this module: + +* Resource Capacity Management +* Resource Reservation +* Resource Allocation + +This module also contains a collection of [YANG data models](schema/) as defined under the direction of [OPNFV Promise](http://wiki.opnfv.org/promise) project. + +## Installation + +`opnfv-promise` is built with [YangForge](http://github.com/opnfv/yangforge) data modeling +framework. You will need to first install `yangforge` and use the +provided `yfc` command line utility to run this module. + +```bash +$ npm install -g yangforge +``` + +There are also alternative installer plugins for [Fuel](http://github.com/opnfv/fuel-plugin-promise) and [Juju](http://github.com/opnfv/juju-plugin-promise). + +## Usage +```bash +$ yfc run promise.yaml +``` + +The `yfc run` command will load the primary application +package from this repository along with any other dependency +files/assets referenced within the YAML manifest and instantiate the +opnfv-promise module and run REST/JSON interface by default listening +on port 5000. + +You can also checkout this GIT repository or simply download the files +into your local system and run the application. + +## Testing + +```bash +$ npm install +$ npm test +``` + +TBD + +## Primary YANG Data Models + +name | description | status +--- | --- | --- +[opnfv-promise](schema/opnfv-promise.yang) | provide resource reservation and capacity management | 95% complete +[nfv-infrastructure](schema/nfv-infrastructure.yang) | common NFV Infrastructure resource models | 80% complete +[nfv-mano](schema/nfv-mano.yang) | common NFV MANO resource models including VIM | 20% complete +[openstack](schema/openstack.yang) | openstack specific VIM extensions | 50% complete + +## Promise Information Models + +### ResourceReservation + +The data model describing the required parameters regarding a resource +reservation. The schema definition expressed in Yang can be found +[here](schema/opnfv-promise.yang). + +#### Key Elements + +Name | Type | Description +--- | --- | --- +start | ys:date-and-time | Timestamp of when the consumption of reserved resources can begin +end | ys:date-and-time | Timestamp of when the consumption of reserved resource must end +expiry | number | Duration expressed in seconds since `start` when resource not yet allocated shall be released back to the available zone +zone | nfvi:AvailabilityZone | Reference to a zone where the resources will be reserved +capacity | object | Quantity of resources to be reserved per resource types +attributes | list | References to resource attributes needed for reservation +resources | list (nfvi:ResourceElement) | Reference to a collection of existing resource elements required + +#### State Elements (read-only) + +State Elements are available as part of lookup response about the data model. + +Name | Type | Description +--- | --- | --- +provider | nfvi:ResourceProvider | Reference to a specific provider when reservation service supports multiple providers +remaining | object | Quantity of resources remaining for consumption based on consumed allocations +allocations | list (nfvi:ResourceAllocation) | Reference to a collection of consumed allocations referencing this reservation + +#### Notification Elements + +Name | Type | Description +--- | --- | --- +reservation-event | Event | Subscribers will be notified if the reservation encounters an error or other events + +#### Inherited Elements + +##### Extended from [nfvi:ResourceElement](schema/nfv-infrastructure.yang) + +Name | Type | Description +--- | --- | --- +id | yang:uuid | A GUID identifier for the data model (usually auto-generated, but can also be specified) +name | string | Name of the data model +enabled | boolean | Enable/Disable the data model +protected | boolean | Prevent model from being destroyed when protected +owner | nfvi:AccessIdentity | An owner for the data model +visibility | enumeration | Visibility level of the given data model +tags | list (string) | List of string tags for query/filter +members | list (nfvi:AccessIdentity) | List of additional AccessIdentities that can operate on the data model + +### Resource Allocation + +The data model describing the required parameters regarding a resource +allocation. The schema definition expressed in YANG can be found +[here](schema/opnfv-promise.yang). + +#### Key Elements + +Name | Type | Description +--- | --- | --- +reservation | nfvi:ResourceReservation | Reference to an existing reservation identifier +allocate-on-start | boolean | Specify whether the allocation can take effect automatically upon reservation 'start' +resources | list (nfvi:ResourceElement) | Reference to a collection of new resource elements to be allocated + +#### State Elements (read-only) + +Name | Type | Description +--- | --- | --- +priority | number | Read-only state information about the priority classification of the reservation + +#### Inherited Elements + +##### Extended from [nfvi:ResourceElement](schema/nfv-infrastructure.yang) + +Name | Type | Description +--- | --- | --- +id | yang:uuid | A GUID identifier for the data model (usually auto-generated, but can also be specified) +name | string | Name of the data model +enabled | boolean | Enable/Disable the data model +protected | boolean | Prevent model from being destroyed when protected +owner | nfvi:AccessIdentity | An owner for the data model +visibility | enumeration | Visibility level of the given data model +tags | list (string) | List of string tags for query/filter +members | list (nfvi:AccessIdentity) | List of additional AccessIdentities that can operate on the data model + +## License + [Apache-2.0](LICENSE) diff --git a/deprecated/source/config/custom-environment-variables.yaml b/deprecated/source/config/custom-environment-variables.yaml new file mode 100644 index 0000000..001e799 --- /dev/null +++ b/deprecated/source/config/custom-environment-variables.yaml @@ -0,0 +1,25 @@ +# OPNFV FuncTest config (refer to schema/opnfv-functest.yang) +opnfv-functest: + environment: + installer: + type: INSTALLER_TYPE + address: INSTALLER_IP + lab: NODE_NAME + +# OpenStack config (native) +openstack: + auth: + endpoint: OS_AUTH_URL + strategy: OS_AUTH_STRATEGY + project: + id: OS_PROJECT_ID + name: OS_PROJECT_NAME + domain-name: OS_PROJECT_DOMAIN_NAME + username: OS_USERNAME + password: OS_PASSWORD + user-domain-name: OS_USER_DOMAIN_NAME + test: + image: OS_TEST_IMAGE + flavor: OS_TEST_FLAVOR + network: OS_TEST_NETWORK + diff --git a/deprecated/source/config/default.yaml b/deprecated/source/config/default.yaml new file mode 100644 index 0000000..52bb61a --- /dev/null +++ b/deprecated/source/config/default.yaml @@ -0,0 +1,11 @@ +# default configuration for 'npm test' + +opnfv-promise: + promise: + policy: + reservation: + max-future-start-range: + max-future-end-range: + max-duration: + expiry: 600 + diff --git a/deprecated/source/config/demo.json b/deprecated/source/config/demo.json new file mode 100644 index 0000000..dffb3af --- /dev/null +++ b/deprecated/source/config/demo.json @@ -0,0 +1,118 @@ +{ + "opnfv-promise": { + "promise": { + "providers": [ + { + "name": "example-demo-provider", + "token": "dummy-token" + } + ], + "pools": [ + { + "ResourcePool": { + "id": "4085f0da-8030-4252-a0ff-c6f93870eb5f", + "name": "OPNFV OpenStack - West", + "source": "example-demo-provider", + "capacity": { + "cores": 100, + "ram": 262144, + "instances": 500, + "networks": 100, + "ports": 100, + "routers": 30, + "subnets": 1000, + "addresses": 500, + "gigabytes": 10000, + "snapshots": 100, + "volumes": 100 + } + } + } + ], + "reservations": [ + { + "capacity": { + "cores": 10, + "ram": 4096, + "instances": 10, + "networks": 4, + "ports": 10, + "routers": 1, + "subnets": 1, + "addresses": 10, + "gigabytes": 0, + "snapshots": 0, + "volumes": 0 + }, + "start": "2015-11-07T10:17:12.747Z", + "end": "2016-02-13T10:17:18.226Z", + "pools": [ + "4085f0da-8030-4252-a0ff-c6f93870eb5f" + ] + }, + { + "capacity": { + "cores": 20, + "ram": 10000, + "instances": 5, + "networks": 2, + "ports": 10, + "routers": 1, + "subnets": 1, + "addresses": 5, + "gigabytes": 0, + "snapshots": 0, + "volumes": 0 + }, + "start": "2015-11-09T10:17:12.747Z", + "end": "2016-02-11T10:17:18.226Z", + "pools": [ + "4085f0da-8030-4252-a0ff-c6f93870eb5f" + ] + }, + { + "id": "c7287f30-2c65-4a88-a047-48724b8ff747", + "capacity": { + "cores": 10, + "ram": 4096, + "instances": 10, + "networks": 5, + "ports": 10, + "routers": 1, + "subnets": 5, + "addresses": 20, + "gigabytes": 0, + "snapshots": 0, + "volumes": 0 + }, + "start": "2015-11-10T10:17:12.747Z", + "end": "2015-12-13T10:17:18.226Z", + "pools": [ + "4085f0da-8030-4252-a0ff-c6f93870eb5f" + ] + }, + { + "id": "0f2e31f7-9760-416d-8d53-1ee68aa4b11f", + "capacity": { + "cores": 10, + "ram": 4096, + "instances": 5, + "networks": 2, + "ports": 10, + "routers": 1, + "subnets": 1, + "addresses": 5, + "gigabytes": 0, + "snapshots": 0, + "volumes": 0 + }, + "start": "2015-11-09T10:17:12.747Z", + "end": "2015-12-03T10:17:18.226Z", + "pools": [ + "4085f0da-8030-4252-a0ff-c6f93870eb5f" + ] + } + ] + } + } +} diff --git a/deprecated/source/config/functest.yaml b/deprecated/source/config/functest.yaml new file mode 100644 index 0000000..6655fc4 --- /dev/null +++ b/deprecated/source/config/functest.yaml @@ -0,0 +1,9 @@ +# NODE_ENV=functest + +opnfv-functest: + environment: + images: + - + name: cirros + path: /home/opnfv/functest/images/cirros-0.3.5-x86_64-disk.img + diff --git a/deprecated/source/config/test-intercloud.yaml b/deprecated/source/config/test-intercloud.yaml new file mode 100644 index 0000000..f5e04ed --- /dev/null +++ b/deprecated/source/config/test-intercloud.yaml @@ -0,0 +1,21 @@ +# the following config is used when ENV is as follows: +# NODE_ENV=test +# NODE_APP_INSTANCE=intercloud +openstack: + auth: + strategy: keystone + endpoint: http://vhub4.intercloud.net:5000/v2.0 + tenant: + id: 62a2d90992114994977fd6707bac5758 + username: peter + password: # set OS_PASSWORD=xxxx environmental variable + test: + image: ee0fb445-0fc2-4fda-a2dc-175bf3cc3cb1 + flavor: 2312fd98-369e-4361-b967-606373891c11 + +opnfv-promise: + promise: + policy: + reservation: + max-future-start-range: 7 + max-duration: 24 diff --git a/deprecated/source/forge.yaml b/deprecated/source/forge.yaml new file mode 100644 index 0000000..d8d1f39 --- /dev/null +++ b/deprecated/source/forge.yaml @@ -0,0 +1,51 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# + +# YF 0.12.x forge manifest + +compilers: + yang: yangforge/register + coffee: coffee-script/register + +components: + nfvi: + - yangforge:common + - schema/access-control-models.yang + - schema/nfv-infrastructure.yang + - schema/nfv-mano.yang + + # primary promise service + promise: + - nfvi + - schema/opnfv-promise.yang + - spec/promise.yaml + + # base openstack composition + openstack: + - nfvi + - schema/openstack.yang + - schema/openstack-identity.yang + - schema/openstack-image.yang + - schema/openstack-compute.yang + - schema/openstack-storage.yang + - schema/openstack-network.yang + - spec/openstack.yaml + + # openstack with promise augmentation + os-promise: + - promise + - openstack + - schema/openstack-promise.yang + - spec/openstack-promise.yaml + + # test component for using with 'npm test' + test: + - os-promise + - schema/opnfv-functest.yang + - config/demo.json diff --git a/deprecated/source/index.yaml b/deprecated/source/index.yaml new file mode 100644 index 0000000..071d685 --- /dev/null +++ b/deprecated/source/index.yaml @@ -0,0 +1,4120 @@ +synth: source +name: opnfv-promise +version: ! '' +description: Resource Management for Virtualized Infrastructure +license: Apache-2.0 +schema: + module: + opnfv-promise: + namespace: 'urn:opnfv:promise' + prefix: promise + import: + complex-types: + prefix: ct + ietf-yang-types: + prefix: yang + ietf-inet-types: + prefix: inet + access-control-models: + prefix: acm + nfv-infrastructure: + prefix: nfvi + description: OPNFV Promise Resource Reservation/Allocation controller module + revision: + '2015-10-05': + description: Complete coverage of reservation related intents + '2015-08-06': + description: Updated to incorporate YangForge framework + '2015-04-16': + description: Initial revision. + feature: + reservation-service: + description: 'When enabled, provides resource reservation service' + multi-provider: + description: 'When enabled, provides resource management across multiple providers' + grouping: + resource-utilization: + container: + capacity: + container: + total: + description: Conceptual container that should be extended + reserved: + description: Conceptual container that should be extended + config: false + usage: + description: Conceptual container that should be extended + config: false + available: + description: Conceptual container that should be extended + config: false + temporal-resource-collection: + description: Information model capturing resource-collection with start/end time window + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + resource-usage-request: + description: |- + Information model capturing available parameters to make a resource + usage request. + reference: 'OPNFV-PROMISE, Section 3.4.1' + uses: {} + leaf: + zone: + description: Optional identifier to an Availability Zone + type: + instance-identifier: + 'ct:instance-type': 'nfvi:AvailabilityZone' + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + description: |- + Reference to a list of 'pre-existing' resource elements that are + required for fulfillment of the resource-usage-request. + + It can contain any instance derived from ResourceElement, + such as ServerInstances or even other + ResourceReservations. If the resource-usage-request is + accepted, the ResourceElement(s) listed here will be placed + into 'protected' mode as to prevent accidental removal. + + If any of these resource elements become 'unavailable' due to + environmental or administrative activity, a notification will + be issued informing of the issue. + query-start-end-window: + container: + window: + description: Matches entries that are within the specified start/end time window + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + scope: + type: + enumeration: + enum: + exclusive: + description: Matches entries that start AND end within the window + value: 0 + inclusive: + description: Matches entries that start OR end within the window + value: 1 + default: inclusive + query-resource-collection: + uses: {} + leaf-list: + without: + description: Excludes specified collection identifiers from the result + type: + instance-identifier: + 'ct:instance-type': ResourceCollection + leaf: + show-utilization: + type: boolean + default: 'true' + container: + elements: + leaf-list: + some: + description: Query for ResourceCollection(s) that contain some or more of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + every: + description: Query for ResourceCollection(s) that contain all of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + window: + description: Matches entries that are within the specified start/end time window + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + scope: + type: + enumeration: + enum: + exclusive: + description: Matches entries that start AND end within the window + value: 0 + inclusive: + description: Matches entries that start OR end within the window + value: 1 + default: inclusive + common-intent-output: + leaf: + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + utilization-output: + list: + utilization: + key: timestamp + leaf: + timestamp: + type: 'yang:date-and-time' + count: + type: int16 + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + 'ct:complex-type': + ResourceCollection: + 'ct:extends': 'nfvi:ResourceContainer' + 'ct:abstract': 'true' + description: |- + Describes an abstract ResourceCollection data model, which represents + a grouping of capacity and elements available during a given + window in time which must be extended by other resource + collection related models + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + active: + config: false + description: |- + Provides current state of this record whether it is enabled and within + specified start/end time + type: boolean + ResourcePool: + 'ct:extends': ResourceCollection + description: |- + Describes an instance of an active ResourcePool record, which + represents total available capacity and elements from a given + source. + leaf: + source: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceContainer' + require-instance: true + mandatory: true + refine: + elements: + must: + 'boolean(/source/elements/*[@id=id])': + error-message: One or more of the ResourceElement(s) does not exist in the provider to be reserved + ResourceReservation: + 'ct:extends': ResourceCollection + description: |- + Describes an instance of an accepted resource reservation request, + created usually as a result of 'create-reservation' request. + + A ResourceReservation is a derived instance of a generic + ResourceCollection which has additional parameters to map the + pool(s) that were referenced to accept this reservation as well + as to track allocations made referencing this reservation. + + Contains the capacities of various resource attributes being + reserved along with any resource elements that are needed to be + available at the time of allocation(s). + reference: 'OPNFV-PROMISE, Section 3.4.1' + leaf: + created-on: + type: 'yang:date-and-time' + config: false + modified-on: + type: 'yang:date-and-time' + config: false + leaf-list: + pools: + config: false + description: |- + Provides list of one or more pools that were referenced for providing + the requested resources for this reservation. This is an + important parameter for informing how/where allocation + requests can be issued using this reservation since it is + likely that the total reserved resource capacity/elements are + made availble from multiple sources. + type: + instance-identifier: + 'ct:instance-type': ResourcePool + require-instance: true + allocations: + config: false + description: |- + Reference to a collection of consumed allocations referencing + this reservation. + type: + instance-identifier: + 'ct:instance-type': ResourceAllocation + require-instance: true + container: + remaining: + config: false + description: |- + Provides visibility into total remaining capacity for this + reservation based on allocations that took effect utilizing + this reservation ID as a reference. + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + ResourceAllocation: + 'ct:extends': ResourceCollection + description: |- + A ResourceAllocation record denotes consumption of resources from a + referenced ResourcePool. + + It does not reflect an accepted request but is created to + represent the actual state about the ResourcePool. It is + created once the allocation(s) have successfully taken effect + on the 'source' of the ResourcePool. + + The 'priority' state indicates the classification for dealing + with resource starvation scenarios. Lower priority allocations + will be forcefully terminated to allow for higher priority + allocations to be fulfilled. + + Allocations without reference to an existing reservation will + receive the lowest priority. + reference: 'OPNFV-PROMISE, Section 3.4.3' + leaf: + reservation: + description: Reference to an existing reservation identifier (optional) + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + require-instance: true + pool: + description: Reference to an existing resource pool from which allocation is drawn + type: + instance-identifier: + 'ct:instance-type': ResourcePool + require-instance: true + priority: + config: false + description: Reflects current priority level of the allocation according to classification rules + type: + enumeration: + enum: + high: + value: 1 + normal: + value: 2 + low: + value: 3 + default: normal + container: + instance-ref: + config: false + description: Reference to actual instance identifier of the provider/server for this allocation + leaf: + provider: + type: + instance-identifier: + 'ct:instance-type': ResourceProvider + server: + type: 'yang:uuid' + ResourceFlavor: + description: currently NOT an extension of ResourceElement. + key: id + leaf: + id: + type: string + name: + type: string + disk: + type: uint32 + units: GB + default: '0' + ram: + type: uint32 + units: MB + default: '0' + vcpus: + type: uint16 + default: '0' + ResourceProvider: + 'ct:extends': 'nfvi:ResourceContainer' + leaf: + token: + type: string + mandatory: true + container: + services: + config: false + container: + compute: + leaf: + endpoint: + type: 'inet:uri' + 'ct:instance-list': + flavors: + 'ct:instance-type': ResourceFlavor + leaf-list: + pools: + config: false + description: Provides list of one or more pools that are referencing this provider. + type: + instance-identifier: + 'ct:instance-type': ResourcePool + require-instance: true + container: + promise: + uses: {} + 'ct:instance-list': + providers: + if-feature: multi-provider + description: Aggregate collection of all registered ResourceProvider instances for Promise resource management service + 'ct:instance-type': ResourceProvider + status: unavailable + pools: + if-feature: reservation-service + description: Aggregate collection of all ResourcePool instances + 'ct:instance-type': ResourcePool + status: unavailable + reservations: + if-feature: reservation-service + description: Aggregate collection of all ResourceReservation instances + 'ct:instance-type': ResourceReservation + status: unavailable + allocations: + description: Aggregate collection of all ResourceAllocation instances + 'ct:instance-type': ResourceAllocation + container: + policy: + container: + reservation: + leaf: + max-future-start-range: + description: "Enforce reservation request 'start' time is within allowed range from now" + type: + uint16: + range: 0..365 + units: days + max-future-end-range: + description: "Enforce reservation request 'end' time is within allowed range from now" + type: + uint16: + range: 0..365 + units: days + max-duration: + description: Enforce reservation duration (end-start) does not exceed specified threshold + type: uint16 + units: hours + default: '8760' + expiry: + description: |- + Duration in minutes from start when unallocated reserved resources + will be released back into the pool + type: uint32 + units: minutes + capacity: + container: + total: + description: Conceptual container that should be extended + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + reserved: + description: Conceptual container that should be extended + config: false + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + usage: + description: Conceptual container that should be extended + config: false + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + available: + description: Conceptual container that should be extended + config: false + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + rpc: + create-reservation: + if-feature: reservation-service + description: Make a request to the reservation system to reserve resources + input: + uses: {} + leaf: + zone: + description: Optional identifier to an Availability Zone + type: + instance-identifier: + 'ct:instance-type': 'nfvi:AvailabilityZone' + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + description: |- + Reference to a list of 'pre-existing' resource elements that are + required for fulfillment of the resource-usage-request. + + It can contain any instance derived from ResourceElement, + such as ServerInstances or even other + ResourceReservations. If the resource-usage-request is + accepted, the ResourceElement(s) listed here will be placed + into 'protected' mode as to prevent accidental removal. + + If any of these resource elements become 'unavailable' due to + environmental or administrative activity, a notification will + be issued informing of the issue. + output: + leaf: + reservation-id: + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + status: unavailable + update-reservation: + description: Update reservation details for an existing reservation + input: + leaf: + reservation-id: + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + require-instance: true + mandatory: true + zone: + description: Optional identifier to an Availability Zone + type: + instance-identifier: + 'ct:instance-type': 'nfvi:AvailabilityZone' + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + uses: {} + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + description: |- + Reference to a list of 'pre-existing' resource elements that are + required for fulfillment of the resource-usage-request. + + It can contain any instance derived from ResourceElement, + such as ServerInstances or even other + ResourceReservations. If the resource-usage-request is + accepted, the ResourceElement(s) listed here will be placed + into 'protected' mode as to prevent accidental removal. + + If any of these resource elements become 'unavailable' due to + environmental or administrative activity, a notification will + be issued informing of the issue. + output: + leaf: + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + cancel-reservation: + description: Cancel the reservation and be a good steward + input: + leaf: + reservation-id: + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + mandatory: true + output: + leaf: + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + query-reservation: + if-feature: reservation-service + description: Query the reservation system to return matching reservation(s) + input: + leaf: + zone: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:AvailabilityZone' + show-utilization: + type: boolean + default: 'true' + uses: {} + leaf-list: + without: + description: Excludes specified collection identifiers from the result + type: + instance-identifier: + 'ct:instance-type': ResourceCollection + container: + elements: + leaf-list: + some: + description: Query for ResourceCollection(s) that contain some or more of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + every: + description: Query for ResourceCollection(s) that contain all of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + window: + description: Matches entries that are within the specified start/end time window + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + scope: + type: + enumeration: + enum: + exclusive: + description: Matches entries that start AND end within the window + value: 0 + inclusive: + description: Matches entries that start OR end within the window + value: 1 + default: inclusive + output: + leaf-list: + reservations: + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + list: + utilization: + key: timestamp + leaf: + timestamp: + type: 'yang:date-and-time' + count: + type: int16 + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + status: unavailable + increase-capacity: + description: Increase total capacity for the reservation system between a window in time + input: + leaf: + source: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceContainer' + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + output: + leaf: + pool-id: + type: + instance-identifier: + 'ct:instance-type': ResourcePool + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + decrease-capacity: + description: Decrease total capacity for the reservation system between a window in time + input: + leaf: + source: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceContainer' + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + output: + leaf: + pool-id: + type: + instance-identifier: + 'ct:instance-type': ResourcePool + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + query-capacity: + description: Check available capacity information about a specified resource collection + input: + leaf: + capacity: + type: + enumeration: + enum: + total: + value: 0 + reserved: + value: 1 + usage: + value: 2 + available: + value: 3 + default: available + zone: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:AvailabilityZone' + show-utilization: + type: boolean + default: 'true' + uses: {} + leaf-list: + without: + description: Excludes specified collection identifiers from the result + type: + instance-identifier: + 'ct:instance-type': ResourceCollection + container: + elements: + leaf-list: + some: + description: Query for ResourceCollection(s) that contain some or more of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + every: + description: Query for ResourceCollection(s) that contain all of these element(s) + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + window: + description: Matches entries that are within the specified start/end time window + leaf: + start: + type: 'yang:date-and-time' + end: + type: 'yang:date-and-time' + scope: + type: + enumeration: + enum: + exclusive: + description: Matches entries that start AND end within the window + value: 0 + inclusive: + description: Matches entries that start OR end within the window + value: 1 + default: inclusive + output: + leaf-list: + collections: + type: + instance-identifier: + 'ct:instance-type': ResourceCollection + list: + utilization: + key: timestamp + leaf: + timestamp: + type: 'yang:date-and-time' + count: + type: int16 + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + create-instance: + description: Create an instance of specified resource(s) utilizing capacity from the pool + input: + leaf: + provider-id: + if-feature: multi-provider + type: + instance-identifier: + 'ct:instance-type': ResourceProvider + require-instance: true + status: unavailable + name: + type: string + mandatory: true + image: + type: + union: + type: + 'yang:uuid': null + 'inet:uri': null + mandatory: true + flavor: + type: + union: + type: + 'yang:uuid': null + 'inet:uri': null + mandatory: true + reservation-id: + type: + instance-identifier: + 'ct:instance-type': ResourceReservation + require-instance: true + output: + leaf: + instance-id: + type: + instance-identifier: + 'ct:instance-type': ResourceAllocation + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + destroy-instance: + description: Destroy an instance of resource utilization and release it back to the pool + input: + leaf: + instance-id: + type: + instance-identifier: + 'ct:instance-type': ResourceAllocation + require-instance: true + output: + leaf: + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + add-provider: + description: Register a new resource provider into reservation system + input: + leaf: + provider-type: + description: Select a specific resource provider type + mandatory: true + type: + enumeration: + enum: + openstack: + value: 0 + hp: + value: 1 + rackspace: + value: 2 + amazon: + status: planned + value: 3 + joyent: + status: planned + value: 4 + azure: + status: planned + value: 5 + default: openstack + strategy: + type: + enumeration: + enum: + oauth: + value: 0 + keystone: + value: 1 + default: keystone + endpoint: + type: 'inet:uri' + description: The target endpoint for authentication + mandatory: true + default: 'http://localhost:5000/v2.0' + username: + type: string + mandatory: true + password: + type: 'acm:password' + mandatory: true + uses: {} + container: + tenant: + leaf: + id: + type: string + name: + type: string + output: + leaf: + provider-id: + type: + instance-identifier: + 'ct:instance-type': ResourceProvider + result: + type: + enumeration: + enum: + ok: + value: 0 + conflict: + value: 1 + error: + value: 2 + message: + type: string + notification: + reservation-event: null + capacity-event: null + allocation-event: null +dependencies: + access-control-models: + module: + access-control-models: + prefix: acm + namespace: 'urn:opnfv:promise:acm' + import: + complex-types: + prefix: ct + ietf-yang-types: + prefix: yang + ietf-inet-types: + prefix: inet + typedef: + password: + type: + string: + length: 1..255 + grouping: + access-credentials: + leaf: + strategy: + type: + enumeration: + enum: + oauth: + value: 0 + keystone: + value: 1 + default: oauth + endpoint: + type: 'inet:uri' + description: The target endpoint for authentication + mandatory: true + username: + type: string + mandatory: true + password: + type: 'acm:password' + mandatory: true + 'ct:complex-type': + Identity: + 'ct:abstract': 'true' + description: Identity represents an administrative access model entity + key: id + leaf: + id: + type: 'yang:uuid' + mandatory: true + name: + type: string + mandatory: true + description: + type: string + enabled: + type: boolean + default: 'true' + User: + 'ct:extends': Identity + leaf: + credential: + type: string + mandatory: true + domain: + type: + instance-identifier: + 'ct:instance-type': Domain + container: + contact: + leaf: + fullName: + type: string + email: + type: string + leaf-list: + groups: + type: + instance-identifer: + 'ct:instance-type': Group + Group: + 'ct:extends': Identity + leaf-list: + users: + type: + instance-identifier: + 'ct:instance-type': User + leaf: + domain: + type: + instance-identifier: + 'ct:instance-type': Domain + Domain: + 'ct:extends': Identity + description: |- + Domain represent a distinct administrative domain across + collection of users and groups. + 'ct:instance-list': + users: + 'ct:instance-type': User + groups: + 'ct:instance-type': Group + rpc: + create-user: null + remove-user: null + create-group: null + remove-group: null + nfv-infrastructure: + module: + nfv-infrastructure: + namespace: 'urn:opnfv:promise:nfv:infrastructure' + prefix: nfvi + import: + access-control-models: + prefix: acm + ietf-inet-types: + prefix: inet + ietf-yang-types: + prefix: yang + complex-types: + prefix: ct + description: |- + NFV Infrastructure Data Models with complex types and typed instance + identifiers representing the various ResourceElements available + in the infrastructure across compute, network, and storage. + revision: + '2015-10-13': + description: Introduce capacity and element collection into NFVI models + '2015-08-07': + description: |- + This YANG module is modeled using 'yangforge' which natively provides + complex types and typed instance identifiers. This module + provides various collections of resource management data models + for instance based management + identity: + manager: + description: used by specific modules implementing manager role for NFVI + grouping: + compute-capacity: + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + network-capacity: + leaf: + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + storage-capacity: + leaf: + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + resource-capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + resource-collection: + description: |- + Information model capturing parameters for describing a collection of + resource capacity and resource elements + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + resource-stack: + description: |- + Information model describing a NFVI resource stack comprising of + various resource elements across compute, network, and storage + 'ct:instance-list': + hosts: + 'ct:instance-type': 'nfvi:PhysicalHost' + hypervisors: + 'ct:instance-type': 'nfvi:Hypervisor' + container: + compute: + description: Contains compute related resources + 'ct:instance-list': + servers: + 'ct:instance-type': 'nfvi:ServerInstance' + images: + 'ct:instance-type': 'nfvi:VirtualMachineImage' + flavors: + 'ct:instance-type': 'nfvi:ComputeFlavor' + network: + description: Contains networking related resources + 'ct:instance-list': + networks: + 'ct:instance-type': 'nfvi:Network' + subnets: + 'ct:instance-type': 'nfvi:SubNetwork' + ports: + 'ct:instance-type': 'nfvi:SwitchPort' + 'ct:complex-type': + ResourceElement: + 'ct:abstract': 'true' + key: id + leaf: + id: + type: 'yang:uuid' + mandatory: true + name: + type: string + enabled: + type: boolean + default: 'true' + protected: + type: boolean + default: 'false' + owner: + type: + instance-identifier: + 'ct:instance-type': 'acm:Identity' + visibility: + description: "Specify visibility level available from the perspective of 'owner'" + type: + enumeration: + enum: + public: + value: 0 + domain: + value: 1 + project: + value: 2 + group: + value: 3 + user: + value: 4 + default: user + leaf-list: + tags: + type: string + members: + description: Optionally share with explicit list of members of AccessIdentity complex-type + type: + instance-identifier: + 'ct:instance-type': 'acm:Identity' + ResourceInstance: + 'ct:extends': ResourceElement + 'ct:abstract': 'true' + leaf: + status: + type: + enumeration: + enum: + active: + value: 0 + inactive: + value: 1 + pending: + value: 2 + progress: + type: + uint8: + range: 0..100 + default: '0' + ResourceContainer: + 'ct:extends': ResourceInstance + 'ct:abstract': 'true' + description: |- + An abstract resource instance which contains a collection of capacity + and elements. + container: + capacity: + uses: {} + leaf: + cores: + type: int16 + default: '0' + ram: + type: int32 + default: '0' + units: MB + instances: + type: int16 + default: '0' + networks: + type: int16 + default: '0' + ports: + type: int16 + default: '0' + routers: + type: int16 + default: '0' + subnets: + type: int16 + default: '0' + addresses: + type: int32 + default: '0' + gigabytes: + type: int32 + default: '0' + units: GB + snapshots: + type: int16 + default: '0' + volumes: + type: int16 + default: '0' + leaf-list: + elements: + type: + instance-identifier: + 'ct:instance-type': 'nfvi:ResourceElement' + require-instance: true + AvailabilityZone: + 'ct:extends': ResourceElement + PhysicalHost: + 'ct:extends': ResourceElement + leaf: + type: + type: string + version: + type: string + cpu: + type: uint8 + workload: + type: uint8 + default: '0' + uptime: + type: string + container: + ram: + leaf: + total: + type: uint32 + units: MB + used: + type: uint32 + units: MB + free: + type: uint32 + units: MB + disk: + leaf: + total: + type: uint32 + units: GB + used: + type: uint32 + units: GB + free: + type: uint32 + units: GB + leaf-list: + hypervisors: + type: + instance-identifier: + 'ct:instance-type': Hypervisor + Hypervisor: + 'ct:extends': PhysicalHost + leaf: + host: + type: + instance-identifier: + 'ct:instance-type': PhysicalHost + mandatory: true + container: + vcpu: + leaf: + total: + type: uint16 + used: + type: uint16 + free: + type: uint16 + leaf-list: + servers: + type: + instance-identifier: + 'ct:instance-type': ServerInstance + ComputeElement: + 'ct:extends': ResourceElement + 'ct:abstract': 'true' + container: + constraint: + leaf: + disk: + type: uint32 + units: GB + default: '0' + ram: + type: uint32 + units: MB + default: '0' + vcpu: + type: uint16 + default: '0' + leaf-list: + instances: + description: State info about instances currently using this resource element + type: + instance-identifier: + 'ct:instance-type': ResourceInstance + config: false + VirtualMachineImage: + 'ct:extends': ComputeElement + container: + data: + leaf: + checksum: + type: string + mandatory: true + size: + type: uint32 + units: Bytes + mandatory: true + content: + description: "should be a 'private' property so only direct access retrieves content" + type: binary + container: + format: + leaf: + container: + type: + enumeration: + enum: + ami: + value: 0 + ari: + value: 1 + aki: + value: 2 + bare: + value: 3 + ovf: + value: 4 + default: bare + disk: + type: + enumeration: + enum: + ami: + value: 0 + ari: + value: 1 + aki: + value: 2 + vhd: + value: 3 + vmdk: + value: 4 + raw: + value: 5 + qcow2: + value: 6 + vdi: + value: 7 + iso: + value: 8 + ComputeFlavor: + 'ct:extends': ResourceElement + leaf: + disk: + type: uint32 + units: GB + default: '0' + ram: + type: uint32 + units: MB + default: '0' + vcpus: + type: uint16 + default: '0' + ServerInstance: + 'ct:extends': ResourceInstance + leaf: + flavor: + type: + instance-identifier: + 'ct:instance-type': ComputeFlavor + mandatory: true + image: + type: + instance-identifier: + 'ct:instance-type': VirtualMachineImage + mandatory: true + host: + type: + instance-identifier: + 'ct:instance-type': PhysicalHost + leaf-list: + connections: + description: |- + References to collection of NetworkingElement class objects such as + Network, Subnet, Port, Router that this ServerInstance is + connected with. + type: + instance-identifier: + 'ct:instance-type': NetworkElement + NetworkElement: + 'ct:extends': ResourceElement + 'ct:abstract': 'true' + Network: + 'ct:extends': NetworkElement + leaf-list: + subnets: + type: + instance-identifier: + 'ct:instance-type': SubNetwork + SubNetwork: + 'ct:extends': NetworkElement + leaf: + network: + type: + instance-identifier: + 'ct:instance-type': Network + leaf-list: + nameservers: + type: string + container: + dhcp: + leaf: + enabled: + type: boolean + list: + pools: + leaf: + start: + type: 'inet:ip-address' + end: + type: 'inet:ip-address' + SwitchPort: + 'ct:extends': NetworkElement + leaf: + subnet: + type: + instance-identifier: + 'ct:instance-type': SubNetwork +extension: + module: + argument: name + include: 0..n + prefix: 0..1 + anyxml: 0..n + augment: 0..n + choice: 0..n + contact: 0..1 + container: 0..n + description: 0..1 + deviation: 0..n + extension: 0..n + feature: 0..n + grouping: 0..n + identity: 0..n + import: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + namespace: 0..1 + notification: 0..n + organization: 0..1 + reference: 0..1 + revision: 0..n + rpc: 0..n + typedef: 0..n + uses: 0..n + yang-version: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var changes, match, ref, synth, target; + synth = this.require('data-synth'); + ref = params.augment; + for (target in ref) { + changes = ref[target]; + match = this.locate(ctx, target); + if (match == null) { + continue; + } + synth.copy(match, changes); + } + return delete this.source[params.prefix]; + } + construct: ! |- + function (arg, params, children, ctx, self) { + return (self.origin.construct.apply(this, arguments)).merge({ + models: this.resolve('complex-type') + }); + } + complex-type: 0..n + instance: 0..n + instance-list: 0..n + origin: + argument: name + include: 0..n + prefix: 0..1 + anyxml: 0..n + augment: 0..n + choice: 0..n + contact: 0..1 + container: 0..n + description: 0..1 + deviation: 0..n + extension: 0..n + feature: 0..n + grouping: 0..n + identity: 0..n + import: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + namespace: 0..1 + notification: 0..n + organization: 0..1 + reference: 0..1 + revision: 0..n + rpc: 0..n + typedef: 0..n + uses: 0..n + yang-version: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var changes, match, ref, synth, target; + synth = this.require('data-synth'); + ref = params.augment; + for (target in ref) { + changes = ref[target]; + match = this.locate(ctx, target); + if (match == null) { + continue; + } + synth.copy(match, changes); + } + return delete this.source[params.prefix]; + } + construct: ! |- + function (arg, params, children) { + var k, m, modules, ref, synth, v; + synth = this.require('data-synth'); + modules = {}; + ref = params["import"]; + for (k in ref) { + v = ref[k]; + modules[k] = children[k]; + delete children[k]; + } + m = (synth.Store(params, function() { + return this.set({ + name: arg, + modules: modules + }); + })).bind(children); + this.define('module', arg, m); + return m; + } + prefix: + argument: value + preprocess: ! |- + function (arg, params, ctx) { + return this.source[arg] = this.source; + } + include: + argument: module + preprocess: ! |- + function (arg, params, ctx) { + var k, m, ref, ref1, ref2, results, v; + m = this.preprocess(this.resolve('dependencies', arg)); + ref = m.extension; + for (k in ref) { + v = ref[k]; + this.define('extension', k, v); + } + ref1 = m.typedef; + for (k in ref1) { + v = ref1[k]; + this.define('typedef', k, v); + } + ref2 = m.schema; + results = []; + for (k in ref2) { + v = ref2[k]; + results.push(ctx[k] = v); + } + return results; + } + revision-date: 0..1 + augment: + anyxml: 0..n + case: 0..n + choice: 0..n + container: 0..n + description: 0..1 + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + reference: 0..1 + status: 0..1 + uses: 0..n + when: 0..1 + argument: target-node + belongs-to: + prefix: 1 + preprocess: ! |- + function (arg, params, ctx) { + return this.source[params.prefix] = this.source; + } + argument: module + bit: + description: 0..1 + reference: 0..1 + status: 0..1 + position: 0..1 + argument: name + case: + anyxml: 0..n + choice: 0..n + container: 0..n + description: 0..1 + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + reference: 0..1 + status: 0..1 + uses: 0..n + when: 0..1 + argument: name + choice: + anyxml: 0..n + case: 0..n + config: 0..1 + container: 0..n + default: 0..1 + description: 0..1 + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + mandatory: 0..1 + reference: 0..1 + status: 0..1 + when: 0..1 + argument: condition + config: + preprocess: ! |- + function (arg, p, ctx) { + return ctx.config = arg === true || arg === 'true'; + } + argument: value + container: + anyxml: 0..n + choice: 0..n + config: 0..1 + container: 0..n + description: 0..1 + grouping: 0..n + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + must: 0..n + presence: 0..1 + reference: 0..1 + status: 0..1 + typedef: 0..n + uses: 0..n + when: 0..1 + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + argument: name + instance: 0..n + instance-list: 0..n + origin: + anyxml: 0..n + choice: 0..n + config: 0..1 + container: 0..n + description: 0..1 + grouping: 0..n + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + must: 0..n + presence: 0..1 + reference: 0..1 + status: 0..1 + typedef: 0..n + uses: 0..n + when: 0..1 + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + argument: name + deviate: + config: 0..1 + default: 0..1 + mandatory: 0..1 + max-elements: 0..1 + min-elements: 0..1 + must: 0..n + type: 0..1 + unique: 0..1 + units: 0..1 + argument: value + deviation: + description: 0..1 + deviate: 1..n + reference: 0..1 + argument: target-node + enum: + description: 0..1 + reference: 0..1 + status: 0..1 + value: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + if (params.value == null) { + if (this.enumValue == null) { + this.enumValue = 0; + } + params.value = this.enumValue++; + } else { + params.value = Number(params.value); + this.enumValue = params.value + 1; + } + return ctx["enum"][arg] = params; + } + argument: name + feature: + description: 0..1 + if-feature: 0..n + reference: 0..1 + status: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + if (params.status === 'unavailable') { + console.warn("feature " + arg + " is unavailable"); + if (typeof ctx.feature === 'object') { + return delete ctx.feature[arg]; + } else { + return delete ctx.feature; + } + } + } + construct: ! |- + function (arg, params, children) { + var feature; + feature = this.resolve('feature', arg); + return null; + } + argument: name + grouping: + anyxml: 0..n + choice: 0..n + container: 0..n + description: 0..1 + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + reference: 0..1 + status: 0..1 + typedef: 0..n + uses: 0..n + preprocess: ! |- + function (arg, params) { + return this.define('grouping', arg, params); + } + argument: name + instance: 0..n + instance-list: 0..n + origin: + anyxml: 0..n + choice: 0..n + container: 0..n + description: 0..1 + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + reference: 0..1 + status: 0..1 + typedef: 0..n + uses: 0..n + preprocess: ! |- + function (arg, params) { + return this.define('grouping', arg, params); + } + argument: name + identity: + base: 0..1 + description: 0..1 + reference: 0..1 + status: 0..1 + preprocess: ! |- + function (arg, params) { + return this.define('identity', arg, params); + } + argument: name + if-feature: + preprocess: ! |- + function (arg, params, ctx) { + if ((this.resolve('feature', arg)) == null) { + return ctx.status = 'unavailable'; + } + } + argument: name + import: + prefix: 1 + revision-date: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var copy, k, m, original, ref, ref1, rev, schema, source, synth, v; + synth = this.require('data-synth'); + schema = this.resolve('dependencies', arg, false); + if (schema == null) { + console.warn("no explicit dependency for " + arg + " defined, searching local filesystem"); + schema = this.parse("!yang " + arg + ".yang", this.source); + if (schema != null) { + this.define('dependencies', arg, schema); + source = this.source.parent; + while ((source.parent != null) && source.parent.name !== 'yangforge') { + source = source.parent; + } + if (source.dependencies == null) { + source.dependencies = {}; + } + source.dependencies[arg] = schema; + } + } + m = this.preprocess(schema); + if (m == null) { + throw this.error("unable to resolve '" + arg + "' in dependencies", 'import'); + } + rev = params['revision-date']; + if ((rev != null) && !(rev in m.revision)) { + throw this.error("requested " + rev + " not available in " + arg, 'import'); + } + ref = m.extension; + for (k in ref) { + v = ref[k]; + if (!(v.override === true)) { + continue; + } + original = this.resolve('extension', k); + copy = synth.copy({}, v); + copy.origin = synth.copy({}, (ref1 = original.origin) != null ? ref1 : original); + delete copy.override; + this.define('extension', k, copy); + } + return this.source[params.prefix] = m; + } + construct: ! |- + function (arg, params, children, ctx) { + return this.compile(this.source[params.prefix], this.source); + } + argument: module + input: + anyxml: 0..n + choice: 0..n + container: 0..n + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + typedef: 0..n + uses: 0..n + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + instance: 0..n + instance-list: 0..n + origin: + anyxml: 0..n + choice: 0..n + container: 0..n + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + typedef: 0..n + uses: 0..n + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + leaf: + config: 0..1 + default: 0..1 + description: 0..1 + if-feature: 0..n + mandatory: 0..1 + must: 0..n + reference: 0..1 + status: 0..1 + type: 0..1 + units: 0..1 + when: 0..1 + construct: ! |- + function (arg, params, children, ctx, self) { + var synth; + synth = this.require('data-synth'); + if (params.type['instance-identifier'] != null) { + return synth.BelongsTo(params, function() { + return this.set({ + model: children.type + }); + }); + } else { + return self.origin.construct.apply(this, arguments); + } + } + argument: name + origin: + config: 0..1 + default: 0..1 + description: 0..1 + if-feature: 0..n + mandatory: 0..1 + must: 0..n + reference: 0..1 + status: 0..1 + type: 0..1 + units: 0..1 + when: 0..1 + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return synth.Property(params, function() { + if (children.type != null) { + return this.set({ + type: children.type + }); + } + }); + } + argument: name + leaf-list: + config: 0..1 + description: 0..1 + if-feature: 0..n + max-elements: 0..1 + min-elements: 0..1 + must: 0..n + ordered-by: 0..1 + reference: 0..1 + status: 0..1 + type: 0..1 + units: 0..1 + when: 0..1 + construct: ! |- + function (arg, params, children, ctx, self) { + var synth; + synth = this.require('data-synth'); + if (params.type['instance-identifier'] != null) { + return synth.HasMany(params, function() { + return this.set({ + model: children.type + }); + }); + } else { + return self.origin.construct.apply(this, arguments); + } + } + argument: name + origin: + config: 0..1 + description: 0..1 + if-feature: 0..n + max-elements: 0..1 + min-elements: 0..1 + must: 0..n + ordered-by: 0..1 + reference: 0..1 + status: 0..1 + type: 0..1 + units: 0..1 + when: 0..1 + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return synth.List(params, function() { + if (children.type != null) { + return this.set({ + type: children.type + }); + } + }); + } + argument: name + list: + anyxml: 0..n + choice: 0..n + config: 0..1 + container: 0..n + description: 0..1 + grouping: 0..n + if-feature: 0..n + key: 0..1 + leaf: 0..n + leaf-list: 0..n + list: 0..n + max-elements: 0..1 + min-elements: 0..1 + must: 0..n + ordered-by: 0..1 + reference: 0..1 + status: 0..1 + typedef: 0..n + unique: 0..1 + uses: 0..n + when: 0..1 + construct: ! |- + function (arg, params, children) { + var item, synth; + synth = this.require('data-synth'); + item = (synth.Object(null)).bind(children); + return (synth.List(params)).set({ + type: item + }); + } + argument: name + mandatory: + preprocess: ! |- + function (arg, p, ctx) { + return ctx.mandatory = arg === true || arg === 'true'; + } + argument: value + max-elements: + preprocess: ! |- + function (arg, params, ctx) { + if (arg !== 'unbounded') { + return ctx['max-elements'] = Number(arg); + } + } + argument: value + min-elements: + preprocess: ! |- + function (arg, params, ctx) { + return ctx['min-elements'] = Number(arg); + } + argument: value + must: + description: 0..1 + error-app-tag: 0..1 + error-message: 0..1 + reference: 0..1 + argument: condition + notification: + anyxml: 0..n + choice: 0..n + container: 0..n + description: 0..1 + grouping: 0..n + if-feature: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + reference: 0..1 + status: 0..1 + typedef: 0..n + uses: 0..n + preprocess: ! |- + function (arg, params) { + return this.define('notification', arg, params); + } + argument: event + output: + anyxml: 0..n + choice: 0..n + container: 0..n + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + typedef: 0..n + uses: 0..n + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + instance: 0..n + instance-list: 0..n + origin: + anyxml: 0..n + choice: 0..n + container: 0..n + grouping: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + typedef: 0..n + uses: 0..n + construct: ! |- + function (arg, params, children) { + var synth; + synth = this.require('data-synth'); + return (synth.Object(params)).bind(children); + } + path: + preprocess: ! |- + function (arg, params, ctx) { + return ctx.path = arg.replace(/[_]/g, '.'); + } + argument: value + pattern: + construct: ! |- + function (arg, params, children, ctx) { + if (ctx.patterns == null) { + ctx.patterns = []; + } + return ctx.patterns.push(new RegExp(arg)); + } + argument: value + refine: + default: 0..1 + description: 0..1 + reference: 0..1 + config: 0..1 + mandatory: 0..1 + presence: 0..1 + must: 0..n + min-elements: 0..1 + max-elements: 0..1 + units: 0..1 + argument: target-node + require-instance: + preprocess: ! |- + function (arg, params, ctx) { + return ctx['require-instance'] = arg === true || arg === 'true'; + } + argument: value + revision: + description: 0..1 + reference: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + return this.define('revision', arg, params); + } + argument: date + rpc: + description: 0..1 + grouping: 0..n + if-feature: 0..n + input: 0..1 + output: 0..1 + reference: 0..1 + status: 0..1 + typedef: 0..n + construct: ! |- + function (arg, params, children) { + var func, method, ref, ref1, request, response, synth; + synth = this.require('data-synth'); + func = this.resolve('rpc', arg, false); + if (func == null) { + func = function(input, output, done) { + return done("No control logic found for '" + arg + "' rpc operation"); + }; + } + request = (ref = children.input) != null ? ref : synth.Meta; + response = (ref1 = children.output) != null ? ref1 : synth.Meta; + method = function(data, resolve, reject) { + var e, error, input, output; + if (typeof console.debug === "function") { + console.debug("executing rpc " + arg + "..."); + } + try { + input = new request(data, this); + output = new response(null, this); + } catch (error) { + e = error; + return reject(e); + } + return func.call(this, input, output, function(e) { + if (e == null) { + return resolve(output); + } else { + return reject(e); + } + }); + }; + method.params = params; + method.input = request; + method.output = response; + return method; + } + argument: name + submodule: + argument: name + anyxml: 0..n + augment: 0..n + belongs-to: 0..1 + choice: 0..n + contact: 0..1 + container: 0..n + description: 0..1 + deviation: 0..n + extension: 0..n + feature: 0..n + grouping: 0..n + identity: 0..n + import: 0..n + include: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + notification: 0..n + organization: 0..1 + reference: 0..1 + revision: 0..n + rpc: 0..n + typedef: 0..n + uses: 0..n + yang-version: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var k, v; + for (k in params) { + v = params[k]; + ctx[k] = v; + } + return delete ctx.submodule; + } + complex-type: 0..n + instance: 0..n + instance-list: 0..n + origin: + argument: name + anyxml: 0..n + augment: 0..n + belongs-to: 0..1 + choice: 0..n + contact: 0..1 + container: 0..n + description: 0..1 + deviation: 0..n + extension: 0..n + feature: 0..n + grouping: 0..n + identity: 0..n + import: 0..n + include: 0..n + leaf: 0..n + leaf-list: 0..n + list: 0..n + notification: 0..n + organization: 0..1 + reference: 0..1 + revision: 0..n + rpc: 0..n + typedef: 0..n + uses: 0..n + yang-version: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var k, v; + for (k in params) { + v = params[k]; + ctx[k] = v; + } + return delete ctx.submodule; + } + status: + preprocess: ! |- + function (arg, params, ctx) { + return ctx.status != null ? ctx.status : ctx.status = arg; + } + argument: value + type: + base: 0..1 + bit: 0..n + enum: 0..n + fraction-digits: 0..1 + length: 0..1 + path: 0..1 + pattern: 0..n + range: 0..1 + require-instance: 0..1 + type: 0..n + preprocess: ! |- + function (arg, params, ctx) { + return delete this.enumValue; + } + construct: ! |- + function (arg, params, children, ctx, self) { + if (children.ctype != null) { + ctx.type = children.ctype; + return null; + } else { + return self.origin.construct.apply(this, arguments); + } + } + argument: name + instance-type: 0..1 + origin: + base: 0..1 + bit: 0..n + enum: 0..n + fraction-digits: 0..1 + length: 0..1 + path: 0..1 + pattern: 0..n + range: 0..1 + require-instance: 0..1 + type: 0..n + preprocess: ! |- + function (arg, params, ctx) { + return delete this.enumValue; + } + construct: ! |- + function (arg, params, children, ctx) { + var key, mparams, ref, ref1, synth, typedef, value; + synth = this.require('data-synth'); + typedef = this.resolve('typedef', arg); + if (typedef == null) { + throw this.error("unable to resolve typedef for " + arg); + } + switch (false) { + case typedef.construct == null: + ctx.type = typedef.construct(params, this, arguments.callee); + break; + case typeof typedef.type !== 'object': + ref = typedef.type; + for (key in ref) { + value = ref[key]; + mparams = synth.copy({}, value); + synth.copy(mparams, params); + arguments.callee.call(this, key, mparams, children, ctx); + } + break; + case typeof typedef.type !== 'string': + arguments.callee.call(this, typedef.type, params, children, ctx); + } + if ((ref1 = ctx.type) != null) { + ref1.toString = function() { + return arg; + }; + } + return null; + } + argument: name + typedef: + default: 0..1 + description: 0..1 + units: 0..1 + type: 0..1 + reference: 0..1 + preprocess: ! |- + function (arg, params) { + return this.define('typedef', arg, params); + } + argument: name + uses: + augment: 0..n + description: 0..1 + if-feature: 0..n + refine: 0..n + reference: 0..1 + status: 0..1 + when: 0..1 + preprocess: ! |- + function (arg, params, ctx) { + var changes, grouping, k, match, ref, ref1, synth, target, v; + synth = this.require('data-synth'); + grouping = synth.copy({}, this.resolve('grouping', arg)); + delete grouping.description; + delete grouping.reference; + synth.copy(ctx, grouping); + ref = params.refine; + for (target in ref) { + changes = ref[target]; + match = this.locate(ctx, target); + if (match == null) { + continue; + } + for (k in changes) { + v = changes[k]; + match[k] = v; + } + } + ref1 = params.augment; + for (target in ref1) { + changes = ref1[target]; + match = this.locate(ctx, target); + if (match == null) { + continue; + } + synth.copy(match, changes); + } + if (typeof ctx.uses === 'object') { + return delete ctx.uses[arg]; + } else { + return delete ctx.uses; + } + } + argument: name + when: + description: 0..1 + reference: 0..1 + argument: condition + anyxml: {} + base: + argument: name + contact: + argument: + text: + yin-element: 'true' + default: + argument: value + description: + argument: + text: + yin-element: 'true' + error-app-tag: + argument: value + error-message: + argument: + value: + yin-element: 'true' + fraction-digits: + argument: value + key: + argument: value + length: + argument: value + namespace: + argument: uri + ordered-by: + argument: value + organization: + argument: + text: + yin-element: 'true' + position: + argument: value + presence: + argument: value + range: + argument: value + reference: + argument: + text: + yin-element: 'true' + revision-date: + argument: date + unique: + argument: tag + units: + argument: value + value: + argument: value + yang-version: + argument: value + yin-element: + argument: value +feature: ! '' +keywords: + - opnfv + - promise + - vim + - nfvi + - infrastructure + - openstack + - nbi + - yangforge + - resource + - reservation + - capacity + - allocation +rpc: + create-reservation: ! |- + function (input, output, done) { + var reservation, reservations; + reservation = this.create('ResourceReservation'); + reservations = this.access('promise.reservations'); + return reservation.invoke('update', input.get()).then(function(res) { + return res.save().then(function() { + reservations.push(res); + output.set({ + result: 'ok', + message: 'reservation request accepted' + }); + output.set('reservation-id', res.id); + return done(); + })["catch"](function(err) { + output.set({ + result: 'error', + message: err + }); + return done(); + }); + })["catch"](function(err) { + output.set({ + result: 'conflict', + message: err + }); + return done(); + }); + } + query-reservation: ! |- + function (input, output, done) { + var query; + query = input.get(); + query.capacity = 'reserved'; + return this.invoke('query-capacity', query).then(function(res) { + output.set('reservations', res.get('collections')); + output.set('utilization', res.get('utilization')); + return done(); + })["catch"](function(e) { + return done(e); + }); + } + update-reservation: ! |- + function (input, output, done) { + var reservation; + if ((input.get('reservation-id')) == null) { + output.set({ + result: 'error', + message: "must provide 'reservation-id' parameter" + }); + return done(); + } + reservation = this.find('ResourceReservation', input.get('reservation-id')); + if (reservation == null) { + output.set({ + result: 'error', + message: 'no reservation found for specified identifier' + }); + return done(); + } + return reservation.invoke('update', input.get()).then(function(res) { + return res.save().then(function() { + output.set({ + result: 'ok', + message: 'reservation update successful' + }); + return done(); + })["catch"](function(err) { + output.set({ + result: 'error', + message: err + }); + return done(); + }); + })["catch"](function(err) { + output.set({ + result: 'conflict', + message: err + }); + return done(); + }); + } + cancel-reservation: ! |- + function (input, output, done) { + var reservation; + reservation = this.find('ResourceReservation', input.get('reservation-id')); + if (reservation == null) { + output.set({ + result: 'error', + message: 'no reservation found for specified identifier' + }); + return done(); + } + return reservation.destroy().then((function(_this) { + return function() { + (_this.access('promise.reservations')).remove(reservation.id); + output.set('result', 'ok'); + output.set('message', 'reservation canceled'); + return done(); + }; + })(this))["catch"](function(e) { + output.set('result', 'error'); + output.set('message', e); + return done(); + }); + } + query-capacity: ! |- + function (input, output, done) { + var collections, deltas, entry, k, last, matches, metric, timestamp, usages, v, window; + window = input.get('window'); + metric = input.get('capacity'); + collections = (function() { + switch (metric) { + case 'total': + return ['ResourcePool']; + case 'reserved': + return ['ResourceReservation']; + case 'usage': + return ['ResourceAllocation']; + case 'available': + return ['ResourcePool', 'ResourceReservation', 'ResourceAllocation']; + } + })(); + matches = collections.reduce(((function(_this) { + return function(a, name) { + var res; + res = _this.find(name, { + start: function(value) { + return (window.end == null) || (new Date(value)) <= (new Date(window.end)); + }, + end: function(value) { + return (window.start == null) || (new Date(value)) >= (new Date(window.start)); + }, + enabled: true + }); + return a.concat.apply(a, res); + }; + })(this)), []); + if (window.scope === 'exclusive') { + matches = matches.where({ + start: function(value) { + return (window.start == null) || (new Date(value)) >= (new Date(window.start)); + }, + end: function(value) { + return (window.end == null) || (new Date(value)) <= (new Date(window.end)); + } + }); + } + matches = matches.without({ + id: input.get('without') + }); + if (metric === 'available') { + matches = matches.without({ + reservation: function(v) { + return v != null; + } + }); + } + output.set('collections', matches); + if ((input.get('show-utilization')) !== true) { + return done(); + } + deltas = matches.reduce((function(a, entry) { + var b, base, base1, ekey, k, ref1, ref2, skey, v; + b = entry.get(); + if (b.end == null) { + b.end = 'infiniteT'; + } + ref1 = [(b.start.split('T'))[0], (b.end.split('T'))[0]], skey = ref1[0], ekey = ref1[1]; + if (a[skey] == null) { + a[skey] = { + count: 0, + capacity: {} + }; + } + if (a[ekey] == null) { + a[ekey] = { + count: 0, + capacity: {} + }; + } + a[skey].count += 1; + a[ekey].count -= 1; + ref2 = b.capacity; + for (k in ref2) { + v = ref2[k]; + if (!(v != null)) { + continue; + } + if ((base = a[skey].capacity)[k] == null) { + base[k] = 0; + } + if ((base1 = a[ekey].capacity)[k] == null) { + base1[k] = 0; + } + if (entry.name === 'ResourcePool') { + a[skey].capacity[k] += v; + a[ekey].capacity[k] -= v; + } else { + a[skey].capacity[k] -= v; + a[ekey].capacity[k] += v; + } + } + return a; + }), {}); + last = { + count: 0, + capacity: {} + }; + usages = (function() { + var i, len, ref1, ref2, ref3, results; + ref1 = Object.keys(deltas).sort(); + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + timestamp = ref1[i]; + if (!(timestamp !== 'infinite')) { + continue; + } + entry = deltas[timestamp]; + entry.timestamp = (new Date(timestamp)).toJSON(); + entry.count += last.count; + ref2 = entry.capacity; + for (k in ref2) { + v = ref2[k]; + entry.capacity[k] += (ref3 = last.capacity[k]) != null ? ref3 : 0; + } + last = entry; + results.push(entry); + } + return results; + })(); + output.set('utilization', usages); + return done(); + } + increase-capacity: ! |- + function (input, output, done) { + var pool; + pool = this.create('ResourcePool', input.get()); + return pool.save().then((function(_this) { + return function(res) { + (_this.access('promise.pools')).push(res); + output.set({ + result: 'ok', + message: 'capacity increase successful' + }); + output.set('pool-id', res.id); + return done(); + }; + })(this))["catch"](function(e) { + output.set({ + result: 'error', + message: e + }); + return done(); + }); + } + decrease-capacity: ! |- + function (input, output, done) { + var k, pool, ref1, request, v; + request = input.get(); + ref1 = request.capacity; + for (k in ref1) { + v = ref1[k]; + request.capacity[k] = -v; + } + pool = this.create('ResourcePool', request); + return pool.save().then((function(_this) { + return function(res) { + (_this.access('promise.pools')).push(res); + output.set({ + result: 'ok', + message: 'capacity decrease successful' + }); + output.set('pool-id', res.id); + return done(); + }; + })(this))["catch"](function(e) { + output.set({ + result: 'error', + message: e + }); + return done(); + }); + } + create-instance: ! |- + function (input, output, done) { + var available, flavor, k, pid, provider, required, reservation, rid, v; + pid = input.get('provider-id'); + if (pid != null) { + provider = this.find('ResourceProvider', pid); + if (provider == null) { + output.set({ + result: 'error', + message: "no matching provider found for specified identifier: " + pid + }); + return done(); + } + } else { + provider = (this.find('ResourceProvider'))[0]; + if (provider == null) { + output.set({ + result: 'error', + message: "no available provider found for create-instance" + }); + return done(); + } + } + flavor = provider.access("services.compute.flavors." + (input.get('flavor'))); + if (flavor == null) { + output.set({ + result: 'error', + message: "no such flavor found for specified identifier: " + pid + }); + return done(); + } + required = { + instances: 1, + cores: flavor.get('vcpus'), + ram: flavor.get('ram'), + gigabytes: flavor.get('disk') + }; + rid = input.get('reservation-id'); + if (rid != null) { + reservation = this.find('ResourceReservation', rid); + if (reservation == null) { + output.set({ + result: 'error', + message: 'no valid reservation found for specified identifier' + }); + return done(); + } + if ((reservation.get('active')) !== true) { + output.set({ + result: 'error', + message: "reservation is currently not active" + }); + return done(); + } + available = reservation.get('remaining'); + } else { + available = this.get('promise.capacity.available'); + } + for (k in required) { + v = required[k]; + if ((v != null) && !!v) { + if (!(available[k] >= v)) { + output.set({ + result: 'conflict', + message: "required " + k + "=" + v + " exceeds available " + available[k] + }); + return done(); + } + } + } + return this.create('ResourceAllocation', { + reservation: rid, + capacity: required + }).save().then((function(_this) { + return function(instance) { + var request, url; + url = provider.get('services.compute.endpoint'); + request = _this.parent.require('superagent'); + request.post(url + "/servers").send({ + server: { + name: input.get('name'), + imageRef: input.get('image'), + flavorRef: input.get('flavor') + } + }).set('X-Auth-Token', provider.get('token')).set('Accept', 'application/json').end(function(err, res) { + if ((err != null) || !res.ok) { + instance.destroy(); + console.error(err); + return done(res.error); + } + instance.set('instance-ref', { + provider: provider, + server: res.body.server.id + }); + (_this.access('promise.allocations')).push(instance); + output.set({ + result: 'ok', + message: 'create-instance request accepted' + }); + output.set('instance-id', instance.id); + return done(); + }); + return instance; + }; + })(this))["catch"](function(err) { + output.set({ + result: 'error', + mesage: err + }); + return done(); + }); + } + destroy-instance: ! |- + function (input, output, done) { + var instance; + instance = this.find('ResourceAllocation', input.get('instance-id')); + if (instance == null) { + output.set({ + result: 'error', + message: 'no allocation found for specified identifier' + }); + return done(); + } + return instance.destroy().then((function(_this) { + return function() { + var provider, ref, request, url; + (_this.access('promise.allocations')).remove(instance.id); + ref = instance.get('instance-ref'); + provider = _this.access("promise.providers." + ref.provider); + url = provider.get('services.compute.endpoint'); + request = _this.parent.require('superagent'); + request["delete"](url + "/servers/" + ref.server).set('X-Auth-Token', provider.get('token')).set('Accept', 'application/json').end(function(err, res) { + if ((err != null) || !res.ok) { + console.error(err); + return done(res.error); + } + output.set('result', 'ok'); + output.set('message', 'instance destroyed and resource released back to pool'); + return done(); + }); + return instance; + }; + })(this))["catch"](function(e) { + output.set('result', 'error'); + output.set('message', e); + return done(); + }); + } + add-provider: ! "function (input, output, done) {\n var app, payload, providers, request, url;\n app = this.parent;\n request = app.require('superagent');\n payload = (function() {\n switch (input.get('provider-type')) {\n case 'openstack':\n return {\n auth: {\n tenantId: input.get('tenant.id'),\n tenantName: input.get('tenant.name'),\n passwordCredentials: input.get('username', 'password')\n }\n };\n }\n })();\n if (payload == null) {\n return done('Sorry, only openstack supported at this time');\n }\n url = input.get('endpoint');\n switch (input.get('strategy')) {\n case 'keystone':\n case 'oauth':\n if (!/\\/tokens$/.test(url)) {\n url += '/tokens';\n }\n }\n providers = this.access('promise.providers');\n return request.post(url).send(payload).set('Accept', 'application/json').end((function(_this) {\n return function(err, res) {\n var access, provider, ref1, ref2, ref3;\n if ((err != null) || !res.ok) {\n return done(res.error);\n }\n access = res.body.access;\n provider = _this.create('ResourceProvider', {\n token: access != null ? (ref1 = access.token) != null ? ref1.id : void 0 : void 0,\n name: access != null ? (ref2 = access.token) != null ? (ref3 = ref2.tenant) != null ? ref3.name : void 0 : void 0 : void 0\n });\n return provider.invoke('update', access.serviceCatalog).then(function(res) {\n return res.save().then(function() {\n providers.push(res);\n output.set('result', 'ok');\n output.set('provider-id', res.id);\n return done();\n })[\"catch\"](function(err) {\n output.set('error', {\n message: err\n });\n return done();\n });\n })[\"catch\"](function(err) {\n output.set('error', {\n message: err\n });\n return done();\n });\n };\n })(this));\n }" +typedef: ! '' +complex-type: + ResourceElement: + id: ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + ResourceCollection: + id: + - ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + start: + - ! |- + function (prev) { + return prev.set('default', function() { + return (new Date).toJSON(); + }); + } + active: + - ! |- + function (prev) { + return this.computed((function() { + var end, now, start; + now = new Date; + start = new Date(this.get('start')); + end = (function() { + switch (false) { + case (this.get('end')) == null: + return new Date(this.get('end')); + default: + return now; + } + }).call(this); + return (this.get('enabled')) && ((start <= now && now <= end)); + }), { + type: prev + }); + } + ResourceReservation: + id: + - ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + start: + - ! |- + function (prev) { + return prev.set('default', function() { + return (new Date).toJSON(); + }); + } + active: + - ! |- + function (prev) { + return this.computed((function() { + var end, now, start; + now = new Date; + start = new Date(this.get('start')); + end = (function() { + switch (false) { + case (this.get('end')) == null: + return new Date(this.get('end')); + default: + return now; + } + }).call(this); + return (this.get('enabled')) && ((start <= now && now <= end)); + }), { + type: prev + }); + } + end: + - ! |- + function (prev) { + return prev.set('default', function() { + var end, max; + end = new Date(this.get('start')); + max = this.parent.get('promise.policy.reservation.max-duration'); + if (max == null) { + return; + } + end.setTime(end.getTime() + (max * 60 * 60 * 1000)); + return end.toJSON(); + }); + } + allocations: + - ! |- + function (prev) { + return this.computed((function() { + var res; + res = this.store.find('ResourceAllocation', { + reservation: this.id + }); + return res.map(function(x) { + return x.get('id'); + }); + }), { + type: 'array' + }); + } + remaining: + - ! |- + function (prev) { + return this.computed((function() { + var entry, i, k, len, records, total, usage, v; + total = this.get('capacity'); + records = this.store.find('ResourceAllocation', { + id: this.get('allocations'), + active: true + }); + for (i = 0, len = records.length; i < len; i++) { + entry = records[i]; + usage = entry.get('capacity'); + for (k in usage) { + v = usage[k]; + total[k] -= v; + } + } + return total; + }), { + type: prev + }); + } + validate: + - ! |- + function (prev) { + return function(value, resolve, reject) { + var end, hasCapacity, k, now, ref, start, v; + if (value == null) { + value = {}; + } + ref = value.capacity; + for (k in ref) { + v = ref[k]; + if ((v != null) && !!v) { + hasCapacity = true; + } + } + if ((!hasCapacity) && value.elements.length === 0) { + return reject("unable to validate reservation record without anything being reserved"); + } + now = new Date; + if (value.start != null) { + start = new Date(value.start); + } + if (value.end != null) { + end = new Date(value.end); + } + if ((end != null) && end < now) { + return reject("requested end time " + value.end + " cannot be in the past"); + } + if ((start != null) && (end != null) && start > end) { + retun(reject("requested start time must be earlier than end time")); + } + return resolve(this); + }; + } + update: + - ! |- + function (prev) { + return function(req, resolve, reject) { + if (req.start == null) { + req.start = this.get('start'); + } + if (req.end == null) { + req.end = this.get('end'); + } + return this.parent.invoke('query-capacity', { + start: req.start, + end: req.end, + capacity: 'available', + without: this.id + }).then((function(_this) { + return function(res) { + var available, collections, end, entries, i, k, pools, ref, ref1, start, t1, t2, v, x; + collections = res.get('collections'); + if (!(collections.length > 0)) { + return reject('no resource capacity available during requested start/end time'); + } + pools = collections.filter(function(e) { + return /^ResourcePool/.test(e); + }); + entries = res.get('utilization'); + start = new Date(req.start); + end = new Date(req.end); + for (x = i = 0, ref = entries.length - 1; 0 <= ref ? i <= ref : i >= ref; x = 0 <= ref ? ++i : --i) { + t1 = new Date(entries[x].timestamp); + if (!(t1 < end)) { + break; + } + if (x < entries.length - 1) { + t2 = new Date(entries[x + 1].timestamp); + if (!(t2 > start)) { + continue; + } + } + available = entries[x].capacity; + ref1 = req.capacity; + for (k in ref1) { + v = ref1[k]; + if ((v != null) && !!v) { + if (!(available[k] >= v)) { + return reject("requested " + k + "=" + v + " exceeds available " + available[k] + " between " + t1 + " and " + t2); + } + } + } + } + _this.set(req); + _this.set('pools', pools); + return resolve(_this); + }; + })(this))["catch"](function(err) { + return reject(err); + }); + }; + } + save: + - ! |- + function (prev) { + return function(resolve, reject) { + return this.invoke('validate', this.get()).then(function(res) { + var now; + now = (new Date).toJSON(); + if ((res.get('created-on')) == null) { + res.set('created-on', now); + } + res.set('modified-on', now); + return resolve(res); + })["catch"](function(e) { + return reject(e); + }); + }; + } + ResourceAllocation: + id: + - ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + start: + - ! |- + function (prev) { + return prev.set('default', function() { + return (new Date).toJSON(); + }); + } + active: + - ! |- + function (prev) { + return this.computed((function() { + var end, now, start; + now = new Date; + start = new Date(this.get('start')); + end = (function() { + switch (false) { + case (this.get('end')) == null: + return new Date(this.get('end')); + default: + return now; + } + }).call(this); + return (this.get('enabled')) && ((start <= now && now <= end)); + }), { + type: prev + }); + } + priority: + - ! |- + function (prev) { + return this.computed((function() { + switch (false) { + case !((this.get('reservation')) == null): + return 3; + case !!(this.get('active')): + return 2; + default: + return 1; + } + }), { + type: prev + }); + } + ResourcePool: + id: + - ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + start: + - ! |- + function (prev) { + return prev.set('default', function() { + return (new Date).toJSON(); + }); + } + active: + - ! |- + function (prev) { + return this.computed((function() { + var end, now, start; + now = new Date; + start = new Date(this.get('start')); + end = (function() { + switch (false) { + case (this.get('end')) == null: + return new Date(this.get('end')); + default: + return now; + } + }).call(this); + return (this.get('enabled')) && ((start <= now && now <= end)); + }), { + type: prev + }); + } + save: + - ! |- + function (prev) { + return function(resolve, reject) { + var hasCapacity, k, ref, v, value; + value = this.get(); + ref = value.capacity; + for (k in ref) { + v = ref[k]; + if ((v != null) && !!v) { + hasCapacity = true; + } + } + if ((!hasCapacity) && value.elements.length === 0) { + return reject("unable to save pool record without any capacity values"); + } + return resolve(this); + }; + } + ResourceProvider: + id: + - ! |- + function (prev) { + return prev.set('default', function() { + return this.uuid(); + }); + } + token: + - ! |- + function (prev) { + return prev.set('private', true); + } + pools: + - ! |- + function (prev) { + return this.computed((function() { + return (this.store.find('ResourcePool', { + source: this.get('name') + })).map(function(x) { + return x.get('id'); + }); + }), { + type: 'array' + }); + } + update: + - ! |- + function (prev) { + return function(services, resolve, reject) { + var request; + if (services == null) { + services = []; + } + if (!services.length) { + return reject("unable to update provider without list of services"); + } + request = this.store.parent.require('superagent'); + services.forEach((function(_this) { + return function(service) { + var url; + switch (service.type) { + case 'compute': + url = service.endpoints[0].publicURL; + _this.set('services.compute.endpoint', url); + request.get(url + "/limits").set('X-Auth-Token', _this.get('token')).set('Accept', 'application/json').end(function(err, res) { + var capacity, ref; + if ((err != null) || !res.ok) { + console.warn("request to discover capacity limits failed"); + return; + } + capacity = (ref = res.body.limits) != null ? ref.absolute : void 0; + return (_this.access('capacity')).set({ + cores: capacity.maxTotalCores, + ram: capacity.maxTotalRAMSize, + instances: capacity.maxTotalInstances, + addresses: capacity.maxTotalFloatingIps + }); + }); + return request.get(url + "/flavors/detail").set('X-Auth-Token', _this.get('token')).set('Accept', 'application/json').end(function(err, res) { + var er, error, flavors, ref; + if ((err != null) || !res.ok) { + console.warn("request to discover compute flavors failed"); + return; + } + flavors = res.body.flavors; + try { + flavors = flavors.map(function(x) { + return { + ResourceFlavor: x + }; + }); + return (ref = _this.access('services.compute.flavors')).push.apply(ref, flavors); + } catch (error) { + er = error; + return console.warn("failed to update flavors into the provider due to validation errors"); + } + }); + } + }; + })(this)); + return resolve(this); + }; + } + ResourceFlavor: ! '' +pkgdir: /home/plee/hack/opnfv-promise +module: + opnfv-promise: + promise.capacity.total: + - ! |- + function (prev) { + return this.computed((function() { + var combine; + combine = function(a, b) { + var k, ref, v; + ref = b.capacity; + for (k in ref) { + v = ref[k]; + if (!(v != null)) { + continue; + } + if (a[k] == null) { + a[k] = 0; + } + a[k] += v; + } + return a; + }; + return (this.parent.get('pools')).filter(function(entry) { + return entry.active === true; + }).reduce(combine, {}); + }), { + type: prev + }); + } + promise.capacity.reserved: + - ! |- + function (prev) { + return this.computed((function() { + var combine; + combine = function(a, b) { + var k, ref, v; + ref = b.remaining; + for (k in ref) { + v = ref[k]; + if (!(v != null)) { + continue; + } + if (a[k] == null) { + a[k] = 0; + } + a[k] += v; + } + return a; + }; + return (this.parent.get('reservations')).filter(function(entry) { + return entry.active === true; + }).reduce(combine, {}); + }), { + type: prev + }); + } + promise.capacity.usage: + - ! |- + function (prev) { + return this.computed((function() { + var combine; + combine = function(a, b) { + var k, ref, v; + ref = b.capacity; + for (k in ref) { + v = ref[k]; + if (!(v != null)) { + continue; + } + if (a[k] == null) { + a[k] = 0; + } + a[k] += v; + } + return a; + }; + return (this.parent.get('allocations')).filter(function(entry) { + return entry.active === true; + }).reduce(combine, {}); + }), { + type: prev + }); + } + promise.capacity.available: + - ! |- + function (prev) { + return this.computed((function() { + var k, reserved, total, usage, v; + total = this.get('total'); + reserved = this.get('reserved'); + usage = this.get('usage'); + for (k in total) { + v = total[k]; + if (!(v != null)) { + continue; + } + if (reserved[k] != null) { + total[k] -= reserved[k]; + } + if (usage[k] != null) { + total[k] -= usage[k]; + } + } + return total; + }), { + type: prev + }); + } +config: ! '' diff --git a/deprecated/source/openstack.yaml b/deprecated/source/openstack.yaml new file mode 100644 index 0000000..16eb447 --- /dev/null +++ b/deprecated/source/openstack.yaml @@ -0,0 +1,22 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# + +name: openstack +description: OpenStack Management Module (WIP) +author: Peter K. Lee +license: Apache-2.0 +yangforge: "0.11.x" + +schema: !yang schema/openstack.yang + +dependencies: + access-control-models: !yang schema/access-control-models.yang + nfv-infrastructure: !yang schema/nfv-infrastructure.yang + +rpc: !require spec/openstack-intents.coffee diff --git a/deprecated/source/package.json b/deprecated/source/package.json new file mode 100644 index 0000000..59d489a --- /dev/null +++ b/deprecated/source/package.json @@ -0,0 +1,41 @@ +{ + "name": "@opnfv/promise", + "version": "1.0.0", + "description": "Resource Management for Virtualized Infrastructure", + "author": "Peter K. Lee ", + "license": "Apache-2.0", + "private": true, + "homepage": "http://wiki.opnfv.org/promise", + "repository": "opnfv/promise", + "keywords": [ + "opnfv", + "promise", + "vim", + "nfvi", + "infrastructure", + "openstack", + "nbi", + "yangforge", + "resource", + "reservation", + "capacity", + "allocation" + ], + "engines": { + "yangforge": ">=0.11.0" + }, + "devDependencies": { + "config": "^1.19.0", + "js-yaml": "^3.5.2", + "mocha": "~2.0.1", + "promise": "^7.1.1", + "should": "~3.1.3", + "yangforge": "^0.11.0" + }, + "main": "./lib/index.js", + "scripts": { + "prepublish": "yfc build -o index.yaml promise.yaml", + "test": "mocha", + "start": "yfc run --express 5050 promise.yaml" + } +} diff --git a/deprecated/source/promise.yaml b/deprecated/source/promise.yaml new file mode 100644 index 0000000..98dcdc4 --- /dev/null +++ b/deprecated/source/promise.yaml @@ -0,0 +1,299 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# + +name: opnfv-promise +description: Resource Management for Virtualized Infrastructure +author: Peter K. Lee +license: Apache-2.0 +homepage: http://wiki.opnfv.org/promise +repository: git://github.com/opnfv/promise.git +yangforge: "0.11.x" +keywords: + - opnfv + - promise + - vim + - nfvi + - infrastructure + - openstack + - nbi + - yangforge + - resource + - reservation + - capacity + - allocation + +schema: !yang schema/opnfv-promise.yang + +# below config provides default parameters +# NOTE: uncomment locally for testing with pre-existing data +#config: !json config/demo.json + +dependencies: + access-control-models: !yang schema/access-control-models.yang + nfv-infrastructure: !yang schema/nfv-infrastructure.yang + +# MODULE model active bindings +module: + opnfv-promise: + # rebind to be a computed property + promise.capacity.total: !coffee/function | + (prev) -> @computed (-> + combine = (a, b) -> + for k, v of b.capacity when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'pools') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + # rebind to be a computed property + promise.capacity.reserved: !coffee/function | + (prev) -> @computed (-> + combine = (a, b) -> + for k, v of b.remaining when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'reservations') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + # rebind to be a computed property + promise.capacity.usage: !coffee/function | + (prev) -> @computed (-> + combine = (a, b) -> + for k, v of b.capacity when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'allocations') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + # rebind to be a computed property + promise.capacity.available: !coffee/function | + (prev) -> @computed (-> + total = @get 'total' + reserved = @get 'reserved' + usage = @get 'usage' + for k, v of total when v? + total[k] -= reserved[k] if reserved[k]? + total[k] -= usage[k] if usage[k]? + total + ), type: prev + +# RPC definitions (INTENT interfaces) +rpc: !require spec/promise-intents.coffee + +# COMPLEX-TYPE model active bindings (controller logic) +complex-type: + ResourceElement: + #properties + id: !coffee/function | + (prev) -> prev.set 'default', -> @uuid() + + ResourceCollection: + # properties + start: !coffee/function | + (prev) -> prev.set 'default', -> (new Date).toJSON() + + active: !coffee/function | + (prev) -> @computed (-> + now = new Date + start = new Date (@get 'start') + end = switch + when (@get 'end')? then new Date (@get 'end') + else now + (@get 'enabled') and (start <= now <= end) + ), type: prev + + ResourceReservation: + end: !coffee/function | + (prev) -> prev.set 'default', -> + end = (new Date @get 'start') + max = @parent.get 'promise.policy.reservation.max-duration' + return unless max? + end.setTime (end.getTime() + (max*60*60*1000)) + end.toJSON() + + allocations: !coffee/function | + (prev) -> @computed (-> + res = (@store.find 'ResourceAllocation', reservation: @id) + res.map (x) -> x.get 'id' + ), type: 'array' + + remaining: !coffee/function | + (prev) -> @computed (-> + total = @get 'capacity' + records = @store.find 'ResourceAllocation', id: (@get 'allocations'), active: true + for entry in records + usage = entry.get 'capacity' + for k, v of usage + total[k] -= v + total + ), type: prev + + # methods + validate: !coffee/function | + (prev) -> (value={}, resolve, reject) -> + # validate that request contains sufficient data + for k, v of value.capacity when v? and !!v + hasCapacity = true + if (not hasCapacity) and value.elements.length is 0 + return reject "unable to validate reservation record without anything being reserved" + # time range verifications + now = new Date + start = (new Date value.start) if value.start? + end = (new Date value.end) if value.end? + # if start? and start < now + # return reject "requested start time #{value.start} cannot be in the past" + if end? and end < now + return reject "requested end time #{value.end} cannot be in the past" + if start? and end? and start > end + retun reject "requested start time must be earlier than end time" + resolve this + + update: !coffee/function | + (prev) -> (req, resolve, reject) -> + req.start ?= @get 'start' + req.end ?= @get 'end' + + # TODO: should validate here... + @parent.invoke 'query-capacity', + start: req.start + end: req.end + capacity: 'available' + without: @id + .then (res) => + collections = res.get 'collections' + unless collections.length > 0 + return reject 'no resource capacity available during requested start/end time' + + pools = collections.filter (e) -> /^ResourcePool/.test e + # should do some policy or check to see if more than one pool acceptable to reservee + + entries = res.get 'utilization' + start = new Date req.start + end = new Date req.end + + for x in [0..entries.length-1] + t1 = new Date entries[x].timestamp + break unless t1 < end + + if x < entries.length-1 + t2 = new Date entries[x+1].timestamp + continue unless t2 > start + + available = entries[x].capacity + for k, v of req.capacity when v? and !!v + unless available[k] >= v + return reject "requested #{k}=#{v} exceeds available #{available[k]} between #{t1} and #{t2}" + + @set req + @set 'pools', pools + resolve this + .catch (err) -> reject err + + save: !coffee/function | + (prev) -> (resolve, reject) -> + @invoke 'validate', @get() + .then (res) -> + # should do something about this reservation record... + now = (new Date).toJSON() + unless (res.get 'created-on')? + res.set 'created-on', now + res.set 'modified-on', now + resolve res + .catch (e) -> reject e + + ResourceAllocation: + # properties + priority: !coffee/function | + (prev) -> @computed (-> + switch + when not (@get 'reservation')? then 3 + when not (@get 'active') then 2 + else 1 + ), type: prev + + ResourcePool: + save: !coffee/function | + (prev) -> (resolve, reject) -> + # validate that record contains sufficient data + value = @get() + + for k, v of value.capacity when v? and !!v + hasCapacity = true + if (not hasCapacity) and value.elements.length is 0 + return reject "unable to save pool record without any capacity values" + + resolve this + + ResourceProvider: + # properties + token: !coffee/function | + (prev) -> prev.set 'private', true + + pools: !coffee/function | + (prev) -> @computed (-> + (@store.find 'ResourcePool', source: (@get 'name')).map (x) -> x.get 'id' + ), type: 'array' + + # methods + # XXX - this method is OpenStack-specific only, will need to revise later + update: !coffee/function | + (prev) -> (services=[], resolve, reject) -> + return reject "unable to update provider without list of services" unless services.length + request = @store.parent.require 'superagent' + services.forEach (service) => + switch service.type + when 'compute' + url = service.endpoints[0].url + @set 'services.compute.endpoint', url + request + .get "#{url}/limits" + .set 'X-Auth-Token', @get 'token' + .set 'Accept', 'application/json' + .end (err, res) => + if err? or !res.ok + console.warn "request to discover capacity limits failed" + return + + capacity = res.body.limits?.absolute + #console.log "\ndiscovered capacity:" + #console.log capacity + + (@access 'capacity').set { + cores: capacity.maxTotalCores + ram: capacity.maxTotalRAMSize + instances: capacity.maxTotalInstances + addresses: capacity.maxTotalFloatingIps + } + request + .get "#{url}/flavors/detail" + .set 'X-Auth-Token', @get 'token' + .set 'Accept', 'application/json' + .end (err, res) => + if err? or !res.ok + console.warn "request to discover compute flavors failed" + return + + flavors = res.body.flavors + # console.log "\ndiscovered flavors:" + # console.log flavors + try + flavors = flavors.map (x) -> ResourceFlavor: x + (@access 'services.compute.flavors').push flavors... + catch er + console.warn "failed to update flavors into the provider due to validation errors" + + # XXX - update should do promise.all + resolve this + diff --git a/deprecated/source/schema/access-control-models.yang b/deprecated/source/schema/access-control-models.yang new file mode 100644 index 0000000..7b4684c --- /dev/null +++ b/deprecated/source/schema/access-control-models.yang @@ -0,0 +1,92 @@ +module access-control-models { + prefix acm; + namespace "urn:opnfv:promise:acm"; + + import complex-types { prefix ct; } + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + typedef password { + type string { + length 1..255; + } + } + + grouping access-credentials { + leaf strategy { + type enumeration { + enum oauth; + enum keystone; + } + default oauth; + } + leaf endpoint { + type inet:uri; + description "The target endpoint for authentication"; + mandatory true; + } + leaf username { + type string; + mandatory true; + } + leaf password { + type acm:password; + mandatory true; + } + } + + /********************************************* + * Identity Models + *********************************************/ + + ct:complex-type Identity { + ct:abstract true; + description "Identity represents an administrative access model entity"; + + key "id"; + leaf id { type yang:uuid; mandatory true; } + leaf name { type string; mandatory true; } + leaf description { type string; } + leaf enabled { type boolean; default true; } + } + + ct:complex-type User { + ct:extends Identity; + + leaf credential { + //type instance-identifier { ct:instance-type IdentityCredential; } + type string; + mandatory true; + } + + container contact { + leaf fullName { type string; } + leaf email { type string; } + } + + leaf-list groups { type instance-identifer { ct:instance-type Group; } } + leaf domain { type instance-identifier { ct:instance-type Domain; } } + } + + ct:complex-type Group { + ct:extends Identity; + + leaf-list users { type instance-identifier { ct:instance-type User; } } + leaf domain { type instance-identifier { ct:instance-type Domain; } } + } + + ct:complex-type Domain { + ct:extends Identity; + description + "Domain represent a distinct administrative domain across + collection of users and groups."; + + ct:instance-list users { ct:instance-type User; } + ct:instance-list groups { ct:instance-type Group; } + } + + rpc create-user; + rpc remove-user; + rpc create-group; + rpc remove-group; +} diff --git a/deprecated/source/schema/nfv-infrastructure.yang b/deprecated/source/schema/nfv-infrastructure.yang new file mode 100644 index 0000000..ccad269 --- /dev/null +++ b/deprecated/source/schema/nfv-infrastructure.yang @@ -0,0 +1,322 @@ +module nfv-infrastructure { + namespace "urn:opnfv:promise:nfv:infrastructure"; + prefix nfvi; + + import access-control-models { prefix acm; } + import ietf-inet-types { prefix inet; } + import ietf-yang-types { prefix yang; } + import complex-types { prefix ct; } + + description + "NFV Infrastructure Data Models with complex types and typed instance + identifiers representing the various ResourceElements available + in the infrastructure across compute, network, and storage."; + + revision 2015-10-13 { + description + "Introduce capacity and element collection into NFVI models"; + } + + revision 2015-08-07 { + description + "This YANG module is modeled using 'yangforge' which natively provides + complex types and typed instance identifiers. This module + provides various collections of resource management data models + for instance based management"; + } + + identity manager { + description "used by specific modules implementing manager role for NFVI"; + } + + grouping compute-capacity { + leaf cores { type int16; default 0; } + leaf ram { type int32; default 0; units 'MB'; } + leaf instances { type int16; default 0; } + } + + grouping network-capacity { + leaf networks { type int16; default 0; } + leaf ports { type int16; default 0; } + leaf routers { type int16; default 0; } + leaf subnets { type int16; default 0; } + leaf addresses { type int32; default 0; } + } + + grouping storage-capacity { + leaf gigabytes { type int32; default 0; units 'GB'; } + leaf snapshots { type int16; default 0; } + leaf volumes { type int16; default 0; } + } + + grouping resource-capacity { + uses compute-capacity; + uses network-capacity; + uses storage-capacity; + } + + grouping resource-collection { + description + "Information model capturing parameters for describing a collection of + resource capacity and resource elements"; + + container capacity { uses resource-capacity; } + leaf-list elements { + type instance-identifier { + ct:instance-type nfvi:ResourceElement; + require-instance true; + } + } + } + + grouping resource-stack { + description + "Information model describing a NFVI resource stack comprising of + various resource elements across compute, network, and storage"; + + ct:instance-list hosts { ct:instance-type nfvi:PhysicalHost; } + ct:instance-list hypervisors { ct:instance-type nfvi:Hypervisor; } + + container compute { + description "Contains compute related resources"; + + ct:instance-list servers { ct:instance-type nfvi:ServerInstance; } + ct:instance-list images { ct:instance-type nfvi:VirtualMachineImage; } + ct:instance-list flavors { ct:instance-type nfvi:ComputeFlavor; } + } + + container network { + description "Contains networking related resources"; + + ct:instance-list networks { ct:instance-type nfvi:Network; } + ct:instance-list subnets { ct:instance-type nfvi:SubNetwork; } + ct:instance-list ports { ct:instance-type nfvi:SwitchPort; } + //ct:instance-list routers { ct:instance-type Router; } + } + } + + /********************************************* + * Abstract Models (top-level) + *********************************************/ + + ct:complex-type ResourceElement { + ct:abstract true; + + key "id"; + leaf id { type yang:uuid; mandatory true; } + leaf name { type string; } + leaf enabled { type boolean; default true; } + leaf protected { type boolean; default false; } + leaf owner { type instance-identifier { ct:instance-type acm:Identity; } } + leaf visibility { + description "Specify visibility level available from the perspective of 'owner'"; + type enumeration { + enum public; + enum domain; + enum project; + enum group; + enum user; + } + default user; + } + leaf-list tags { type string; } + + leaf-list members { + description "Optionally share with explicit list of members of AccessIdentity complex-type"; + type instance-identifier { + ct:instance-type acm:Identity; + } + } + } + + ct:complex-type ResourceInstance { + ct:extends ResourceElement; + ct:abstract true; + + leaf status { + type enumeration { + enum active; + enum inactive; + enum pending; + } + } + leaf progress { + type uint8 { range 0..100; } + default 0; + } + } + + ct:complex-type ResourceContainer { + ct:extends ResourceInstance; + ct:abstract true; + + description + "An abstract resource instance which contains a collection of capacity + and elements."; + + uses resource-collection; + } + + /********************************************* + * Compute Models + *********************************************/ + + ct:complex-type AvailabilityZone { + ct:extends ResourceElement; + } + + ct:complex-type PhysicalHost { + ct:extends ResourceElement; + + leaf type { type string; } + leaf version { type string; } + + leaf cpu { type uint8; } + leaf workload { type uint8; default 0; } + leaf uptime { type string; } + + container ram { + leaf total { type uint32; units 'MB'; } + leaf used { type uint32; units 'MB'; } + leaf free { type uint32; units 'MB'; } + } + container disk { + leaf total { type uint32; units 'GB'; } + leaf used { type uint32; units 'GB'; } + leaf free { type uint32; units 'GB'; } + } + + leaf-list hypervisors { type instance-identifier { ct:instance-type Hypervisor; } } + } + + ct:complex-type Hypervisor { + ct:extends PhysicalHost; + + leaf host { + type instance-identifier { ct:instance-type PhysicalHost; } + mandatory true; + } + container vcpu { + leaf total { type uint16; } + leaf used { type uint16; } + leaf free { type uint16; } + } + leaf-list servers { type instance-identifier { ct:instance-type ServerInstance; } } + } + + ct:complex-type ComputeElement { + ct:extends ResourceElement; + ct:abstract true; + + container constraint { + leaf disk { type uint32; units 'GB'; default 0; } + leaf ram { type uint32; units 'MB'; default 0; } + leaf vcpu { type uint16; default 0; } + } + + leaf-list instances { + description "State info about instances currently using this resource element"; + type instance-identifier { + ct:instance-type ResourceInstance; + } + config false; + } + } + + ct:complex-type VirtualMachineImage { + ct:extends ComputeElement; + + container data { + leaf checksum { type string; mandatory true; } + leaf size { type uint32; units 'Bytes'; mandatory true; } + + container format { + leaf container { + type enumeration { enum ami; enum ari; enum aki; enum bare; enum ovf; } + default bare; + } + leaf disk { + type enumeration { enum ami; enum ari; enum aki; enum vhd; enum vmdk; enum raw; enum qcow2; enum vdi; enum iso; } + } + } + leaf content { + description "should be a 'private' property so only direct access retrieves content"; + type binary; + } + } + } + + ct:complex-type ComputeFlavor { + ct:extends ResourceElement; + + leaf disk { type uint32; units 'GB'; default 0; } + leaf ram { type uint32; units 'MB'; default 0; } + leaf vcpus { type uint16; default 0; } + } + + ct:complex-type ServerInstance { + ct:extends ResourceInstance; + + leaf flavor { + type instance-identifier { ct:instance-type ComputeFlavor; } + mandatory true; + } + leaf image { + type instance-identifier { ct:instance-type VirtualMachineImage; } + mandatory true; + } + + //ct:instance metadata { ct:instance-type MetaData; } + + leaf host { + type instance-identifier { ct:instance-type PhysicalHost; } + } + + leaf-list connections { + description + "References to collection of NetworkingElement class objects such as + Network, Subnet, Port, Router that this ServerInstance is + connected with."; + type instance-identifier { ct:instance-type NetworkElement; } + } + } + + /********************************************* + * Network Models (Work-in-Progress) + *********************************************/ + + ct:complex-type NetworkElement { + ct:extends ResourceElement; + ct:abstract true; + } + + ct:complex-type Network { + ct:extends NetworkElement; + + leaf-list subnets { + type instance-identifier { ct:instance-type SubNetwork; } + } + } + + ct:complex-type SubNetwork { + ct:extends NetworkElement; + + leaf network { type instance-identifier { ct:instance-type Network; } } + + leaf-list nameservers { type string; } + + container dhcp { + leaf enabled { type boolean; } + list pools { + leaf start { type inet:ip-address; } + leaf end { type inet:ip-address; } + } + } + } + + ct:complex-type SwitchPort { + ct:extends NetworkElement; + + leaf subnet { type instance-identifier { ct:instance-type SubNetwork; } } + } +} diff --git a/deprecated/source/schema/nfv-mano.yang b/deprecated/source/schema/nfv-mano.yang new file mode 100644 index 0000000..0e3bbbe --- /dev/null +++ b/deprecated/source/schema/nfv-mano.yang @@ -0,0 +1,149 @@ +module nfv-mano { + namespace "urn:opnfv:promise:nfv:mano"; + prefix mano; + + import access-control-models { prefix acm; } + import nfv-infrastructure { prefix nfvi; } + import complex-types { prefix ct; } + import ietf-inet-types { prefix inet; } + import iana-crypt-hash { prefix ianach; } + + description + "NFV Management and Orchestration Data Models with complex types and typed + instance identifiers representing the NFVO, VNFM, and the VIM."; + + revision 2015-09-03 { + description + "This YANG module is modeled using 'yangforge' which natively provides + complex types and typed instance identifiers. This module + provides various collections of infrastructure management data + models for instance based management"; + } + + grouping provider-credentials { + leaf endpoint { + type inet:uri; + description "The target URL endpoint for the resource provider"; + mandatory true; + } + leaf username { + type string; + mandatory true; + } + leaf password { + type acm:password; + mandatory true; + } + leaf region { + type string; + description "Optional specified region for the provider"; + } + } + + ct:complex-type ServiceOrchestrator { + ct:extends acm:Domain; + ct:abstract true; + // TBD + } + + ct:complex-type ResourceOrchestrator { + ct:extends acm:Domain; + ct:abstract true; + // TBD + } + + ct:complex-type VirtualNetworkFunctionManager { + ct:extends acm:Domain; + ct:abstract true; + // TBD + } + + ct:complex-type VirtualInfrastructureManager { + ct:extends acm:Domain; + ct:abstract true; + + leaf name { type string; mandatory true; } + + container auth { + description 'Conceptual container that will be extended by explicit provider'; + // ct:instance-list credentials { ct:instance-type AccessCredential; } + // ct:instance-list roles { ct:instance-type AccessRole; } + // ct:instance-list policies { ct:instance-type AccessPolicy; } + } + + ct:instance-list hosts { ct:instance-type nfvi:PhysicalHost; } + ct:instance-list hypervisors { ct:instance-type nfvi:Hypervisor; } + + container compute { + if-feature has-compute; + description "Contains compute related resources"; + + ct:instance-list servers { ct:instance-type nfvi:ServerInstance; } + ct:instance-list images { ct:instance-type nfvi:VirtualMachineImage; } + ct:instance-list flavors { ct:instance-type nfvi:ComputeFlavor; } + } + + container network { + if-feature has-networking; + description "Contains networking related resources"; + + ct:instance-list networks { ct:instance-type nfvi:Network; } + ct:instance-list subnets { ct:instance-type nfvi:SubNetwork; } + ct:instance-list ports { ct:instance-type nfvi:SwitchPort; } + //ct:instance-list routers { ct:instance-type Router; } + } + } + + container stack { + container nfvo { + ct:instance service { ct:instance-type ServiceOrchestrator; } + ct:instance resource { ct:instance-type ResourceOrchestrator; } + } + container vnfm { + ct:instance-list managers { ct:instance-type VirtualNetworkFunctionManager; } + } + container vim { + ct:instance-list managers { ct:instance-type VirtualInfrastructureManager; } + } + } + + rpc add-vim { + description "This operation allows you to add a new VirtualInfrastructureManager into the NFVI stack"; + input { + uses provider-credentials; + + leaf provider { + description "Select a specific resource provider"; + mandatory true; + type enumeration { + enum openstack; + enum hp; + enum rackspace; + enum amazon { + status planned; + } + enum joyent { + status planned; + } + enum azure { + status planned; + } + } + } + } + output { + leaf id { + description "Unique identifier for the newly added provider found in /promise/providers"; + type instance-identifier { + ct:instance-type VirtualInfrastructureManager; + } + } + leaf result { + type enumeration { + enum success; + enum error; + } + } + } + } +} diff --git a/deprecated/source/schema/openstack-compute.yang b/deprecated/source/schema/openstack-compute.yang new file mode 100644 index 0000000..c3e790c --- /dev/null +++ b/deprecated/source/schema/openstack-compute.yang @@ -0,0 +1,72 @@ +module openstack-compute { + prefix os-com; + + import nfv-infrastructure { prefix nfvi; } + import complex-types { prefix ct; } + + identity nova { base nvfi:compute; } + + feature availability-zone { + description "Specifies whether availability zone functionality is available."; + } + feature extended-status { + description "Specifies whether extended status functionality is available."; + } + feature security-groups { + description "Specifies whether security groups functionality is available."; + } + + ct:complex-type ServerInstance { + ct:extends nfvi:ServerInstance; + + leaf zone { + if-feature availability-zone; + type string; + } + + leaf project { + type instance-identifier { ct:instance-type nfvi:ResourceProject; } + mandatory true; + } + + container extended-status { + if-feature extended-status; + leaf locked-by; + leaf power; + leaf task; + leaf vm; + } + + leaf-list security-groups { + if-feature security-groups; + type instance-identifier { ct:instance-type SecurityGroup; } + } + + } + + choice version { + case v2.1 { + ct:instance-list servers { ct:instance-type ServerInstance; } + } + } + + // OpenStack Nova specific RPC calls + rpc resize { + input { + leaf server { type instance-type { ct:instance-type ServerInstance; } } + // other params for resize + } + } + rpc backup; + rpc migrate; + rpc restore; + rpc evacuate; + rpc lock; + rpc unlock; + rpc suspend; + rpc resume; + rpc pause; + rpc unpause; + rpc inject-network; + rpc reset-network; +} diff --git a/deprecated/source/schema/openstack-identity.yang b/deprecated/source/schema/openstack-identity.yang new file mode 100644 index 0000000..4b92957 --- /dev/null +++ b/deprecated/source/schema/openstack-identity.yang @@ -0,0 +1,84 @@ +module openstack-identity { + namespace "urn:opnfv:promise:openstack:identity"; + prefix os-id; + + import access-control-models { prefix acm; } + import nfv-infrastructure { prefix nfvi; } + import complex-types { prefix ct; } + import ietf-yang-types { prefix yang; } + + description + "OpenStack Identity Data Models with complex types and typed instance + identifiers represent the various Access Control Models available + within OpenStack."; + + revision 2015-09-03 { + description + "This YANG module is modeled using 'yangforge' which natively provides + complex types and typed instance identifiers. This module + provides various collections of resource management data models + for instance based management"; + } + + /********************************************* + * OpenStack Identity Models + *********************************************/ + + ct:complex-type Project { + ct:extends acm:Group; + description + "OpenStack Project represent a distinct resource consumption space across + collection of users and groups that can reserve and allocate + resources."; + + leaf-list groups { type instance-identifer { ct:instance-type acm:Group; } } + + container resource { + leaf-list images { + if-feature vm-images; + type instance-identifier { ct:instance-type nfvi:VirtualMachineImage; } + } + + leaf-list flavors { + if-feature compute-flavors; + type instance-identifier { ct:instance-type nfvi:VirtualMachineFlavor; } + } + } + } + + ct:complex-type User { + ct:extends acm:User; + + description + "OpenStack User can also belong to multiple projects."; + + leaf-list projects { type instance-identifier { ct:instance-type Project; } } + } + + ct:complex-type Group { + ct:extends acm:Group; + + description + "OpenStack Group can also belong to multiple projects."; + + leaf-list projects { type instance-identifier { ct:instance-type Project; } } + } + + ct:complex-type Domain { + ct:extends acm:Domain; + + description + "OpenStack Domain represent a distinct administrative domain including projects."; + + ct:instance-list projects { ct:instance-type Project; } + } + + ct:complex-type Token { + leaf key { type yang:uuid; } + leaf identity { type instance-identifier { ct:instance-type Identity; } } + } + + + rpc create-project; + rpc remove-project; +} diff --git a/deprecated/source/schema/openstack.yang b/deprecated/source/schema/openstack.yang new file mode 100644 index 0000000..6878f7e --- /dev/null +++ b/deprecated/source/schema/openstack.yang @@ -0,0 +1,74 @@ +module openstack { + prefix os; + + import nfv-infrastructure { prefix nfvi; } + import access-control-models { prefix acm; } + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + import complex-types { prefix ct; } + + description + "OpenStack controller module"; + + revision 2016-01-19 { + description "Basic coverage of limited intents needed for Promise"; + } + + identity openstack { base nfvi:manager; } + identity release { base openstack; } + identity distro { base openstack; } + + feature os-system-admin { + description "OpenStack system administration capability"; + } + + grouping os-credentials { + uses acm:access-credentials { + refine strategy { + default keystone; + } + refine endpoint { + default "http://localhost:5000/v2.0"; + } + } + container tenant { + leaf id { type string; } + leaf name { type string; } + } + } + + // OpenStack infrastructure platform (PLACEHOLDER) + container platform { + uses nfvi:resource-stack; + + leaf release { type identityref { base release; } } + leaf distro { type identityref { base distro; } } + + //ct:instance-list services { ct:instance-type OpenStackService; } + //ct:instance-list endpoints { ct:instance-type ServiceEndpoint; } + } + + // OpenStack system administrator configuration tree + container admin { + if-feature os-system-admin; + container auth { + uses os-credentials; + leaf token { type yang:uuid; } + } + } + + rpc authenticate { + if-feature os-system-admin; + input { + uses os-credentials; + } + output { + leaf token { type yang:uuid; } + } + } + + rpc create-tenant { + if-feature os-system-admin; + + } +} diff --git a/deprecated/source/schema/opnfv-promise.yang b/deprecated/source/schema/opnfv-promise.yang new file mode 100644 index 0000000..9ee7564 --- /dev/null +++ b/deprecated/source/schema/opnfv-promise.yang @@ -0,0 +1,642 @@ +module opnfv-promise { + namespace "urn:opnfv:promise"; + prefix promise; + + import complex-types { prefix ct; } + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + import access-control-models { prefix acm; } + import nfv-infrastructure { prefix nfvi; } + + description + "OPNFV Promise Resource Reservation/Allocation controller module"; + + revision 2015-10-05 { + description "Complete coverage of reservation related intents"; + } + + revision 2015-08-06 { + description "Updated to incorporate YangForge framework"; + } + + revision 2015-04-16 { + description "Initial revision."; + } + + feature reservation-service { + description "When enabled, provides resource reservation service"; + } + + feature multi-provider { + description "When enabled, provides resource management across multiple providers"; + } + + typedef reference-identifier { + description "defines valid formats for external reference id"; + type union { + type yang:uuid; + type inet:uri; + type uint32; + } + } + + grouping resource-utilization { + container capacity { + container total { description 'Conceptual container that should be extended'; } + container reserved { description 'Conceptual container that should be extended'; config false; } + container usage { description 'Conceptual container that should be extended'; config false; } + container available { description 'Conceptual container that should be extended'; config false; } + } + } + + grouping temporal-resource-collection { + description + "Information model capturing resource-collection with start/end time window"; + + leaf start { type yang:date-and-time; } + leaf end { type yang:date-and-time; } + + uses nfvi:resource-collection; + } + + grouping resource-usage-request { + description + "Information model capturing available parameters to make a resource + usage request."; + reference "OPNFV-PROMISE, Section 3.4.1"; + + uses temporal-resource-collection { + refine elements { + description + "Reference to a list of 'pre-existing' resource elements that are + required for fulfillment of the resource-usage-request. + + It can contain any instance derived from ResourceElement, + such as ServerInstances or even other + ResourceReservations. If the resource-usage-request is + accepted, the ResourceElement(s) listed here will be placed + into 'protected' mode as to prevent accidental removal. + + If any of these resource elements become 'unavailable' due to + environmental or administrative activity, a notification will + be issued informing of the issue."; + } + } + + leaf zone { + description "Optional identifier to an Availability Zone"; + type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } + } + } + + grouping query-start-end-window { + container window { + description "Matches entries that are within the specified start/end time window"; + leaf start { type yang:date-and-time; } + leaf end { type yang:date-and-time; } + leaf scope { + type enumeration { + enum "exclusive" { + description "Matches entries that start AND end within the window"; + } + enum "inclusive" { + description "Matches entries that start OR end within the window"; + } + } + default "inclusive"; + } + } + } + + grouping query-resource-collection { + uses query-start-end-window { + description "Match for ResourceCollection(s) that are within the specified start/end time window"; + } + leaf-list without { + description "Excludes specified collection identifiers from the result"; + type instance-identifier { ct:instance-type ResourceCollection; } + } + leaf show-utilization { type boolean; default true; } + container elements { + leaf-list some { + description "Query for ResourceCollection(s) that contain some or more of these element(s)"; + type instance-identifier { ct:instance-type nfvi:ResourceElement; } + } + leaf-list every { + description "Query for ResourceCollection(s) that contain all of these element(s)"; + type instance-identifier { ct:instance-type nfvi:ResourceElement; } + } + } + } + + grouping common-intent-output { + leaf result { + type enumeration { + enum "ok"; + enum "conflict"; + enum "error"; + } + } + leaf message { type string; } + } + + grouping utilization-output { + list utilization { + key 'timestamp'; + leaf timestamp { type yang:date-and-time; } + leaf count { type int16; } + container capacity { uses nfvi:resource-capacity; } + } + } + + ct:complex-type ResourceCollection { + ct:extends nfvi:ResourceContainer; + ct:abstract true; + + description + "Describes an abstract ResourceCollection data model, which represents + a grouping of capacity and elements available during a given + window in time which must be extended by other resource + collection related models"; + + leaf start { type yang:date-and-time; } + leaf end { type yang:date-and-time; } + + leaf active { + config false; + description + "Provides current state of this record whether it is enabled and within + specified start/end time"; + type boolean; + } + } + + ct:complex-type ResourcePool { + ct:extends ResourceCollection; + + description + "Describes an instance of an active ResourcePool record, which + represents total available capacity and elements from a given + source."; + + leaf source { + type instance-identifier { + ct:instance-type nfvi:ResourceContainer; + require-instance true; + } + mandatory true; + } + + refine elements { + // following 'must' statement applies to each element + // NOTE: just a non-working example for now... + must "boolean(/source/elements/*[@id=id])" { + error-message "One or more of the ResourceElement(s) does not exist in the provider to be reserved"; + } + } + } + + ct:complex-type ResourceReservation { + ct:extends ResourceCollection; + + description + "Describes an instance of an accepted resource reservation request, + created usually as a result of 'create-reservation' request. + + A ResourceReservation is a derived instance of a generic + ResourceCollection which has additional parameters to map the + pool(s) that were referenced to accept this reservation as well + as to track allocations made referencing this reservation. + + Contains the capacities of various resource attributes being + reserved along with any resource elements that are needed to be + available at the time of allocation(s)."; + + reference "OPNFV-PROMISE, Section 3.4.1"; + + leaf created-on { type yang:date-and-time; config false; } + leaf modified-on { type yang:date-and-time; config false; } + + leaf-list pools { + config false; + description + "Provides list of one or more pools that were referenced for providing + the requested resources for this reservation. This is an + important parameter for informing how/where allocation + requests can be issued using this reservation since it is + likely that the total reserved resource capacity/elements are + made availble from multiple sources."; + type instance-identifier { + ct:instance-type ResourcePool; + require-instance true; + } + } + + container remaining { + config false; + description + "Provides visibility into total remaining capacity for this + reservation based on allocations that took effect utilizing + this reservation ID as a reference."; + + uses nfvi:resource-capacity; + } + + leaf-list allocations { + config false; + description + "Reference to a collection of consumed allocations referencing + this reservation."; + type instance-identifier { + ct:instance-type ResourceAllocation; + require-instance true; + } + } + } + + ct:complex-type ResourceAllocation { + ct:extends ResourceCollection; + + description + "A ResourceAllocation record denotes consumption of resources from a + referenced ResourcePool. + + It does not reflect an accepted request but is created to + represent the actual state about the ResourcePool. It is + created once the allocation(s) have successfully taken effect + on the 'source' of the ResourcePool. + + The 'priority' state indicates the classification for dealing + with resource starvation scenarios. Lower priority allocations + will be forcefully terminated to allow for higher priority + allocations to be fulfilled. + + Allocations without reference to an existing reservation will + receive the lowest priority."; + + reference "OPNFV-PROMISE, Section 3.4.3"; + + leaf reservation { + description "Reference to an existing reservation identifier (optional)"; + + type instance-identifier { + ct:instance-type ResourceReservation; + require-instance true; + } + } + + leaf pool { + description "Reference to an existing resource pool from which allocation is drawn"; + + type instance-identifier { + ct:instance-type ResourcePool; + require-instance true; + } + } + + container instance-ref { + config false; + description + "Reference to actual instance identifier of the provider/server for this allocation"; + leaf provider { + type instance-identifier { ct:instance-type ResourceProvider; } + } + leaf server { type yang:uuid; } + } + + leaf priority { + config false; + description + "Reflects current priority level of the allocation according to classification rules"; + type enumeration { + enum "high" { value 1; } + enum "normal" { value 2; } + enum "low" { value 3; } + } + default "normal"; + } + } + + ct:complex-type ResourceFlavor { + description "currently NOT an extension of ResourceElement."; + key "id"; + leaf id { type string; } + leaf name { type string; } + leaf disk { type uint32; units 'GB'; default 0; } + leaf ram { type uint32; units 'MB'; default 0; } + leaf vcpus { type uint16; default 0; } + } + + ct:complex-type ResourceProvider { + ct:extends nfvi:ResourceContainer; + + key "name"; + leaf token { type string; mandatory true; } + + container services { // read-only + config false; + container compute { + leaf endpoint { type inet:uri; } + ct:instance-list flavors { ct:instance-type ResourceFlavor; } + } + } + + leaf-list pools { + config false; + description + "Provides list of one or more pools that are referencing this provider."; + + type instance-identifier { + ct:instance-type ResourcePool; + require-instance true; + } + } + } + + // MAIN CONTAINER + container promise { + + uses resource-utilization { + description "Describes current state info about capacity utilization info"; + + augment "capacity/total" { uses nfvi:resource-capacity; } + augment "capacity/reserved" { uses nfvi:resource-capacity; } + augment "capacity/usage" { uses nfvi:resource-capacity; } + augment "capacity/available" { uses nfvi:resource-capacity; } + } + + ct:instance-list providers { + if-feature multi-provider; + description "Aggregate collection of all registered ResourceProvider instances for Promise resource management service"; + ct:instance-type ResourceProvider; + } + + ct:instance-list pools { + if-feature reservation-service; + description "Aggregate collection of all ResourcePool instances"; + ct:instance-type ResourcePool; + } + + ct:instance-list reservations { + if-feature reservation-service; + description "Aggregate collection of all ResourceReservation instances"; + ct:instance-type ResourceReservation; + } + + ct:instance-list allocations { + description "Aggregate collection of all ResourceAllocation instances"; + ct:instance-type ResourceAllocation; + } + + container policy { + container reservation { + leaf max-future-start-range { + description + "Enforce reservation request 'start' time is within allowed range from now"; + type uint16 { range 0..365; } + units "days"; + } + leaf max-future-end-range { + description + "Enforce reservation request 'end' time is within allowed range from now"; + type uint16 { range 0..365; } + units "days"; + } + leaf max-duration { + description + "Enforce reservation duration (end-start) does not exceed specified threshold"; + type uint16; + units "hours"; + default 8760; // for now cap it at max one year as default + } + leaf expiry { + description + "Duration in minutes from start when unallocated reserved resources + will be released back into the pool"; + type uint32; + units "minutes"; + } + } + } + } + + //------------------- + // INTENT INTERFACE + //------------------- + + // RESERVATION INTENTS + rpc create-reservation { + if-feature reservation-service; + description "Make a request to the reservation system to reserve resources"; + input { + uses resource-usage-request; + } + output { + uses common-intent-output; + leaf reservation-id { + type instance-identifier { ct:instance-type ResourceReservation; } + } + } + } + + rpc update-reservation { + description "Update reservation details for an existing reservation"; + input { + leaf reservation-id { + type instance-identifier { + ct:instance-type ResourceReservation; + require-instance true; + } + mandatory true; + } + uses resource-usage-request; + } + output { + uses common-intent-output; + } + } + + rpc cancel-reservation { + description "Cancel the reservation and be a good steward"; + input { + leaf reservation-id { + type instance-identifier { ct:instance-type ResourceReservation; } + mandatory true; + } + } + output { + uses common-intent-output; + } + } + + rpc query-reservation { + if-feature reservation-service; + description "Query the reservation system to return matching reservation(s)"; + input { + leaf zone { type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } } + uses query-resource-collection; + } + output { + leaf-list reservations { type instance-identifier { ct:instance-type ResourceReservation; } } + uses utilization-output; + } + } + + // CAPACITY INTENTS + rpc increase-capacity { + description "Increase total capacity for the reservation system between a window in time"; + input { + uses temporal-resource-collection; + leaf source { + type instance-identifier { + ct:instance-type nfvi:ResourceContainer; + } + } + } + output { + uses common-intent-output; + leaf pool-id { + type instance-identifier { ct:instance-type ResourcePool; } + } + } + } + + rpc decrease-capacity { + description "Decrease total capacity for the reservation system between a window in time"; + input { + uses temporal-resource-collection; + leaf source { + type instance-identifier { + ct:instance-type nfvi:ResourceContainer; + } + } + } + output { + uses common-intent-output; + leaf pool-id { + type instance-identifier { ct:instance-type ResourcePool; } + } + } + } + + rpc query-capacity { + description "Check available capacity information about a specified resource collection"; + input { + leaf capacity { + type enumeration { + enum 'total'; + enum 'reserved'; + enum 'usage'; + enum 'available'; + } + default 'available'; + } + leaf zone { type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } } + uses query-resource-collection; + // TBD: additional parameters for query-capacity + } + output { + leaf-list collections { type instance-identifier { ct:instance-type ResourceCollection; } } + uses utilization-output; + } + } + + // ALLOCATION INTENTS (should go into VIM module in the future) + rpc create-instance { + description "Create an instance of specified resource(s) utilizing capacity from the pool"; + input { + leaf provider-id { + if-feature multi-provider; + type instance-identifier { ct:instance-type ResourceProvider; require-instance true; } + } + leaf name { type string; mandatory true; } + leaf image { + type reference-identifier; + mandatory true; + } + leaf flavor { + type reference-identifier; + mandatory true; + } + leaf-list networks { + type reference-identifier; + description "optional, will assign default network if not provided"; + } + + // TODO: consider supporting a template-id (such as HEAT) for more complex instantiation + + leaf reservation-id { + type instance-identifier { ct:instance-type ResourceReservation; require-instance true; } + } + } + output { + uses common-intent-output; + leaf instance-id { + type instance-identifier { ct:instance-type ResourceAllocation; } + } + } + } + + rpc destroy-instance { + description "Destroy an instance of resource utilization and release it back to the pool"; + input { + leaf instance-id { + type instance-identifier { ct:instance-type ResourceAllocation; require-instance true; } + } + } + output { + uses common-intent-output; + } + } + + // PROVIDER INTENTS (should go into VIM module in the future) + rpc add-provider { + description "Register a new resource provider into reservation system"; + input { + leaf provider-type { + description "Select a specific resource provider type"; + mandatory true; + type enumeration { + enum openstack; + enum hp; + enum rackspace; + enum amazon { + status planned; + } + enum joyent { + status planned; + } + enum azure { + status planned; + } + } + default openstack; + } + uses acm:access-credentials { + refine strategy { + default keystone; + } + refine endpoint { + default "http://localhost:5000/v2.0"; + } + } + leaf user-domain-name { type string; } + container project { + leaf id { type string; } + leaf name { type string; } + leaf domain-name { type string; } + } + } + output { + uses common-intent-output; + leaf provider-id { + type instance-identifier { ct:instance-type ResourceProvider; } + } + } + } + + // TODO... + notification reservation-event; + notification capacity-event; + notification allocation-event; +} diff --git a/deprecated/source/spec/openstack-intents.coffee b/deprecated/source/spec/openstack-intents.coffee new file mode 100644 index 0000000..6fd8fe2 --- /dev/null +++ b/deprecated/source/spec/openstack-intents.coffee @@ -0,0 +1,14 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +request = require 'superagent' + +module.exports = + 'create-tenant': + (input, output, done) -> + # TODO - this requires OS-KSADM extension diff --git a/deprecated/source/spec/promise-intents.coffee b/deprecated/source/spec/promise-intents.coffee new file mode 100644 index 0000000..985e81f --- /dev/null +++ b/deprecated/source/spec/promise-intents.coffee @@ -0,0 +1,379 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +module.exports = + 'create-reservation': + (input, output, done) -> + # 1. create the reservation record (empty) + reservation = @create 'ResourceReservation' + reservations = @access 'promise.reservations' + + # 2. update the record with requested input + reservation.invoke 'update', input.get() + .then (res) -> + # 3. save the record and add to list + res.save() + .then -> + reservations.push res + output.set result: 'ok', message: 'reservation request accepted' + output.set 'reservation-id', res.id + done() + .catch (err) -> + output.set result: 'error', message: err + done() + .catch (err) -> + output.set result: 'conflict', message: err + done() + + 'query-reservation': + (input, output, done) -> + query = input.get() + query.capacity = 'reserved' + @invoke 'query-capacity', query + .then (res) -> + output.set 'reservations', res.get 'collections' + output.set 'utilization', res.get 'utilization' + done() + .catch (e) -> done e + + 'update-reservation': + (input, output, done) -> + # TODO: we shouldn't need this... need to check why leaf mandatory: true not being enforced + unless (input.get 'reservation-id')? + output.set result: 'error', message: "must provide 'reservation-id' parameter" + return done() + + # 1. find the reservation + reservation = @find 'ResourceReservation', input.get 'reservation-id' + unless reservation? + output.set result: 'error', message: 'no reservation found for specified identifier' + return done() + + # 2. update the record with requested input + reservation.invoke 'update', input.get() + .then (res) -> + # 3. save the updated record + res.save() + .then -> + output.set result: 'ok', message: 'reservation update successful' + done() + .catch (err) -> + output.set result: 'error', message: err + done() + .catch (err) -> + output.set result: 'conflict', message: err + done() + + 'cancel-reservation': + (input, output, done) -> + # 1. find the reservation + reservation = @find 'ResourceReservation', input.get 'reservation-id' + unless reservation? + output.set result: 'error', message: 'no reservation found for specified identifier' + return done() + + # 2. destroy all traces of this reservation + reservation.destroy() + .then => + (@access 'promise.reservations').remove reservation.id + output.set 'result', 'ok' + output.set 'message', 'reservation canceled' + done() + .catch (e) -> + output.set 'result', 'error' + output.set 'message', e + done() + + 'query-capacity': + (input, output, done) -> + # 1. we gather up all collections that match the specified window + window = input.get 'window' + metric = input.get 'capacity' + + collections = switch metric + when 'total' then [ 'ResourcePool' ] + when 'reserved' then [ 'ResourceReservation' ] + when 'usage' then [ 'ResourceAllocation' ] + when 'available' then [ 'ResourcePool', 'ResourceReservation', 'ResourceAllocation' ] + + matches = collections.reduce ((a, name) => + res = @find name, + start: (value) -> (not window.end?) or (new Date value) <= (new Date window.end) + end: (value) -> (not window.start?) or (new Date value) >= (new Date window.start) + enabled: true + a.concat res... + ), [] + + if window.scope is 'exclusive' + # yes, we CAN query filter in one shot above but this makes logic cleaner... + matches = matches.where + start: (value) -> (not window.start?) or (new Date value) >= (new Date window.start) + end: (value) -> (not window.end?) or (new Date value) <= (new Date window.end) + + # exclude any identifiers specified + matches = matches.without id: (input.get 'without') + + if metric is 'available' + # excludes allocations with reservation property set (to prevent double count) + matches = matches.without reservation: (v) -> v? + + output.set 'collections', matches + unless (input.get 'show-utilization') is true + return done() + + # 2. we calculate the deltas based on start/end times of each match item + deltas = matches.reduce ((a, entry) -> + b = entry.get() + b.end ?= 'infiniteT' + [ skey, ekey ] = [ (b.start.split 'T')[0], (b.end.split 'T')[0] ] + a[skey] ?= count: 0, capacity: {} + a[ekey] ?= count: 0, capacity: {} + a[skey].count += 1 + a[ekey].count -= 1 + + for k, v of b.capacity when v? + a[skey].capacity[k] ?= 0 + a[ekey].capacity[k] ?= 0 + if entry.name is 'ResourcePool' + a[skey].capacity[k] += v + a[ekey].capacity[k] -= v + else + a[skey].capacity[k] -= v + a[ekey].capacity[k] += v + return a + ), {} + + # 3. we then sort the timestamps and aggregate the deltas + last = count: 0, capacity: {} + usages = for timestamp in Object.keys(deltas).sort() when timestamp isnt 'infinite' + entry = deltas[timestamp] + entry.timestamp = (new Date timestamp).toJSON() + entry.count += last.count + for k, v of entry.capacity + entry.capacity[k] += (last.capacity[k] ? 0) + last = entry + entry + + output.set 'utilization', usages + done() + + 'increase-capacity': + (input, output, done) -> + pool = @create 'ResourcePool', input.get() + pool.save() + .then (res) => + (@access 'promise.pools').push res + output.set result: 'ok', message: 'capacity increase successful' + output.set 'pool-id', res.id + done() + .catch (e) -> + output.set result: 'error', message: e + done() + + 'decrease-capacity': + (input, output, done) -> + request = input.get() + for k, v of request.capacity + request.capacity[k] = -v + pool = @create 'ResourcePool', request + pool.save() + .then (res) => + (@access 'promise.pools').push res + output.set result: 'ok', message: 'capacity decrease successful' + output.set 'pool-id', res.id + done() + .catch (e) -> + output.set result: 'error', message: e + done() + + # TEMPORARY (should go into VIM-specific module) + 'create-instance': + (input, output, done) -> + pid = input.get 'provider-id' + if pid? + provider = @find 'ResourceProvider', pid + unless provider? + output.set result: 'error', message: "no matching provider found for specified identifier: #{pid}" + return done() + else + provider = (@find 'ResourceProvider')[0] + unless provider? + output.set result: 'error', message: "no available provider found for create-instance" + return done() + + # calculate required capacity based on 'flavor' and other params + flavor = provider.access "services.compute.flavors.#{input.get 'flavor'}" + unless flavor? + output.set result: 'error', message: "no such flavor found for specified identifier: #{pid}" + return done() + + required = + instances: 1 + cores: flavor.get 'vcpus' + ram: flavor.get 'ram' + gigabytes: flavor.get 'disk' + + rid = input.get 'reservation-id' + if rid? + reservation = @find 'ResourceReservation', rid + unless reservation? + output.set result: 'error', message: 'no valid reservation found for specified identifier' + return done() + unless (reservation.get 'active') is true + output.set result: 'error', message: "reservation is currently not active" + return done() + available = reservation.get 'remaining' + else + available = @get 'promise.capacity.available' + + # TODO: need to verify whether 'provider' associated with this 'reservation' + + for k, v of required when v? and !!v + unless available[k] >= v + output.set result: 'conflict', message: "required #{k}=#{v} exceeds available #{available[k]}" + return done() + + @create 'ResourceAllocation', + reservation: rid + capacity: required + .save() + .then (instance) => + url = provider.get 'services.compute.endpoint' + payload = + server: + name: input.get 'name' + imageRef: input.get 'image' + flavorRef: input.get 'flavor' + networks = (input.get 'networks').filter (x) -> x? and !!x + if networks.length > 0 + payload.server.networks = networks.map (x) -> uuid: x + + request = @parent.require 'superagent' + request + .post "#{url}/servers" + .send payload + .set 'X-Auth-Token', provider.get 'token' + .set 'Accept', 'application/json' + .end (err, res) => + if err? or !res.ok + instance.destroy() + #console.error err + return done res.error + #console.log JSON.stringify res.body, null, 2 + instance.set 'instance-ref', + provider: provider + server: res.body.server.id + (@access 'promise.allocations').push instance + output.set result: 'ok', message: 'create-instance request accepted' + output.set 'instance-id', instance.id + done() + return instance + .catch (err) -> + output.set result: 'error', mesage: err + done() + + 'destroy-instance': + (input, output, done) -> + # 1. find the instance + instance = @find 'ResourceAllocation', input.get 'instance-id' + unless instance? + output.set result: 'error', message: 'no allocation found for specified identifier' + return done() + + # 2. destroy all traces of this instance + instance.destroy() + .then => + # always remove internally + (@access 'promise.allocations').remove instance.id + ref = instance.get 'instance-ref' + provider = (@access "promise.providers.#{ref.provider}") + url = provider.get 'services.compute.endpoint' + request = @parent.require 'superagent' + request + .delete "#{url}/servers/#{ref.server}" + .set 'X-Auth-Token', provider.get 'token' + .set 'Accept', 'application/json' + .end (err, res) => + if err? or !res.ok + console.error err + return done res.error + output.set 'result', 'ok' + output.set 'message', 'instance destroyed and resource released back to pool' + done() + return instance + .catch (e) -> + output.set 'result', 'error' + output.set 'message', e + done() + + # TEMPORARY (should go into VIM-specific module) + 'add-provider': + (input, output, done) -> + app = @parent + request = app.require 'superagent' + + payload = switch input.get 'provider-type' + when 'openstack' + auth: + identity: + methods: [ "password" ] + password: + user: + name: input.get 'username' + password: input.get 'password' + domain: + name: input.get 'user-domain-name' + scope: + project: + name: input.get 'project.name' + domain: + name: input.get 'project.domain-name' + + unless payload? + return done 'Sorry, only openstack supported at this time' + + url = input.get 'endpoint' + switch input.get 'strategy' + when 'keystone', 'oauth' + url += '/auth/tokens' unless /\/tokens$/.test url + + providers = @access 'promise.providers' + request + .post url + .send payload + .set 'Accept', 'application/json' + .end (err, res) => + if err? or !res.ok then return done res.error + #console.log JSON.stringify res.body, null, 2 + #console.log res.headers + #console.log res.body.token.catalog + provider = @create 'ResourceProvider', + token: res.headers['x-subject-token'] + name: res.body.token.project.name + provider.invoke 'update', res.body.token.catalog + .then (res) -> + res.save() + .then -> + providers.push res + output.set 'result', 'ok' + output.set 'provider-id', res.id + done() + .catch (err) -> + output.set 'error', message: err + done() + .catch (err) -> + output.set 'error', message: err + done() + + # @using 'mano', -> + # @invoke 'add-provider', (input.get 'endpoint', 'region', 'username', 'password') + # .then (res) => + # (@access 'promise.providers').push res + # output.set 'result', 'ok' + # output.set 'provider-id', res.id + # done() diff --git a/deprecated/source/spec/promise-module.coffee b/deprecated/source/spec/promise-module.coffee new file mode 100644 index 0000000..f021f6c --- /dev/null +++ b/deprecated/source/spec/promise-module.coffee @@ -0,0 +1,80 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +module.exports = + '/opnfv-promise/promise/capacity/total': (prev) -> + @computed (-> + combine = (a, b) -> + for k, v of b.capacity when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'pools') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + + '/opnfv-promise/promise/capacity/reserved', (prev) -> + @computed (-> + combine = (a, b) -> + for k, v of b.capacity when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'reservations') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + + # rebind to be a computed property + '/opnfv-promise/promise/capacity/usage': (prev) -> + @computed (-> + combine = (a, b) -> + for k, v of b.capacity when v? + a[k] ?= 0 + a[k] += v + return a + (@parent.get 'allocations') + .filter (entry) -> entry.active is true + .reduce combine, {} + ), type: prev + + # rebind to be a computed property + '/opnfv-promise/promise/capacity/available': (prev) -> + @computed (-> + total = @get 'total' + reserved = @get 'reserved' + usage = @get 'usage' + for k, v of total when v? + total[k] -= reserved[k] if reserved[k]? + total[k] -= usage[k] if usage[k]? + total + ), type: prev + + '/opnfv-promise/create-reservation': + (input, output, done) -> + # 1. create the reservation record (empty) + reservation = @create 'ResourceReservation' + reservations = @access 'promise.reservations' + + # 2. update the record with requested input + reservation.invoke 'update', input.get() + .then (res) -> + # 3. save the record and add to list + res.save() + .then -> + reservations.push res + output.set result: 'ok', message: 'reservation request accepted' + output.set 'reservation-id', res.id + done() + .catch (err) -> + output.set result: 'error', message: err + done() + .catch (err) -> + output.set result: 'conflict', message: err + done() diff --git a/deprecated/source/test/mocha.opts b/deprecated/source/test/mocha.opts new file mode 100644 index 0000000..1e154ee --- /dev/null +++ b/deprecated/source/test/mocha.opts @@ -0,0 +1,2 @@ +--require should +--compilers coffee:coffee-script/register diff --git a/deprecated/source/test/promise-intents.coffee b/deprecated/source/test/promise-intents.coffee new file mode 100644 index 0000000..db7e8d6 --- /dev/null +++ b/deprecated/source/test/promise-intents.coffee @@ -0,0 +1,445 @@ +# +# Author: Peter K. Lee (peter@corenova.com) +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# +config = require 'config' +assert = require 'assert' +forge = require 'yangforge' +app = forge.load '!yaml ../promise.yaml', async: false, pkgdir: __dirname + +# this is javascript promise framework and not related to opnfv-promise +promise = require 'promise' + +if process.env.DEBUG + debug = console.log +else + debug = -> + +# in the future with YF 0.12.x +# app = forge.load('..').build('test') +# app.set config +# app.use 'proxy', target: x.x.x.x:5050, interface: 'restjson' + +describe "promise", -> + before -> + # ensure we have valid OpenStack environment to test against + try + config.get 'openstack.auth.endpoint' + catch e + throw new Error "missing OpenStack environmental variables" + + + # below 'provider' is used across test suites + provider = undefined + + # Test Scenario 00 (FUTURE) + # describe "prepare OpenStack for testing", -> + # before (done) -> + # # ensure we have valid OpenStack environment to test against + # try + # config.get 'openstack.auth.url' + # catch e + # throw new Error "missing OpenStack environmental variables" + + # os = forge.load '!yaml ../openstack.yaml', async: false, pkgdir: __dirname + # app.attach 'openstack', os.access 'openstack' + # app.set config + + # describe "authenticate", -> + # it "should retrieve available service catalog", (done) -> + # app.access('openstack').invoke 'authenticate' + # .then (res) -> + + # done() + # .catch (err) -> done err + + # describe "create-tenant", -> + # # create a new tenant for testing purposes + + # describe "upload-image", -> + # # upload a new test image + + + + # Test Scenario 01 + describe "register OpenStack into resource pool", -> + pool = undefined + + # TC-01 + describe "add-provider", -> + it "should add a new OpenStack provider without error", (done) -> + @timeout 5000 + + auth = config.get 'openstack.auth' + auth['provider-type'] = 'openstack' + + app.access('opnfv-promise').invoke 'add-provider', auth + .then (res) -> + res.get('result').should.equal 'ok' + provider = id: res.get('provider-id') + # HACK - we delay by a second to allow time for discovering capacity and flavors + setTimeout done, 1000 + .catch (err) -> done err + + it "should update promise.providers with a new entry", -> + app.get('opnfv-promise.promise.providers').should.have.length(1) + + it "should contain a new ResourceProvider record in the store", -> + assert provider?.id?, "unable to check without ID" + provider = app.access('opnfv-promise').find('ResourceProvider', provider.id) + assert provider? + + # TC-02 + describe "increase-capacity", -> + it "should add more capacity to the reservation service without error", (done) -> + app.access('opnfv-promise').invoke 'increase-capacity', + source: provider + capacity: + cores: 20 + ram: 51200 + instances: 10 + addresses: 10 + .then (res) -> + res.get('result').should.equal 'ok' + pool = id: res.get('pool-id') + done() + .catch (err) -> done err + + it "should update promise.pools with a new entry", -> + app.get('opnfv-promise.promise.pools').should.have.length(1) + + it "should contain a ResourcePool record in the store", -> + assert pool?.id?, "unable to check without ID" + pool = app.access('opnfv-promise').find('ResourcePool', pool.id) + assert pool? + + # TC-03 + describe "query-capacity", -> + it "should report total collections and utilizations", (done) -> + app.access('opnfv-promise').invoke 'query-capacity', + capacity: 'total' + .then (res) -> + res.get('collections').should.be.Array + res.get('collections').length.should.be.above(0) + res.get('utilization').should.be.Array + res.get('utilization').length.should.be.above(0) + done() + .catch (err) -> done err + + it "should contain newly added capacity pool", (done) -> + app.access('opnfv-promise').invoke 'query-capacity', + capacity: 'total' + .then (res) -> + res.get('collections').should.containEql "ResourcePool:#{pool.id}" + done() + .catch (err) -> done err + + # Test Scenario 02 + describe "allocation without reservation", -> + + # TC-04 + describe "create-instance", -> + allocation = undefined + instance_id = undefined + + before -> + # XXX - need to determine image and flavor to use in the given provider for this test + assert provider?, + "unable to execute without registered 'provider'" + + it "should create a new server in target provider without error", (done) -> + @timeout 5000 + test = config.get 'openstack.test' + app.access('opnfv-promise').invoke 'create-instance', + 'provider-id': provider.id + name: 'promise-test-no-reservation' + image: test.image + flavor: test.flavor + networks: [ test.network ] + .then (res) -> + debug res.get() + res.get('result').should.equal 'ok' + instance_id = res.get('instance-id') + done() + .catch (err) -> done err + + it "should update promise.allocations with a new entry", -> + app.get('opnfv-promise.promise.allocations').length.should.be.above(0) + + it "should contain a new ResourceAllocation record in the store", -> + assert instance_id?, "unable to check without ID" + allocation = app.access('opnfv-promise').find('ResourceAllocation', instance_id) + assert allocation? + + it "should reference the created server ID from the provider", -> + assert allocation?, "unable to check without record" + allocation.get('instance-ref').should.have.property('provider') + allocation.get('instance-ref').should.have.property('server') + + it "should have low priority state", -> + assert allocation?, "unable to check without record" + allocation.get('priority').should.equal 'low' + + # Test Scenario 03 + describe "allocation using reservation for immediate use", -> + reservation = undefined + + # TC-05 + describe "create-reservation", -> + it "should create reservation record (no start/end) without error", (done) -> + app.access('opnfv-promise').invoke 'create-reservation', + capacity: + cores: 5 + ram: 25600 + addresses: 3 + instances: 3 + .then (res) -> + res.get('result').should.equal 'ok' + reservation = id: res.get('reservation-id') + done() + .catch (err) -> done err + + it "should update promise.reservations with a new entry", -> + app.get('opnfv-promise.promise.reservations').length.should.be.above(0) + + it "should contain a new ResourceReservation record in the store", -> + assert reservation?.id?, "unable to check without ID" + reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) + assert reservation? + + # TC-06 + describe "create-instance", -> + allocation = undefined + + before -> + assert provider?, + "unable to execute without registered 'provider'" + assert reservation?, + "unable to execute without valid reservation record" + + it "should create a new server in target provider (with reservation) without error", (done) -> + @timeout 5000 + test = config.get 'openstack.test' + app.access('opnfv-promise').invoke 'create-instance', + 'provider-id': provider.id + name: 'promise-test-reservation' + image: test.image + flavor: test.flavor + networks: [ test.network ] + 'reservation-id': reservation.id + .then (res) -> + debug res.get() + res.get('result').should.equal 'ok' + allocation = id: res.get('instance-id') + done() + .catch (err) -> done err + + it "should contain a new ResourceAllocation record in the store", -> + assert allocation?.id?, "unable to check without ID" + allocation = app.access('opnfv-promise').find('ResourceAllocation', allocation.id) + assert allocation? + + it "should be referenced in the reservation record", -> + assert reservation? and allocation?, "unable to check without records" + reservation.get('allocations').should.containEql allocation.id + + it "should have high priority state", -> + assert allocation?, "unable to check without record" + allocation.get('priority').should.equal 'high' + + # Test Scenario 04 + describe "reservation for future use", -> + reservation = undefined + start = new Date + end = new Date + # 7 days in the future + start.setTime (start.getTime() + 7*60*60*1000) + # 8 days in the future + end.setTime (end.getTime() + 8*60*60*1000) + + # TC-07 + describe "create-reservation", -> + it "should create reservation record (for future) without error", (done) -> + app.access('opnfv-promise').invoke 'create-reservation', + start: start.toJSON() + end: end.toJSON() + capacity: + cores: 1 + ram: 12800 + addresses: 1 + instances: 1 + .then (res) -> + res.get('result').should.equal 'ok' + reservation = id: res.get('reservation-id') + done() + .catch (err) -> done err + + it "should update promise.reservations with a new entry", -> + app.get('opnfv-promise.promise.reservations').length.should.be.above(0) + + it "should contain a new ResourceReservation record in the store", -> + assert reservation?.id?, "unable to check without ID" + reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) + assert reservation? + + # TC-08 + describe "query-reservation", -> + it "should contain newly created future reservation", (done) -> + app.access('opnfv-promise').invoke 'query-reservation', + window: + start: start.toJSON() + end: end.toJSON() + .then (res) -> + res.get('reservations').should.containEql reservation.id + done() + .catch (err) -> done err + + # TC-09 + describe "update-reservation", -> + it "should modify existing reservation without error", (done) -> + app.access('opnfv-promise').invoke 'update-reservation', + 'reservation-id': reservation.id + capacity: + cores: 3 + ram: 12800 + addresses: 2 + instances: 2 + .then (res) -> + res.get('result').should.equal 'ok' + done() + .catch (err) -> done err + + # TC-10 + describe "cancel-reservation", -> + it "should modify existing reservation without error", (done) -> + app.access('opnfv-promise').invoke 'cancel-reservation', + 'reservation-id': reservation.id + .then (res) -> + res.get('result').should.equal 'ok' + done() + .catch (err) -> done err + + it "should no longer contain record of the deleted reservation", -> + assert reservation?.id?, "unable to check without ID" + reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) + assert not reservation? + + # Test Scenario 05 + describe "capacity planning", -> + + # TC-11 + describe "decrease-capacity", -> + start = new Date + end = new Date + # 30 days in the future + start.setTime (start.getTime() + 30*60*60*1000) + # 45 days in the future + end.setTime (end.getTime() + 45*60*60*1000) + + it "should decrease available capacity from a provider in the future", (done) -> + app.access('opnfv-promise').invoke 'decrease-capacity', + source: provider + capacity: + cores: 5 + ram: 17920 + instances: 5 + start: start.toJSON() + end: end.toJSON() + .then (res) -> + res.get('result').should.equal 'ok' + done() + .catch (err) -> done err + + # TC-12 + describe "increase-capacity", -> + start = new Date + end = new Date + # 14 days in the future + start.setTime (start.getTime() + 14*60*60*1000) + # 21 days in the future + end.setTime (end.getTime() + 21*60*60*1000) + + it "should increase available capacity from a provider in the future", (done) -> + app.access('opnfv-promise').invoke 'decrease-capacity', + source: provider + capacity: + cores: 1 + ram: 3584 + instances: 1 + start: start.toJSON() + end: end.toJSON() + .then (res) -> + res.get('result').should.equal 'ok' + done() + .catch (err) -> done err + + # TC-13 (Should improve this TC) + describe "query-capacity", -> + it "should report available collections and utilizations", (done) -> + app.access('opnfv-promise').invoke 'query-capacity', + capacity: 'available' + .then (res) -> + res.get('collections').should.be.Array + res.get('collections').length.should.be.above(0) + res.get('utilization').should.be.Array + res.get('utilization').length.should.be.above(0) + done() + .catch (err) -> done err + + # Test Scenario 06 + describe "reservation with conflict", -> + # TC-14 + describe "create-reservation", -> + it "should fail to create immediate reservation record with proper error", (done) -> + app.access('opnfv-promise').invoke 'create-reservation', + capacity: + cores: 5 + ram: 17920 + instances: 10 + .then (res) -> + res.get('result').should.equal 'conflict' + done() + .catch (err) -> done err + + it "should fail to create future reservation record with proper error", (done) -> + start = new Date + # 30 days in the future + start.setTime (start.getTime() + 30*60*60*1000) + + app.access('opnfv-promise').invoke 'create-reservation', + capacity: + cores: 5 + ram: 17920 + instances: 10 + start: start.toJSON() + .then (res) -> + res.get('result').should.equal 'conflict' + done() + .catch (err) -> done err + + # Test Scenario 07 + describe "cleanup test allocations", -> + allocations = undefined + before -> + allocations = app.get('opnfv-promise.promise.allocations') + debug provider.get() + debug allocations + allocations.length.should.be.above(0) + + describe "destroy-instance", -> + it "should successfully destroy all allocations", (done) -> + @timeout 5000 + promises = allocations.map (x) -> + app.access('opnfv-promise').invoke 'destroy-instance', + 'instance-id': x.id + promise.all promises + .then (res) -> + res.forEach (x) -> + debug x.get() + x.get('result').should.equal 'ok' + done() + .catch (err) -> done err diff --git a/promise/test/functest/run_promise_tests.py b/promise/test/functest/run_promise_tests.py deleted file mode 100644 index a57918c..0000000 --- a/promise/test/functest/run_promise_tests.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/python -# -# Copyright (c) 2015 All rights reserved -# This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -import argparse -import json -import logging -import os -import re -import subprocess -import sys -import time - -import functest.utils.openstack_utils as os_utils -from functest.utils.constants import CONST - -parser = argparse.ArgumentParser() - -parser.add_argument("-d", "--debug", help="Debug mode", action="store_true") -parser.add_argument("-r", "--report", - help="Create json result file", - action="store_true") -args = parser.parse_args() - - -PROMISE_REPO_DIR = '/src/promise' -RESULTS_DIR = CONST.dir_results - -PROMISE_TENANT_NAME = CONST.promise_tenant_name -PROMISE_PROJECT_NAME = CONST.promise_tenant_name -PROMISE_PROJECT_DESCRIPTION = CONST.promise_tenant_description -PROMISE_USER_NAME = CONST.promise_user_name -PROMISE_USER_PWD = CONST.promise_user_pwd -PROMISE_IMAGE_NAME = CONST.promise_image_name -PROMISE_FLAVOR_NAME = CONST.promise_flavor_name -PROMISE_FLAVOR_VCPUS = CONST.promise_flavor_vcpus -PROMISE_FLAVOR_RAM = CONST.promise_flavor_ram -PROMISE_FLAVOR_DISK = CONST.promise_flavor_disk - - -GLANCE_IMAGE_FILENAME = CONST.openstack_image_file_name -GLANCE_IMAGE_FORMAT = CONST.openstack_image_disk_format -GLANCE_IMAGE_NAME = CONST.openstack_image_file_name -GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_images, - GLANCE_IMAGE_FILENAME) - -PROMISE_NET_NAME = CONST.promise_network_name -PROMISE_SUBNET_NAME = CONST.promise_subnet_name -PROMISE_SUBNET_CIDR = CONST.promise_subnet_cidr -PROMISE_ROUTER_NAME = CONST.promise_router_name - - -""" logging configuration """ -logger = logging.getLogger('promise') - - -def main(): - return_code = -1 - os_auth = os.environ["OS_AUTH_URL"] - - creds = os_utils.get_credentials() - - try: - logger.info("Env variables") - logger.info("OS_AUTH_URL: %s" % os.environ["OS_AUTH_URL"]) - logger.info("OS_IDENTITY_API_VERSION: %s " % - os.environ["OS_IDENTITY_API_VERSION"]) - logger.info("OS_USER_DOMAIN_NAME: %s" % - os.environ["OS_USER_DOMAIN_NAME"]) - logger.info("OS_PROJECT_DOMAIN_NAME: %s" % - os.environ["OS_PROJECT_DOMAIN_NAME"]) - except KeyError: - logger.error("Please set the OS environment variables") - - keystone_client = os_utils.get_keystone_client() - - logger.info("Creating project '%s'..." % PROMISE_PROJECT_NAME) - project_id = os_utils.create_tenant( - keystone_client, PROMISE_PROJECT_NAME, PROMISE_PROJECT_DESCRIPTION) - if not project_id: - logger.error("Error : Failed to create %s project" - % PROMISE_PROJECT_NAME) - return return_code - logger.debug("Project '%s' created successfully." % PROMISE_PROJECT_NAME) - - roles_name = ["_member_", "Member"] - role_id = '' - for role_name in roles_name: - if role_id == '': - role_id = os_utils.get_role_id(keystone_client, role_name) - - if role_id == '': - logger.error("Error : Failed to get id for %s role" % role_name) - return return_code - - domain_id = '' - domain_id = os_utils.get_domain_id(keystone_client, - os.environ["OS_USER_DOMAIN_NAME"]) - if domain_id == '': - logger.error("Error: Failed to get id for %s domain" % - os.environ["OS_USER_DOMAIN_NAME"]) - return return_code - - logger.info("Creating user '%s'..." % PROMISE_USER_NAME) - try: - user = keystone_client.users.create(name=PROMISE_USER_NAME, - domain=domain_id, - password=PROMISE_USER_PWD) - except Exception as e: - logger.error("Error : Failed to create %s user" % PROMISE_USER_NAME) - return return_code - logger.debug("User '%s' created successfully." % PROMISE_USER_NAME) - - try: - keystone_client.roles.grant(role=role_id, user=user.id, - project=project_id) - except Exception as e: - logger.error("Error: Failed to grant member role on project %s" % - project_id) - return return_code - - nova_client = os_utils.get_nova_client() - glance_client = os_utils.get_glance_client() - - logger.info("Creating image '%s' from '%s'..." % (PROMISE_IMAGE_NAME, - GLANCE_IMAGE_PATH)) - - logger.info("Upload some OS images if it doesn't exist") - - image_id = os_utils.get_image_id(glance_client, GLANCE_IMAGE_NAME) - - if image_id == '': - logger.info("%s image doesn't exist on glance repo" % GLANCE_IMAGE_NAME) - logger.info("Try downloading this image and upload on glance !") - image_id = os_utils.create_glance_image( - glance_client, GLANCE_IMAGE_NAME, GLANCE_IMAGE_PATH) - - if image_id == '': - logger.error("Failed to create the Glance image...") - return return_code - - logger.debug("Image '%s' with ID '%s' created successfully." - % (PROMISE_IMAGE_NAME, image_id)) - flavor_id = os_utils.get_flavor_id(nova_client, PROMISE_FLAVOR_NAME) - if flavor_id == '': - logger.info("Creating flavor '%s'..." % PROMISE_FLAVOR_NAME) - flavor_id = os_utils.create_flavor(nova_client, - PROMISE_FLAVOR_NAME, - PROMISE_FLAVOR_RAM, - PROMISE_FLAVOR_DISK, - PROMISE_FLAVOR_VCPUS) - if not flavor_id: - logger.error("Failed to create the Flavor...") - return return_code - logger.debug("Flavor '%s' with ID '%s' created successfully." % - (PROMISE_FLAVOR_NAME, flavor_id)) - else: - logger.debug("Using existing flavor '%s' with ID '%s'..." - % (PROMISE_FLAVOR_NAME, flavor_id)) - - network_dic = os_utils.create_shared_network_full(PROMISE_NET_NAME, - PROMISE_SUBNET_NAME, - PROMISE_ROUTER_NAME, - PROMISE_SUBNET_CIDR) - if not network_dic: - logger.error("Failed to create the private network...") - return return_code - - logger.info("Exporting environment variables...") - os.environ["NODE_ENV"] = "functest" - os.environ["OS_PASSWORD"] = PROMISE_USER_PWD - os.environ["OS_TEST_IMAGE"] = image_id - os.environ["OS_TEST_FLAVOR"] = flavor_id - os.environ["OS_TEST_NETWORK"] = network_dic["net_id"] - os.environ["OS_PROJECT_NAME"] = PROMISE_PROJECT_NAME - os.environ["OS_USERNAME"] = PROMISE_USER_NAME - - os.chdir(PROMISE_REPO_DIR + '/source/') - results_file_name = os.path.join(RESULTS_DIR, 'promise-results.json') - results_file = open(results_file_name, 'w+') - cmd = 'npm run -s test -- --reporter json' - - logger.info("Running command: %s" % cmd) - ret = subprocess.call(cmd, shell=True, stdout=results_file, - stderr=subprocess.STDOUT) - results_file.close() - - if ret == 0: - logger.info("The test succeeded.") - return_code = 0 - else: - logger.info("The command '%s' failed." % cmd) - - # Print output of file - with open(results_file_name, 'r') as results_file: - data = results_file.read() - logger.debug("\n%s" % data) - json_data = json.loads(data) - - suites = json_data["stats"]["suites"] - tests = json_data["stats"]["tests"] - passes = json_data["stats"]["passes"] - pending = json_data["stats"]["pending"] - failures = json_data["stats"]["failures"] - start_time_json = json_data["stats"]["start"] - end_time = json_data["stats"]["end"] - duration = float(json_data["stats"]["duration"]) / float(1000) - - logger.info("\n" - "****************************************\n" - " Promise test report\n\n" - "****************************************\n" - " Suites: \t%s\n" - " Tests: \t%s\n" - " Passes: \t%s\n" - " Pending: \t%s\n" - " Failures:\t%s\n" - " Start: \t%s\n" - " End: \t%s\n" - " Duration:\t%s\n" - "****************************************\n\n" - % (suites, tests, passes, pending, failures, - start_time_json, end_time, duration)) - end_time = time.time() - - return return_code - - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - sys.exit(main()) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d39c387..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -functest diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index dcdaa25..0000000 --- a/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[metadata] -name = promise -version = 2017.9.0 -home-page = https://wiki.opnfv.org/display/promise/Promise - -[files] -packages = promise/test/functest -scripts = promise/test/functest/run_promise_tests.py diff --git a/setup.py b/setup.py deleted file mode 100644 index a1e9b3b..0000000 --- a/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2017 Orange and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 - -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/source/.gitignore b/source/.gitignore deleted file mode 100644 index f49cc53..0000000 --- a/source/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -lib-cov -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz -pids -logs -results -node_modules -npm-debug.log -*~ -*# - diff --git a/source/.npmignore b/source/.npmignore deleted file mode 100644 index 4f726b0..0000000 --- a/source/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -.git* - diff --git a/source/LICENSE b/source/LICENSE deleted file mode 100644 index 8f71f43..0000000 --- a/source/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff --git a/source/README.md b/source/README.md deleted file mode 100644 index 681e2b9..0000000 --- a/source/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# Resource Management for Virtual Infrastructure - -**Promise** is a resource reservation and management project to identify NFV related requirements and realize resource reservation for future usage by capacity management of resource pools regarding compute, network and storage. - -The following are the key features provided by this module: - -* Resource Capacity Management -* Resource Reservation -* Resource Allocation - -This module also contains a collection of [YANG data models](schema/) as defined under the direction of [OPNFV Promise](http://wiki.opnfv.org/promise) project. - -## Installation - -`opnfv-promise` is built with [YangForge](http://github.com/opnfv/yangforge) data modeling -framework. You will need to first install `yangforge` and use the -provided `yfc` command line utility to run this module. - -```bash -$ npm install -g yangforge -``` - -There are also alternative installer plugins for [Fuel](http://github.com/opnfv/fuel-plugin-promise) and [Juju](http://github.com/opnfv/juju-plugin-promise). - -## Usage -```bash -$ yfc run promise.yaml -``` - -The `yfc run` command will load the primary application -package from this repository along with any other dependency -files/assets referenced within the YAML manifest and instantiate the -opnfv-promise module and run REST/JSON interface by default listening -on port 5000. - -You can also checkout this GIT repository or simply download the files -into your local system and run the application. - -## Testing - -```bash -$ npm install -$ npm test -``` - -TBD - -## Primary YANG Data Models - -name | description | status ---- | --- | --- -[opnfv-promise](schema/opnfv-promise.yang) | provide resource reservation and capacity management | 95% complete -[nfv-infrastructure](schema/nfv-infrastructure.yang) | common NFV Infrastructure resource models | 80% complete -[nfv-mano](schema/nfv-mano.yang) | common NFV MANO resource models including VIM | 20% complete -[openstack](schema/openstack.yang) | openstack specific VIM extensions | 50% complete - -## Promise Information Models - -### ResourceReservation - -The data model describing the required parameters regarding a resource -reservation. The schema definition expressed in Yang can be found -[here](schema/opnfv-promise.yang). - -#### Key Elements - -Name | Type | Description ---- | --- | --- -start | ys:date-and-time | Timestamp of when the consumption of reserved resources can begin -end | ys:date-and-time | Timestamp of when the consumption of reserved resource must end -expiry | number | Duration expressed in seconds since `start` when resource not yet allocated shall be released back to the available zone -zone | nfvi:AvailabilityZone | Reference to a zone where the resources will be reserved -capacity | object | Quantity of resources to be reserved per resource types -attributes | list | References to resource attributes needed for reservation -resources | list (nfvi:ResourceElement) | Reference to a collection of existing resource elements required - -#### State Elements (read-only) - -State Elements are available as part of lookup response about the data model. - -Name | Type | Description ---- | --- | --- -provider | nfvi:ResourceProvider | Reference to a specific provider when reservation service supports multiple providers -remaining | object | Quantity of resources remaining for consumption based on consumed allocations -allocations | list (nfvi:ResourceAllocation) | Reference to a collection of consumed allocations referencing this reservation - -#### Notification Elements - -Name | Type | Description ---- | --- | --- -reservation-event | Event | Subscribers will be notified if the reservation encounters an error or other events - -#### Inherited Elements - -##### Extended from [nfvi:ResourceElement](schema/nfv-infrastructure.yang) - -Name | Type | Description ---- | --- | --- -id | yang:uuid | A GUID identifier for the data model (usually auto-generated, but can also be specified) -name | string | Name of the data model -enabled | boolean | Enable/Disable the data model -protected | boolean | Prevent model from being destroyed when protected -owner | nfvi:AccessIdentity | An owner for the data model -visibility | enumeration | Visibility level of the given data model -tags | list (string) | List of string tags for query/filter -members | list (nfvi:AccessIdentity) | List of additional AccessIdentities that can operate on the data model - -### Resource Allocation - -The data model describing the required parameters regarding a resource -allocation. The schema definition expressed in YANG can be found -[here](schema/opnfv-promise.yang). - -#### Key Elements - -Name | Type | Description ---- | --- | --- -reservation | nfvi:ResourceReservation | Reference to an existing reservation identifier -allocate-on-start | boolean | Specify whether the allocation can take effect automatically upon reservation 'start' -resources | list (nfvi:ResourceElement) | Reference to a collection of new resource elements to be allocated - -#### State Elements (read-only) - -Name | Type | Description ---- | --- | --- -priority | number | Read-only state information about the priority classification of the reservation - -#### Inherited Elements - -##### Extended from [nfvi:ResourceElement](schema/nfv-infrastructure.yang) - -Name | Type | Description ---- | --- | --- -id | yang:uuid | A GUID identifier for the data model (usually auto-generated, but can also be specified) -name | string | Name of the data model -enabled | boolean | Enable/Disable the data model -protected | boolean | Prevent model from being destroyed when protected -owner | nfvi:AccessIdentity | An owner for the data model -visibility | enumeration | Visibility level of the given data model -tags | list (string) | List of string tags for query/filter -members | list (nfvi:AccessIdentity) | List of additional AccessIdentities that can operate on the data model - -## License - [Apache-2.0](LICENSE) diff --git a/source/config/custom-environment-variables.yaml b/source/config/custom-environment-variables.yaml deleted file mode 100644 index 001e799..0000000 --- a/source/config/custom-environment-variables.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# OPNFV FuncTest config (refer to schema/opnfv-functest.yang) -opnfv-functest: - environment: - installer: - type: INSTALLER_TYPE - address: INSTALLER_IP - lab: NODE_NAME - -# OpenStack config (native) -openstack: - auth: - endpoint: OS_AUTH_URL - strategy: OS_AUTH_STRATEGY - project: - id: OS_PROJECT_ID - name: OS_PROJECT_NAME - domain-name: OS_PROJECT_DOMAIN_NAME - username: OS_USERNAME - password: OS_PASSWORD - user-domain-name: OS_USER_DOMAIN_NAME - test: - image: OS_TEST_IMAGE - flavor: OS_TEST_FLAVOR - network: OS_TEST_NETWORK - diff --git a/source/config/default.yaml b/source/config/default.yaml deleted file mode 100644 index 52bb61a..0000000 --- a/source/config/default.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# default configuration for 'npm test' - -opnfv-promise: - promise: - policy: - reservation: - max-future-start-range: - max-future-end-range: - max-duration: - expiry: 600 - diff --git a/source/config/demo.json b/source/config/demo.json deleted file mode 100644 index dffb3af..0000000 --- a/source/config/demo.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "opnfv-promise": { - "promise": { - "providers": [ - { - "name": "example-demo-provider", - "token": "dummy-token" - } - ], - "pools": [ - { - "ResourcePool": { - "id": "4085f0da-8030-4252-a0ff-c6f93870eb5f", - "name": "OPNFV OpenStack - West", - "source": "example-demo-provider", - "capacity": { - "cores": 100, - "ram": 262144, - "instances": 500, - "networks": 100, - "ports": 100, - "routers": 30, - "subnets": 1000, - "addresses": 500, - "gigabytes": 10000, - "snapshots": 100, - "volumes": 100 - } - } - } - ], - "reservations": [ - { - "capacity": { - "cores": 10, - "ram": 4096, - "instances": 10, - "networks": 4, - "ports": 10, - "routers": 1, - "subnets": 1, - "addresses": 10, - "gigabytes": 0, - "snapshots": 0, - "volumes": 0 - }, - "start": "2015-11-07T10:17:12.747Z", - "end": "2016-02-13T10:17:18.226Z", - "pools": [ - "4085f0da-8030-4252-a0ff-c6f93870eb5f" - ] - }, - { - "capacity": { - "cores": 20, - "ram": 10000, - "instances": 5, - "networks": 2, - "ports": 10, - "routers": 1, - "subnets": 1, - "addresses": 5, - "gigabytes": 0, - "snapshots": 0, - "volumes": 0 - }, - "start": "2015-11-09T10:17:12.747Z", - "end": "2016-02-11T10:17:18.226Z", - "pools": [ - "4085f0da-8030-4252-a0ff-c6f93870eb5f" - ] - }, - { - "id": "c7287f30-2c65-4a88-a047-48724b8ff747", - "capacity": { - "cores": 10, - "ram": 4096, - "instances": 10, - "networks": 5, - "ports": 10, - "routers": 1, - "subnets": 5, - "addresses": 20, - "gigabytes": 0, - "snapshots": 0, - "volumes": 0 - }, - "start": "2015-11-10T10:17:12.747Z", - "end": "2015-12-13T10:17:18.226Z", - "pools": [ - "4085f0da-8030-4252-a0ff-c6f93870eb5f" - ] - }, - { - "id": "0f2e31f7-9760-416d-8d53-1ee68aa4b11f", - "capacity": { - "cores": 10, - "ram": 4096, - "instances": 5, - "networks": 2, - "ports": 10, - "routers": 1, - "subnets": 1, - "addresses": 5, - "gigabytes": 0, - "snapshots": 0, - "volumes": 0 - }, - "start": "2015-11-09T10:17:12.747Z", - "end": "2015-12-03T10:17:18.226Z", - "pools": [ - "4085f0da-8030-4252-a0ff-c6f93870eb5f" - ] - } - ] - } - } -} diff --git a/source/config/functest.yaml b/source/config/functest.yaml deleted file mode 100644 index 6655fc4..0000000 --- a/source/config/functest.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# NODE_ENV=functest - -opnfv-functest: - environment: - images: - - - name: cirros - path: /home/opnfv/functest/images/cirros-0.3.5-x86_64-disk.img - diff --git a/source/config/test-intercloud.yaml b/source/config/test-intercloud.yaml deleted file mode 100644 index f5e04ed..0000000 --- a/source/config/test-intercloud.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# the following config is used when ENV is as follows: -# NODE_ENV=test -# NODE_APP_INSTANCE=intercloud -openstack: - auth: - strategy: keystone - endpoint: http://vhub4.intercloud.net:5000/v2.0 - tenant: - id: 62a2d90992114994977fd6707bac5758 - username: peter - password: # set OS_PASSWORD=xxxx environmental variable - test: - image: ee0fb445-0fc2-4fda-a2dc-175bf3cc3cb1 - flavor: 2312fd98-369e-4361-b967-606373891c11 - -opnfv-promise: - promise: - policy: - reservation: - max-future-start-range: 7 - max-duration: 24 diff --git a/source/forge.yaml b/source/forge.yaml deleted file mode 100644 index d8d1f39..0000000 --- a/source/forge.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# - -# YF 0.12.x forge manifest - -compilers: - yang: yangforge/register - coffee: coffee-script/register - -components: - nfvi: - - yangforge:common - - schema/access-control-models.yang - - schema/nfv-infrastructure.yang - - schema/nfv-mano.yang - - # primary promise service - promise: - - nfvi - - schema/opnfv-promise.yang - - spec/promise.yaml - - # base openstack composition - openstack: - - nfvi - - schema/openstack.yang - - schema/openstack-identity.yang - - schema/openstack-image.yang - - schema/openstack-compute.yang - - schema/openstack-storage.yang - - schema/openstack-network.yang - - spec/openstack.yaml - - # openstack with promise augmentation - os-promise: - - promise - - openstack - - schema/openstack-promise.yang - - spec/openstack-promise.yaml - - # test component for using with 'npm test' - test: - - os-promise - - schema/opnfv-functest.yang - - config/demo.json diff --git a/source/index.yaml b/source/index.yaml deleted file mode 100644 index 071d685..0000000 --- a/source/index.yaml +++ /dev/null @@ -1,4120 +0,0 @@ -synth: source -name: opnfv-promise -version: ! '' -description: Resource Management for Virtualized Infrastructure -license: Apache-2.0 -schema: - module: - opnfv-promise: - namespace: 'urn:opnfv:promise' - prefix: promise - import: - complex-types: - prefix: ct - ietf-yang-types: - prefix: yang - ietf-inet-types: - prefix: inet - access-control-models: - prefix: acm - nfv-infrastructure: - prefix: nfvi - description: OPNFV Promise Resource Reservation/Allocation controller module - revision: - '2015-10-05': - description: Complete coverage of reservation related intents - '2015-08-06': - description: Updated to incorporate YangForge framework - '2015-04-16': - description: Initial revision. - feature: - reservation-service: - description: 'When enabled, provides resource reservation service' - multi-provider: - description: 'When enabled, provides resource management across multiple providers' - grouping: - resource-utilization: - container: - capacity: - container: - total: - description: Conceptual container that should be extended - reserved: - description: Conceptual container that should be extended - config: false - usage: - description: Conceptual container that should be extended - config: false - available: - description: Conceptual container that should be extended - config: false - temporal-resource-collection: - description: Information model capturing resource-collection with start/end time window - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - resource-usage-request: - description: |- - Information model capturing available parameters to make a resource - usage request. - reference: 'OPNFV-PROMISE, Section 3.4.1' - uses: {} - leaf: - zone: - description: Optional identifier to an Availability Zone - type: - instance-identifier: - 'ct:instance-type': 'nfvi:AvailabilityZone' - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - description: |- - Reference to a list of 'pre-existing' resource elements that are - required for fulfillment of the resource-usage-request. - - It can contain any instance derived from ResourceElement, - such as ServerInstances or even other - ResourceReservations. If the resource-usage-request is - accepted, the ResourceElement(s) listed here will be placed - into 'protected' mode as to prevent accidental removal. - - If any of these resource elements become 'unavailable' due to - environmental or administrative activity, a notification will - be issued informing of the issue. - query-start-end-window: - container: - window: - description: Matches entries that are within the specified start/end time window - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - scope: - type: - enumeration: - enum: - exclusive: - description: Matches entries that start AND end within the window - value: 0 - inclusive: - description: Matches entries that start OR end within the window - value: 1 - default: inclusive - query-resource-collection: - uses: {} - leaf-list: - without: - description: Excludes specified collection identifiers from the result - type: - instance-identifier: - 'ct:instance-type': ResourceCollection - leaf: - show-utilization: - type: boolean - default: 'true' - container: - elements: - leaf-list: - some: - description: Query for ResourceCollection(s) that contain some or more of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - every: - description: Query for ResourceCollection(s) that contain all of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - window: - description: Matches entries that are within the specified start/end time window - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - scope: - type: - enumeration: - enum: - exclusive: - description: Matches entries that start AND end within the window - value: 0 - inclusive: - description: Matches entries that start OR end within the window - value: 1 - default: inclusive - common-intent-output: - leaf: - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - utilization-output: - list: - utilization: - key: timestamp - leaf: - timestamp: - type: 'yang:date-and-time' - count: - type: int16 - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - 'ct:complex-type': - ResourceCollection: - 'ct:extends': 'nfvi:ResourceContainer' - 'ct:abstract': 'true' - description: |- - Describes an abstract ResourceCollection data model, which represents - a grouping of capacity and elements available during a given - window in time which must be extended by other resource - collection related models - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - active: - config: false - description: |- - Provides current state of this record whether it is enabled and within - specified start/end time - type: boolean - ResourcePool: - 'ct:extends': ResourceCollection - description: |- - Describes an instance of an active ResourcePool record, which - represents total available capacity and elements from a given - source. - leaf: - source: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceContainer' - require-instance: true - mandatory: true - refine: - elements: - must: - 'boolean(/source/elements/*[@id=id])': - error-message: One or more of the ResourceElement(s) does not exist in the provider to be reserved - ResourceReservation: - 'ct:extends': ResourceCollection - description: |- - Describes an instance of an accepted resource reservation request, - created usually as a result of 'create-reservation' request. - - A ResourceReservation is a derived instance of a generic - ResourceCollection which has additional parameters to map the - pool(s) that were referenced to accept this reservation as well - as to track allocations made referencing this reservation. - - Contains the capacities of various resource attributes being - reserved along with any resource elements that are needed to be - available at the time of allocation(s). - reference: 'OPNFV-PROMISE, Section 3.4.1' - leaf: - created-on: - type: 'yang:date-and-time' - config: false - modified-on: - type: 'yang:date-and-time' - config: false - leaf-list: - pools: - config: false - description: |- - Provides list of one or more pools that were referenced for providing - the requested resources for this reservation. This is an - important parameter for informing how/where allocation - requests can be issued using this reservation since it is - likely that the total reserved resource capacity/elements are - made availble from multiple sources. - type: - instance-identifier: - 'ct:instance-type': ResourcePool - require-instance: true - allocations: - config: false - description: |- - Reference to a collection of consumed allocations referencing - this reservation. - type: - instance-identifier: - 'ct:instance-type': ResourceAllocation - require-instance: true - container: - remaining: - config: false - description: |- - Provides visibility into total remaining capacity for this - reservation based on allocations that took effect utilizing - this reservation ID as a reference. - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - ResourceAllocation: - 'ct:extends': ResourceCollection - description: |- - A ResourceAllocation record denotes consumption of resources from a - referenced ResourcePool. - - It does not reflect an accepted request but is created to - represent the actual state about the ResourcePool. It is - created once the allocation(s) have successfully taken effect - on the 'source' of the ResourcePool. - - The 'priority' state indicates the classification for dealing - with resource starvation scenarios. Lower priority allocations - will be forcefully terminated to allow for higher priority - allocations to be fulfilled. - - Allocations without reference to an existing reservation will - receive the lowest priority. - reference: 'OPNFV-PROMISE, Section 3.4.3' - leaf: - reservation: - description: Reference to an existing reservation identifier (optional) - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - require-instance: true - pool: - description: Reference to an existing resource pool from which allocation is drawn - type: - instance-identifier: - 'ct:instance-type': ResourcePool - require-instance: true - priority: - config: false - description: Reflects current priority level of the allocation according to classification rules - type: - enumeration: - enum: - high: - value: 1 - normal: - value: 2 - low: - value: 3 - default: normal - container: - instance-ref: - config: false - description: Reference to actual instance identifier of the provider/server for this allocation - leaf: - provider: - type: - instance-identifier: - 'ct:instance-type': ResourceProvider - server: - type: 'yang:uuid' - ResourceFlavor: - description: currently NOT an extension of ResourceElement. - key: id - leaf: - id: - type: string - name: - type: string - disk: - type: uint32 - units: GB - default: '0' - ram: - type: uint32 - units: MB - default: '0' - vcpus: - type: uint16 - default: '0' - ResourceProvider: - 'ct:extends': 'nfvi:ResourceContainer' - leaf: - token: - type: string - mandatory: true - container: - services: - config: false - container: - compute: - leaf: - endpoint: - type: 'inet:uri' - 'ct:instance-list': - flavors: - 'ct:instance-type': ResourceFlavor - leaf-list: - pools: - config: false - description: Provides list of one or more pools that are referencing this provider. - type: - instance-identifier: - 'ct:instance-type': ResourcePool - require-instance: true - container: - promise: - uses: {} - 'ct:instance-list': - providers: - if-feature: multi-provider - description: Aggregate collection of all registered ResourceProvider instances for Promise resource management service - 'ct:instance-type': ResourceProvider - status: unavailable - pools: - if-feature: reservation-service - description: Aggregate collection of all ResourcePool instances - 'ct:instance-type': ResourcePool - status: unavailable - reservations: - if-feature: reservation-service - description: Aggregate collection of all ResourceReservation instances - 'ct:instance-type': ResourceReservation - status: unavailable - allocations: - description: Aggregate collection of all ResourceAllocation instances - 'ct:instance-type': ResourceAllocation - container: - policy: - container: - reservation: - leaf: - max-future-start-range: - description: "Enforce reservation request 'start' time is within allowed range from now" - type: - uint16: - range: 0..365 - units: days - max-future-end-range: - description: "Enforce reservation request 'end' time is within allowed range from now" - type: - uint16: - range: 0..365 - units: days - max-duration: - description: Enforce reservation duration (end-start) does not exceed specified threshold - type: uint16 - units: hours - default: '8760' - expiry: - description: |- - Duration in minutes from start when unallocated reserved resources - will be released back into the pool - type: uint32 - units: minutes - capacity: - container: - total: - description: Conceptual container that should be extended - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - reserved: - description: Conceptual container that should be extended - config: false - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - usage: - description: Conceptual container that should be extended - config: false - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - available: - description: Conceptual container that should be extended - config: false - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - rpc: - create-reservation: - if-feature: reservation-service - description: Make a request to the reservation system to reserve resources - input: - uses: {} - leaf: - zone: - description: Optional identifier to an Availability Zone - type: - instance-identifier: - 'ct:instance-type': 'nfvi:AvailabilityZone' - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - description: |- - Reference to a list of 'pre-existing' resource elements that are - required for fulfillment of the resource-usage-request. - - It can contain any instance derived from ResourceElement, - such as ServerInstances or even other - ResourceReservations. If the resource-usage-request is - accepted, the ResourceElement(s) listed here will be placed - into 'protected' mode as to prevent accidental removal. - - If any of these resource elements become 'unavailable' due to - environmental or administrative activity, a notification will - be issued informing of the issue. - output: - leaf: - reservation-id: - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - status: unavailable - update-reservation: - description: Update reservation details for an existing reservation - input: - leaf: - reservation-id: - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - require-instance: true - mandatory: true - zone: - description: Optional identifier to an Availability Zone - type: - instance-identifier: - 'ct:instance-type': 'nfvi:AvailabilityZone' - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - uses: {} - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - description: |- - Reference to a list of 'pre-existing' resource elements that are - required for fulfillment of the resource-usage-request. - - It can contain any instance derived from ResourceElement, - such as ServerInstances or even other - ResourceReservations. If the resource-usage-request is - accepted, the ResourceElement(s) listed here will be placed - into 'protected' mode as to prevent accidental removal. - - If any of these resource elements become 'unavailable' due to - environmental or administrative activity, a notification will - be issued informing of the issue. - output: - leaf: - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - cancel-reservation: - description: Cancel the reservation and be a good steward - input: - leaf: - reservation-id: - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - mandatory: true - output: - leaf: - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - query-reservation: - if-feature: reservation-service - description: Query the reservation system to return matching reservation(s) - input: - leaf: - zone: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:AvailabilityZone' - show-utilization: - type: boolean - default: 'true' - uses: {} - leaf-list: - without: - description: Excludes specified collection identifiers from the result - type: - instance-identifier: - 'ct:instance-type': ResourceCollection - container: - elements: - leaf-list: - some: - description: Query for ResourceCollection(s) that contain some or more of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - every: - description: Query for ResourceCollection(s) that contain all of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - window: - description: Matches entries that are within the specified start/end time window - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - scope: - type: - enumeration: - enum: - exclusive: - description: Matches entries that start AND end within the window - value: 0 - inclusive: - description: Matches entries that start OR end within the window - value: 1 - default: inclusive - output: - leaf-list: - reservations: - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - list: - utilization: - key: timestamp - leaf: - timestamp: - type: 'yang:date-and-time' - count: - type: int16 - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - status: unavailable - increase-capacity: - description: Increase total capacity for the reservation system between a window in time - input: - leaf: - source: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceContainer' - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - output: - leaf: - pool-id: - type: - instance-identifier: - 'ct:instance-type': ResourcePool - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - decrease-capacity: - description: Decrease total capacity for the reservation system between a window in time - input: - leaf: - source: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceContainer' - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - output: - leaf: - pool-id: - type: - instance-identifier: - 'ct:instance-type': ResourcePool - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - query-capacity: - description: Check available capacity information about a specified resource collection - input: - leaf: - capacity: - type: - enumeration: - enum: - total: - value: 0 - reserved: - value: 1 - usage: - value: 2 - available: - value: 3 - default: available - zone: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:AvailabilityZone' - show-utilization: - type: boolean - default: 'true' - uses: {} - leaf-list: - without: - description: Excludes specified collection identifiers from the result - type: - instance-identifier: - 'ct:instance-type': ResourceCollection - container: - elements: - leaf-list: - some: - description: Query for ResourceCollection(s) that contain some or more of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - every: - description: Query for ResourceCollection(s) that contain all of these element(s) - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - window: - description: Matches entries that are within the specified start/end time window - leaf: - start: - type: 'yang:date-and-time' - end: - type: 'yang:date-and-time' - scope: - type: - enumeration: - enum: - exclusive: - description: Matches entries that start AND end within the window - value: 0 - inclusive: - description: Matches entries that start OR end within the window - value: 1 - default: inclusive - output: - leaf-list: - collections: - type: - instance-identifier: - 'ct:instance-type': ResourceCollection - list: - utilization: - key: timestamp - leaf: - timestamp: - type: 'yang:date-and-time' - count: - type: int16 - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - create-instance: - description: Create an instance of specified resource(s) utilizing capacity from the pool - input: - leaf: - provider-id: - if-feature: multi-provider - type: - instance-identifier: - 'ct:instance-type': ResourceProvider - require-instance: true - status: unavailable - name: - type: string - mandatory: true - image: - type: - union: - type: - 'yang:uuid': null - 'inet:uri': null - mandatory: true - flavor: - type: - union: - type: - 'yang:uuid': null - 'inet:uri': null - mandatory: true - reservation-id: - type: - instance-identifier: - 'ct:instance-type': ResourceReservation - require-instance: true - output: - leaf: - instance-id: - type: - instance-identifier: - 'ct:instance-type': ResourceAllocation - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - destroy-instance: - description: Destroy an instance of resource utilization and release it back to the pool - input: - leaf: - instance-id: - type: - instance-identifier: - 'ct:instance-type': ResourceAllocation - require-instance: true - output: - leaf: - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - add-provider: - description: Register a new resource provider into reservation system - input: - leaf: - provider-type: - description: Select a specific resource provider type - mandatory: true - type: - enumeration: - enum: - openstack: - value: 0 - hp: - value: 1 - rackspace: - value: 2 - amazon: - status: planned - value: 3 - joyent: - status: planned - value: 4 - azure: - status: planned - value: 5 - default: openstack - strategy: - type: - enumeration: - enum: - oauth: - value: 0 - keystone: - value: 1 - default: keystone - endpoint: - type: 'inet:uri' - description: The target endpoint for authentication - mandatory: true - default: 'http://localhost:5000/v2.0' - username: - type: string - mandatory: true - password: - type: 'acm:password' - mandatory: true - uses: {} - container: - tenant: - leaf: - id: - type: string - name: - type: string - output: - leaf: - provider-id: - type: - instance-identifier: - 'ct:instance-type': ResourceProvider - result: - type: - enumeration: - enum: - ok: - value: 0 - conflict: - value: 1 - error: - value: 2 - message: - type: string - notification: - reservation-event: null - capacity-event: null - allocation-event: null -dependencies: - access-control-models: - module: - access-control-models: - prefix: acm - namespace: 'urn:opnfv:promise:acm' - import: - complex-types: - prefix: ct - ietf-yang-types: - prefix: yang - ietf-inet-types: - prefix: inet - typedef: - password: - type: - string: - length: 1..255 - grouping: - access-credentials: - leaf: - strategy: - type: - enumeration: - enum: - oauth: - value: 0 - keystone: - value: 1 - default: oauth - endpoint: - type: 'inet:uri' - description: The target endpoint for authentication - mandatory: true - username: - type: string - mandatory: true - password: - type: 'acm:password' - mandatory: true - 'ct:complex-type': - Identity: - 'ct:abstract': 'true' - description: Identity represents an administrative access model entity - key: id - leaf: - id: - type: 'yang:uuid' - mandatory: true - name: - type: string - mandatory: true - description: - type: string - enabled: - type: boolean - default: 'true' - User: - 'ct:extends': Identity - leaf: - credential: - type: string - mandatory: true - domain: - type: - instance-identifier: - 'ct:instance-type': Domain - container: - contact: - leaf: - fullName: - type: string - email: - type: string - leaf-list: - groups: - type: - instance-identifer: - 'ct:instance-type': Group - Group: - 'ct:extends': Identity - leaf-list: - users: - type: - instance-identifier: - 'ct:instance-type': User - leaf: - domain: - type: - instance-identifier: - 'ct:instance-type': Domain - Domain: - 'ct:extends': Identity - description: |- - Domain represent a distinct administrative domain across - collection of users and groups. - 'ct:instance-list': - users: - 'ct:instance-type': User - groups: - 'ct:instance-type': Group - rpc: - create-user: null - remove-user: null - create-group: null - remove-group: null - nfv-infrastructure: - module: - nfv-infrastructure: - namespace: 'urn:opnfv:promise:nfv:infrastructure' - prefix: nfvi - import: - access-control-models: - prefix: acm - ietf-inet-types: - prefix: inet - ietf-yang-types: - prefix: yang - complex-types: - prefix: ct - description: |- - NFV Infrastructure Data Models with complex types and typed instance - identifiers representing the various ResourceElements available - in the infrastructure across compute, network, and storage. - revision: - '2015-10-13': - description: Introduce capacity and element collection into NFVI models - '2015-08-07': - description: |- - This YANG module is modeled using 'yangforge' which natively provides - complex types and typed instance identifiers. This module - provides various collections of resource management data models - for instance based management - identity: - manager: - description: used by specific modules implementing manager role for NFVI - grouping: - compute-capacity: - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - network-capacity: - leaf: - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - storage-capacity: - leaf: - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - resource-capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - resource-collection: - description: |- - Information model capturing parameters for describing a collection of - resource capacity and resource elements - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - resource-stack: - description: |- - Information model describing a NFVI resource stack comprising of - various resource elements across compute, network, and storage - 'ct:instance-list': - hosts: - 'ct:instance-type': 'nfvi:PhysicalHost' - hypervisors: - 'ct:instance-type': 'nfvi:Hypervisor' - container: - compute: - description: Contains compute related resources - 'ct:instance-list': - servers: - 'ct:instance-type': 'nfvi:ServerInstance' - images: - 'ct:instance-type': 'nfvi:VirtualMachineImage' - flavors: - 'ct:instance-type': 'nfvi:ComputeFlavor' - network: - description: Contains networking related resources - 'ct:instance-list': - networks: - 'ct:instance-type': 'nfvi:Network' - subnets: - 'ct:instance-type': 'nfvi:SubNetwork' - ports: - 'ct:instance-type': 'nfvi:SwitchPort' - 'ct:complex-type': - ResourceElement: - 'ct:abstract': 'true' - key: id - leaf: - id: - type: 'yang:uuid' - mandatory: true - name: - type: string - enabled: - type: boolean - default: 'true' - protected: - type: boolean - default: 'false' - owner: - type: - instance-identifier: - 'ct:instance-type': 'acm:Identity' - visibility: - description: "Specify visibility level available from the perspective of 'owner'" - type: - enumeration: - enum: - public: - value: 0 - domain: - value: 1 - project: - value: 2 - group: - value: 3 - user: - value: 4 - default: user - leaf-list: - tags: - type: string - members: - description: Optionally share with explicit list of members of AccessIdentity complex-type - type: - instance-identifier: - 'ct:instance-type': 'acm:Identity' - ResourceInstance: - 'ct:extends': ResourceElement - 'ct:abstract': 'true' - leaf: - status: - type: - enumeration: - enum: - active: - value: 0 - inactive: - value: 1 - pending: - value: 2 - progress: - type: - uint8: - range: 0..100 - default: '0' - ResourceContainer: - 'ct:extends': ResourceInstance - 'ct:abstract': 'true' - description: |- - An abstract resource instance which contains a collection of capacity - and elements. - container: - capacity: - uses: {} - leaf: - cores: - type: int16 - default: '0' - ram: - type: int32 - default: '0' - units: MB - instances: - type: int16 - default: '0' - networks: - type: int16 - default: '0' - ports: - type: int16 - default: '0' - routers: - type: int16 - default: '0' - subnets: - type: int16 - default: '0' - addresses: - type: int32 - default: '0' - gigabytes: - type: int32 - default: '0' - units: GB - snapshots: - type: int16 - default: '0' - volumes: - type: int16 - default: '0' - leaf-list: - elements: - type: - instance-identifier: - 'ct:instance-type': 'nfvi:ResourceElement' - require-instance: true - AvailabilityZone: - 'ct:extends': ResourceElement - PhysicalHost: - 'ct:extends': ResourceElement - leaf: - type: - type: string - version: - type: string - cpu: - type: uint8 - workload: - type: uint8 - default: '0' - uptime: - type: string - container: - ram: - leaf: - total: - type: uint32 - units: MB - used: - type: uint32 - units: MB - free: - type: uint32 - units: MB - disk: - leaf: - total: - type: uint32 - units: GB - used: - type: uint32 - units: GB - free: - type: uint32 - units: GB - leaf-list: - hypervisors: - type: - instance-identifier: - 'ct:instance-type': Hypervisor - Hypervisor: - 'ct:extends': PhysicalHost - leaf: - host: - type: - instance-identifier: - 'ct:instance-type': PhysicalHost - mandatory: true - container: - vcpu: - leaf: - total: - type: uint16 - used: - type: uint16 - free: - type: uint16 - leaf-list: - servers: - type: - instance-identifier: - 'ct:instance-type': ServerInstance - ComputeElement: - 'ct:extends': ResourceElement - 'ct:abstract': 'true' - container: - constraint: - leaf: - disk: - type: uint32 - units: GB - default: '0' - ram: - type: uint32 - units: MB - default: '0' - vcpu: - type: uint16 - default: '0' - leaf-list: - instances: - description: State info about instances currently using this resource element - type: - instance-identifier: - 'ct:instance-type': ResourceInstance - config: false - VirtualMachineImage: - 'ct:extends': ComputeElement - container: - data: - leaf: - checksum: - type: string - mandatory: true - size: - type: uint32 - units: Bytes - mandatory: true - content: - description: "should be a 'private' property so only direct access retrieves content" - type: binary - container: - format: - leaf: - container: - type: - enumeration: - enum: - ami: - value: 0 - ari: - value: 1 - aki: - value: 2 - bare: - value: 3 - ovf: - value: 4 - default: bare - disk: - type: - enumeration: - enum: - ami: - value: 0 - ari: - value: 1 - aki: - value: 2 - vhd: - value: 3 - vmdk: - value: 4 - raw: - value: 5 - qcow2: - value: 6 - vdi: - value: 7 - iso: - value: 8 - ComputeFlavor: - 'ct:extends': ResourceElement - leaf: - disk: - type: uint32 - units: GB - default: '0' - ram: - type: uint32 - units: MB - default: '0' - vcpus: - type: uint16 - default: '0' - ServerInstance: - 'ct:extends': ResourceInstance - leaf: - flavor: - type: - instance-identifier: - 'ct:instance-type': ComputeFlavor - mandatory: true - image: - type: - instance-identifier: - 'ct:instance-type': VirtualMachineImage - mandatory: true - host: - type: - instance-identifier: - 'ct:instance-type': PhysicalHost - leaf-list: - connections: - description: |- - References to collection of NetworkingElement class objects such as - Network, Subnet, Port, Router that this ServerInstance is - connected with. - type: - instance-identifier: - 'ct:instance-type': NetworkElement - NetworkElement: - 'ct:extends': ResourceElement - 'ct:abstract': 'true' - Network: - 'ct:extends': NetworkElement - leaf-list: - subnets: - type: - instance-identifier: - 'ct:instance-type': SubNetwork - SubNetwork: - 'ct:extends': NetworkElement - leaf: - network: - type: - instance-identifier: - 'ct:instance-type': Network - leaf-list: - nameservers: - type: string - container: - dhcp: - leaf: - enabled: - type: boolean - list: - pools: - leaf: - start: - type: 'inet:ip-address' - end: - type: 'inet:ip-address' - SwitchPort: - 'ct:extends': NetworkElement - leaf: - subnet: - type: - instance-identifier: - 'ct:instance-type': SubNetwork -extension: - module: - argument: name - include: 0..n - prefix: 0..1 - anyxml: 0..n - augment: 0..n - choice: 0..n - contact: 0..1 - container: 0..n - description: 0..1 - deviation: 0..n - extension: 0..n - feature: 0..n - grouping: 0..n - identity: 0..n - import: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - namespace: 0..1 - notification: 0..n - organization: 0..1 - reference: 0..1 - revision: 0..n - rpc: 0..n - typedef: 0..n - uses: 0..n - yang-version: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var changes, match, ref, synth, target; - synth = this.require('data-synth'); - ref = params.augment; - for (target in ref) { - changes = ref[target]; - match = this.locate(ctx, target); - if (match == null) { - continue; - } - synth.copy(match, changes); - } - return delete this.source[params.prefix]; - } - construct: ! |- - function (arg, params, children, ctx, self) { - return (self.origin.construct.apply(this, arguments)).merge({ - models: this.resolve('complex-type') - }); - } - complex-type: 0..n - instance: 0..n - instance-list: 0..n - origin: - argument: name - include: 0..n - prefix: 0..1 - anyxml: 0..n - augment: 0..n - choice: 0..n - contact: 0..1 - container: 0..n - description: 0..1 - deviation: 0..n - extension: 0..n - feature: 0..n - grouping: 0..n - identity: 0..n - import: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - namespace: 0..1 - notification: 0..n - organization: 0..1 - reference: 0..1 - revision: 0..n - rpc: 0..n - typedef: 0..n - uses: 0..n - yang-version: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var changes, match, ref, synth, target; - synth = this.require('data-synth'); - ref = params.augment; - for (target in ref) { - changes = ref[target]; - match = this.locate(ctx, target); - if (match == null) { - continue; - } - synth.copy(match, changes); - } - return delete this.source[params.prefix]; - } - construct: ! |- - function (arg, params, children) { - var k, m, modules, ref, synth, v; - synth = this.require('data-synth'); - modules = {}; - ref = params["import"]; - for (k in ref) { - v = ref[k]; - modules[k] = children[k]; - delete children[k]; - } - m = (synth.Store(params, function() { - return this.set({ - name: arg, - modules: modules - }); - })).bind(children); - this.define('module', arg, m); - return m; - } - prefix: - argument: value - preprocess: ! |- - function (arg, params, ctx) { - return this.source[arg] = this.source; - } - include: - argument: module - preprocess: ! |- - function (arg, params, ctx) { - var k, m, ref, ref1, ref2, results, v; - m = this.preprocess(this.resolve('dependencies', arg)); - ref = m.extension; - for (k in ref) { - v = ref[k]; - this.define('extension', k, v); - } - ref1 = m.typedef; - for (k in ref1) { - v = ref1[k]; - this.define('typedef', k, v); - } - ref2 = m.schema; - results = []; - for (k in ref2) { - v = ref2[k]; - results.push(ctx[k] = v); - } - return results; - } - revision-date: 0..1 - augment: - anyxml: 0..n - case: 0..n - choice: 0..n - container: 0..n - description: 0..1 - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - reference: 0..1 - status: 0..1 - uses: 0..n - when: 0..1 - argument: target-node - belongs-to: - prefix: 1 - preprocess: ! |- - function (arg, params, ctx) { - return this.source[params.prefix] = this.source; - } - argument: module - bit: - description: 0..1 - reference: 0..1 - status: 0..1 - position: 0..1 - argument: name - case: - anyxml: 0..n - choice: 0..n - container: 0..n - description: 0..1 - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - reference: 0..1 - status: 0..1 - uses: 0..n - when: 0..1 - argument: name - choice: - anyxml: 0..n - case: 0..n - config: 0..1 - container: 0..n - default: 0..1 - description: 0..1 - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - mandatory: 0..1 - reference: 0..1 - status: 0..1 - when: 0..1 - argument: condition - config: - preprocess: ! |- - function (arg, p, ctx) { - return ctx.config = arg === true || arg === 'true'; - } - argument: value - container: - anyxml: 0..n - choice: 0..n - config: 0..1 - container: 0..n - description: 0..1 - grouping: 0..n - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - must: 0..n - presence: 0..1 - reference: 0..1 - status: 0..1 - typedef: 0..n - uses: 0..n - when: 0..1 - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - argument: name - instance: 0..n - instance-list: 0..n - origin: - anyxml: 0..n - choice: 0..n - config: 0..1 - container: 0..n - description: 0..1 - grouping: 0..n - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - must: 0..n - presence: 0..1 - reference: 0..1 - status: 0..1 - typedef: 0..n - uses: 0..n - when: 0..1 - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - argument: name - deviate: - config: 0..1 - default: 0..1 - mandatory: 0..1 - max-elements: 0..1 - min-elements: 0..1 - must: 0..n - type: 0..1 - unique: 0..1 - units: 0..1 - argument: value - deviation: - description: 0..1 - deviate: 1..n - reference: 0..1 - argument: target-node - enum: - description: 0..1 - reference: 0..1 - status: 0..1 - value: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - if (params.value == null) { - if (this.enumValue == null) { - this.enumValue = 0; - } - params.value = this.enumValue++; - } else { - params.value = Number(params.value); - this.enumValue = params.value + 1; - } - return ctx["enum"][arg] = params; - } - argument: name - feature: - description: 0..1 - if-feature: 0..n - reference: 0..1 - status: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - if (params.status === 'unavailable') { - console.warn("feature " + arg + " is unavailable"); - if (typeof ctx.feature === 'object') { - return delete ctx.feature[arg]; - } else { - return delete ctx.feature; - } - } - } - construct: ! |- - function (arg, params, children) { - var feature; - feature = this.resolve('feature', arg); - return null; - } - argument: name - grouping: - anyxml: 0..n - choice: 0..n - container: 0..n - description: 0..1 - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - reference: 0..1 - status: 0..1 - typedef: 0..n - uses: 0..n - preprocess: ! |- - function (arg, params) { - return this.define('grouping', arg, params); - } - argument: name - instance: 0..n - instance-list: 0..n - origin: - anyxml: 0..n - choice: 0..n - container: 0..n - description: 0..1 - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - reference: 0..1 - status: 0..1 - typedef: 0..n - uses: 0..n - preprocess: ! |- - function (arg, params) { - return this.define('grouping', arg, params); - } - argument: name - identity: - base: 0..1 - description: 0..1 - reference: 0..1 - status: 0..1 - preprocess: ! |- - function (arg, params) { - return this.define('identity', arg, params); - } - argument: name - if-feature: - preprocess: ! |- - function (arg, params, ctx) { - if ((this.resolve('feature', arg)) == null) { - return ctx.status = 'unavailable'; - } - } - argument: name - import: - prefix: 1 - revision-date: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var copy, k, m, original, ref, ref1, rev, schema, source, synth, v; - synth = this.require('data-synth'); - schema = this.resolve('dependencies', arg, false); - if (schema == null) { - console.warn("no explicit dependency for " + arg + " defined, searching local filesystem"); - schema = this.parse("!yang " + arg + ".yang", this.source); - if (schema != null) { - this.define('dependencies', arg, schema); - source = this.source.parent; - while ((source.parent != null) && source.parent.name !== 'yangforge') { - source = source.parent; - } - if (source.dependencies == null) { - source.dependencies = {}; - } - source.dependencies[arg] = schema; - } - } - m = this.preprocess(schema); - if (m == null) { - throw this.error("unable to resolve '" + arg + "' in dependencies", 'import'); - } - rev = params['revision-date']; - if ((rev != null) && !(rev in m.revision)) { - throw this.error("requested " + rev + " not available in " + arg, 'import'); - } - ref = m.extension; - for (k in ref) { - v = ref[k]; - if (!(v.override === true)) { - continue; - } - original = this.resolve('extension', k); - copy = synth.copy({}, v); - copy.origin = synth.copy({}, (ref1 = original.origin) != null ? ref1 : original); - delete copy.override; - this.define('extension', k, copy); - } - return this.source[params.prefix] = m; - } - construct: ! |- - function (arg, params, children, ctx) { - return this.compile(this.source[params.prefix], this.source); - } - argument: module - input: - anyxml: 0..n - choice: 0..n - container: 0..n - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - typedef: 0..n - uses: 0..n - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - instance: 0..n - instance-list: 0..n - origin: - anyxml: 0..n - choice: 0..n - container: 0..n - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - typedef: 0..n - uses: 0..n - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - leaf: - config: 0..1 - default: 0..1 - description: 0..1 - if-feature: 0..n - mandatory: 0..1 - must: 0..n - reference: 0..1 - status: 0..1 - type: 0..1 - units: 0..1 - when: 0..1 - construct: ! |- - function (arg, params, children, ctx, self) { - var synth; - synth = this.require('data-synth'); - if (params.type['instance-identifier'] != null) { - return synth.BelongsTo(params, function() { - return this.set({ - model: children.type - }); - }); - } else { - return self.origin.construct.apply(this, arguments); - } - } - argument: name - origin: - config: 0..1 - default: 0..1 - description: 0..1 - if-feature: 0..n - mandatory: 0..1 - must: 0..n - reference: 0..1 - status: 0..1 - type: 0..1 - units: 0..1 - when: 0..1 - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return synth.Property(params, function() { - if (children.type != null) { - return this.set({ - type: children.type - }); - } - }); - } - argument: name - leaf-list: - config: 0..1 - description: 0..1 - if-feature: 0..n - max-elements: 0..1 - min-elements: 0..1 - must: 0..n - ordered-by: 0..1 - reference: 0..1 - status: 0..1 - type: 0..1 - units: 0..1 - when: 0..1 - construct: ! |- - function (arg, params, children, ctx, self) { - var synth; - synth = this.require('data-synth'); - if (params.type['instance-identifier'] != null) { - return synth.HasMany(params, function() { - return this.set({ - model: children.type - }); - }); - } else { - return self.origin.construct.apply(this, arguments); - } - } - argument: name - origin: - config: 0..1 - description: 0..1 - if-feature: 0..n - max-elements: 0..1 - min-elements: 0..1 - must: 0..n - ordered-by: 0..1 - reference: 0..1 - status: 0..1 - type: 0..1 - units: 0..1 - when: 0..1 - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return synth.List(params, function() { - if (children.type != null) { - return this.set({ - type: children.type - }); - } - }); - } - argument: name - list: - anyxml: 0..n - choice: 0..n - config: 0..1 - container: 0..n - description: 0..1 - grouping: 0..n - if-feature: 0..n - key: 0..1 - leaf: 0..n - leaf-list: 0..n - list: 0..n - max-elements: 0..1 - min-elements: 0..1 - must: 0..n - ordered-by: 0..1 - reference: 0..1 - status: 0..1 - typedef: 0..n - unique: 0..1 - uses: 0..n - when: 0..1 - construct: ! |- - function (arg, params, children) { - var item, synth; - synth = this.require('data-synth'); - item = (synth.Object(null)).bind(children); - return (synth.List(params)).set({ - type: item - }); - } - argument: name - mandatory: - preprocess: ! |- - function (arg, p, ctx) { - return ctx.mandatory = arg === true || arg === 'true'; - } - argument: value - max-elements: - preprocess: ! |- - function (arg, params, ctx) { - if (arg !== 'unbounded') { - return ctx['max-elements'] = Number(arg); - } - } - argument: value - min-elements: - preprocess: ! |- - function (arg, params, ctx) { - return ctx['min-elements'] = Number(arg); - } - argument: value - must: - description: 0..1 - error-app-tag: 0..1 - error-message: 0..1 - reference: 0..1 - argument: condition - notification: - anyxml: 0..n - choice: 0..n - container: 0..n - description: 0..1 - grouping: 0..n - if-feature: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - reference: 0..1 - status: 0..1 - typedef: 0..n - uses: 0..n - preprocess: ! |- - function (arg, params) { - return this.define('notification', arg, params); - } - argument: event - output: - anyxml: 0..n - choice: 0..n - container: 0..n - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - typedef: 0..n - uses: 0..n - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - instance: 0..n - instance-list: 0..n - origin: - anyxml: 0..n - choice: 0..n - container: 0..n - grouping: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - typedef: 0..n - uses: 0..n - construct: ! |- - function (arg, params, children) { - var synth; - synth = this.require('data-synth'); - return (synth.Object(params)).bind(children); - } - path: - preprocess: ! |- - function (arg, params, ctx) { - return ctx.path = arg.replace(/[_]/g, '.'); - } - argument: value - pattern: - construct: ! |- - function (arg, params, children, ctx) { - if (ctx.patterns == null) { - ctx.patterns = []; - } - return ctx.patterns.push(new RegExp(arg)); - } - argument: value - refine: - default: 0..1 - description: 0..1 - reference: 0..1 - config: 0..1 - mandatory: 0..1 - presence: 0..1 - must: 0..n - min-elements: 0..1 - max-elements: 0..1 - units: 0..1 - argument: target-node - require-instance: - preprocess: ! |- - function (arg, params, ctx) { - return ctx['require-instance'] = arg === true || arg === 'true'; - } - argument: value - revision: - description: 0..1 - reference: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - return this.define('revision', arg, params); - } - argument: date - rpc: - description: 0..1 - grouping: 0..n - if-feature: 0..n - input: 0..1 - output: 0..1 - reference: 0..1 - status: 0..1 - typedef: 0..n - construct: ! |- - function (arg, params, children) { - var func, method, ref, ref1, request, response, synth; - synth = this.require('data-synth'); - func = this.resolve('rpc', arg, false); - if (func == null) { - func = function(input, output, done) { - return done("No control logic found for '" + arg + "' rpc operation"); - }; - } - request = (ref = children.input) != null ? ref : synth.Meta; - response = (ref1 = children.output) != null ? ref1 : synth.Meta; - method = function(data, resolve, reject) { - var e, error, input, output; - if (typeof console.debug === "function") { - console.debug("executing rpc " + arg + "..."); - } - try { - input = new request(data, this); - output = new response(null, this); - } catch (error) { - e = error; - return reject(e); - } - return func.call(this, input, output, function(e) { - if (e == null) { - return resolve(output); - } else { - return reject(e); - } - }); - }; - method.params = params; - method.input = request; - method.output = response; - return method; - } - argument: name - submodule: - argument: name - anyxml: 0..n - augment: 0..n - belongs-to: 0..1 - choice: 0..n - contact: 0..1 - container: 0..n - description: 0..1 - deviation: 0..n - extension: 0..n - feature: 0..n - grouping: 0..n - identity: 0..n - import: 0..n - include: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - notification: 0..n - organization: 0..1 - reference: 0..1 - revision: 0..n - rpc: 0..n - typedef: 0..n - uses: 0..n - yang-version: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var k, v; - for (k in params) { - v = params[k]; - ctx[k] = v; - } - return delete ctx.submodule; - } - complex-type: 0..n - instance: 0..n - instance-list: 0..n - origin: - argument: name - anyxml: 0..n - augment: 0..n - belongs-to: 0..1 - choice: 0..n - contact: 0..1 - container: 0..n - description: 0..1 - deviation: 0..n - extension: 0..n - feature: 0..n - grouping: 0..n - identity: 0..n - import: 0..n - include: 0..n - leaf: 0..n - leaf-list: 0..n - list: 0..n - notification: 0..n - organization: 0..1 - reference: 0..1 - revision: 0..n - rpc: 0..n - typedef: 0..n - uses: 0..n - yang-version: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var k, v; - for (k in params) { - v = params[k]; - ctx[k] = v; - } - return delete ctx.submodule; - } - status: - preprocess: ! |- - function (arg, params, ctx) { - return ctx.status != null ? ctx.status : ctx.status = arg; - } - argument: value - type: - base: 0..1 - bit: 0..n - enum: 0..n - fraction-digits: 0..1 - length: 0..1 - path: 0..1 - pattern: 0..n - range: 0..1 - require-instance: 0..1 - type: 0..n - preprocess: ! |- - function (arg, params, ctx) { - return delete this.enumValue; - } - construct: ! |- - function (arg, params, children, ctx, self) { - if (children.ctype != null) { - ctx.type = children.ctype; - return null; - } else { - return self.origin.construct.apply(this, arguments); - } - } - argument: name - instance-type: 0..1 - origin: - base: 0..1 - bit: 0..n - enum: 0..n - fraction-digits: 0..1 - length: 0..1 - path: 0..1 - pattern: 0..n - range: 0..1 - require-instance: 0..1 - type: 0..n - preprocess: ! |- - function (arg, params, ctx) { - return delete this.enumValue; - } - construct: ! |- - function (arg, params, children, ctx) { - var key, mparams, ref, ref1, synth, typedef, value; - synth = this.require('data-synth'); - typedef = this.resolve('typedef', arg); - if (typedef == null) { - throw this.error("unable to resolve typedef for " + arg); - } - switch (false) { - case typedef.construct == null: - ctx.type = typedef.construct(params, this, arguments.callee); - break; - case typeof typedef.type !== 'object': - ref = typedef.type; - for (key in ref) { - value = ref[key]; - mparams = synth.copy({}, value); - synth.copy(mparams, params); - arguments.callee.call(this, key, mparams, children, ctx); - } - break; - case typeof typedef.type !== 'string': - arguments.callee.call(this, typedef.type, params, children, ctx); - } - if ((ref1 = ctx.type) != null) { - ref1.toString = function() { - return arg; - }; - } - return null; - } - argument: name - typedef: - default: 0..1 - description: 0..1 - units: 0..1 - type: 0..1 - reference: 0..1 - preprocess: ! |- - function (arg, params) { - return this.define('typedef', arg, params); - } - argument: name - uses: - augment: 0..n - description: 0..1 - if-feature: 0..n - refine: 0..n - reference: 0..1 - status: 0..1 - when: 0..1 - preprocess: ! |- - function (arg, params, ctx) { - var changes, grouping, k, match, ref, ref1, synth, target, v; - synth = this.require('data-synth'); - grouping = synth.copy({}, this.resolve('grouping', arg)); - delete grouping.description; - delete grouping.reference; - synth.copy(ctx, grouping); - ref = params.refine; - for (target in ref) { - changes = ref[target]; - match = this.locate(ctx, target); - if (match == null) { - continue; - } - for (k in changes) { - v = changes[k]; - match[k] = v; - } - } - ref1 = params.augment; - for (target in ref1) { - changes = ref1[target]; - match = this.locate(ctx, target); - if (match == null) { - continue; - } - synth.copy(match, changes); - } - if (typeof ctx.uses === 'object') { - return delete ctx.uses[arg]; - } else { - return delete ctx.uses; - } - } - argument: name - when: - description: 0..1 - reference: 0..1 - argument: condition - anyxml: {} - base: - argument: name - contact: - argument: - text: - yin-element: 'true' - default: - argument: value - description: - argument: - text: - yin-element: 'true' - error-app-tag: - argument: value - error-message: - argument: - value: - yin-element: 'true' - fraction-digits: - argument: value - key: - argument: value - length: - argument: value - namespace: - argument: uri - ordered-by: - argument: value - organization: - argument: - text: - yin-element: 'true' - position: - argument: value - presence: - argument: value - range: - argument: value - reference: - argument: - text: - yin-element: 'true' - revision-date: - argument: date - unique: - argument: tag - units: - argument: value - value: - argument: value - yang-version: - argument: value - yin-element: - argument: value -feature: ! '' -keywords: - - opnfv - - promise - - vim - - nfvi - - infrastructure - - openstack - - nbi - - yangforge - - resource - - reservation - - capacity - - allocation -rpc: - create-reservation: ! |- - function (input, output, done) { - var reservation, reservations; - reservation = this.create('ResourceReservation'); - reservations = this.access('promise.reservations'); - return reservation.invoke('update', input.get()).then(function(res) { - return res.save().then(function() { - reservations.push(res); - output.set({ - result: 'ok', - message: 'reservation request accepted' - }); - output.set('reservation-id', res.id); - return done(); - })["catch"](function(err) { - output.set({ - result: 'error', - message: err - }); - return done(); - }); - })["catch"](function(err) { - output.set({ - result: 'conflict', - message: err - }); - return done(); - }); - } - query-reservation: ! |- - function (input, output, done) { - var query; - query = input.get(); - query.capacity = 'reserved'; - return this.invoke('query-capacity', query).then(function(res) { - output.set('reservations', res.get('collections')); - output.set('utilization', res.get('utilization')); - return done(); - })["catch"](function(e) { - return done(e); - }); - } - update-reservation: ! |- - function (input, output, done) { - var reservation; - if ((input.get('reservation-id')) == null) { - output.set({ - result: 'error', - message: "must provide 'reservation-id' parameter" - }); - return done(); - } - reservation = this.find('ResourceReservation', input.get('reservation-id')); - if (reservation == null) { - output.set({ - result: 'error', - message: 'no reservation found for specified identifier' - }); - return done(); - } - return reservation.invoke('update', input.get()).then(function(res) { - return res.save().then(function() { - output.set({ - result: 'ok', - message: 'reservation update successful' - }); - return done(); - })["catch"](function(err) { - output.set({ - result: 'error', - message: err - }); - return done(); - }); - })["catch"](function(err) { - output.set({ - result: 'conflict', - message: err - }); - return done(); - }); - } - cancel-reservation: ! |- - function (input, output, done) { - var reservation; - reservation = this.find('ResourceReservation', input.get('reservation-id')); - if (reservation == null) { - output.set({ - result: 'error', - message: 'no reservation found for specified identifier' - }); - return done(); - } - return reservation.destroy().then((function(_this) { - return function() { - (_this.access('promise.reservations')).remove(reservation.id); - output.set('result', 'ok'); - output.set('message', 'reservation canceled'); - return done(); - }; - })(this))["catch"](function(e) { - output.set('result', 'error'); - output.set('message', e); - return done(); - }); - } - query-capacity: ! |- - function (input, output, done) { - var collections, deltas, entry, k, last, matches, metric, timestamp, usages, v, window; - window = input.get('window'); - metric = input.get('capacity'); - collections = (function() { - switch (metric) { - case 'total': - return ['ResourcePool']; - case 'reserved': - return ['ResourceReservation']; - case 'usage': - return ['ResourceAllocation']; - case 'available': - return ['ResourcePool', 'ResourceReservation', 'ResourceAllocation']; - } - })(); - matches = collections.reduce(((function(_this) { - return function(a, name) { - var res; - res = _this.find(name, { - start: function(value) { - return (window.end == null) || (new Date(value)) <= (new Date(window.end)); - }, - end: function(value) { - return (window.start == null) || (new Date(value)) >= (new Date(window.start)); - }, - enabled: true - }); - return a.concat.apply(a, res); - }; - })(this)), []); - if (window.scope === 'exclusive') { - matches = matches.where({ - start: function(value) { - return (window.start == null) || (new Date(value)) >= (new Date(window.start)); - }, - end: function(value) { - return (window.end == null) || (new Date(value)) <= (new Date(window.end)); - } - }); - } - matches = matches.without({ - id: input.get('without') - }); - if (metric === 'available') { - matches = matches.without({ - reservation: function(v) { - return v != null; - } - }); - } - output.set('collections', matches); - if ((input.get('show-utilization')) !== true) { - return done(); - } - deltas = matches.reduce((function(a, entry) { - var b, base, base1, ekey, k, ref1, ref2, skey, v; - b = entry.get(); - if (b.end == null) { - b.end = 'infiniteT'; - } - ref1 = [(b.start.split('T'))[0], (b.end.split('T'))[0]], skey = ref1[0], ekey = ref1[1]; - if (a[skey] == null) { - a[skey] = { - count: 0, - capacity: {} - }; - } - if (a[ekey] == null) { - a[ekey] = { - count: 0, - capacity: {} - }; - } - a[skey].count += 1; - a[ekey].count -= 1; - ref2 = b.capacity; - for (k in ref2) { - v = ref2[k]; - if (!(v != null)) { - continue; - } - if ((base = a[skey].capacity)[k] == null) { - base[k] = 0; - } - if ((base1 = a[ekey].capacity)[k] == null) { - base1[k] = 0; - } - if (entry.name === 'ResourcePool') { - a[skey].capacity[k] += v; - a[ekey].capacity[k] -= v; - } else { - a[skey].capacity[k] -= v; - a[ekey].capacity[k] += v; - } - } - return a; - }), {}); - last = { - count: 0, - capacity: {} - }; - usages = (function() { - var i, len, ref1, ref2, ref3, results; - ref1 = Object.keys(deltas).sort(); - results = []; - for (i = 0, len = ref1.length; i < len; i++) { - timestamp = ref1[i]; - if (!(timestamp !== 'infinite')) { - continue; - } - entry = deltas[timestamp]; - entry.timestamp = (new Date(timestamp)).toJSON(); - entry.count += last.count; - ref2 = entry.capacity; - for (k in ref2) { - v = ref2[k]; - entry.capacity[k] += (ref3 = last.capacity[k]) != null ? ref3 : 0; - } - last = entry; - results.push(entry); - } - return results; - })(); - output.set('utilization', usages); - return done(); - } - increase-capacity: ! |- - function (input, output, done) { - var pool; - pool = this.create('ResourcePool', input.get()); - return pool.save().then((function(_this) { - return function(res) { - (_this.access('promise.pools')).push(res); - output.set({ - result: 'ok', - message: 'capacity increase successful' - }); - output.set('pool-id', res.id); - return done(); - }; - })(this))["catch"](function(e) { - output.set({ - result: 'error', - message: e - }); - return done(); - }); - } - decrease-capacity: ! |- - function (input, output, done) { - var k, pool, ref1, request, v; - request = input.get(); - ref1 = request.capacity; - for (k in ref1) { - v = ref1[k]; - request.capacity[k] = -v; - } - pool = this.create('ResourcePool', request); - return pool.save().then((function(_this) { - return function(res) { - (_this.access('promise.pools')).push(res); - output.set({ - result: 'ok', - message: 'capacity decrease successful' - }); - output.set('pool-id', res.id); - return done(); - }; - })(this))["catch"](function(e) { - output.set({ - result: 'error', - message: e - }); - return done(); - }); - } - create-instance: ! |- - function (input, output, done) { - var available, flavor, k, pid, provider, required, reservation, rid, v; - pid = input.get('provider-id'); - if (pid != null) { - provider = this.find('ResourceProvider', pid); - if (provider == null) { - output.set({ - result: 'error', - message: "no matching provider found for specified identifier: " + pid - }); - return done(); - } - } else { - provider = (this.find('ResourceProvider'))[0]; - if (provider == null) { - output.set({ - result: 'error', - message: "no available provider found for create-instance" - }); - return done(); - } - } - flavor = provider.access("services.compute.flavors." + (input.get('flavor'))); - if (flavor == null) { - output.set({ - result: 'error', - message: "no such flavor found for specified identifier: " + pid - }); - return done(); - } - required = { - instances: 1, - cores: flavor.get('vcpus'), - ram: flavor.get('ram'), - gigabytes: flavor.get('disk') - }; - rid = input.get('reservation-id'); - if (rid != null) { - reservation = this.find('ResourceReservation', rid); - if (reservation == null) { - output.set({ - result: 'error', - message: 'no valid reservation found for specified identifier' - }); - return done(); - } - if ((reservation.get('active')) !== true) { - output.set({ - result: 'error', - message: "reservation is currently not active" - }); - return done(); - } - available = reservation.get('remaining'); - } else { - available = this.get('promise.capacity.available'); - } - for (k in required) { - v = required[k]; - if ((v != null) && !!v) { - if (!(available[k] >= v)) { - output.set({ - result: 'conflict', - message: "required " + k + "=" + v + " exceeds available " + available[k] - }); - return done(); - } - } - } - return this.create('ResourceAllocation', { - reservation: rid, - capacity: required - }).save().then((function(_this) { - return function(instance) { - var request, url; - url = provider.get('services.compute.endpoint'); - request = _this.parent.require('superagent'); - request.post(url + "/servers").send({ - server: { - name: input.get('name'), - imageRef: input.get('image'), - flavorRef: input.get('flavor') - } - }).set('X-Auth-Token', provider.get('token')).set('Accept', 'application/json').end(function(err, res) { - if ((err != null) || !res.ok) { - instance.destroy(); - console.error(err); - return done(res.error); - } - instance.set('instance-ref', { - provider: provider, - server: res.body.server.id - }); - (_this.access('promise.allocations')).push(instance); - output.set({ - result: 'ok', - message: 'create-instance request accepted' - }); - output.set('instance-id', instance.id); - return done(); - }); - return instance; - }; - })(this))["catch"](function(err) { - output.set({ - result: 'error', - mesage: err - }); - return done(); - }); - } - destroy-instance: ! |- - function (input, output, done) { - var instance; - instance = this.find('ResourceAllocation', input.get('instance-id')); - if (instance == null) { - output.set({ - result: 'error', - message: 'no allocation found for specified identifier' - }); - return done(); - } - return instance.destroy().then((function(_this) { - return function() { - var provider, ref, request, url; - (_this.access('promise.allocations')).remove(instance.id); - ref = instance.get('instance-ref'); - provider = _this.access("promise.providers." + ref.provider); - url = provider.get('services.compute.endpoint'); - request = _this.parent.require('superagent'); - request["delete"](url + "/servers/" + ref.server).set('X-Auth-Token', provider.get('token')).set('Accept', 'application/json').end(function(err, res) { - if ((err != null) || !res.ok) { - console.error(err); - return done(res.error); - } - output.set('result', 'ok'); - output.set('message', 'instance destroyed and resource released back to pool'); - return done(); - }); - return instance; - }; - })(this))["catch"](function(e) { - output.set('result', 'error'); - output.set('message', e); - return done(); - }); - } - add-provider: ! "function (input, output, done) {\n var app, payload, providers, request, url;\n app = this.parent;\n request = app.require('superagent');\n payload = (function() {\n switch (input.get('provider-type')) {\n case 'openstack':\n return {\n auth: {\n tenantId: input.get('tenant.id'),\n tenantName: input.get('tenant.name'),\n passwordCredentials: input.get('username', 'password')\n }\n };\n }\n })();\n if (payload == null) {\n return done('Sorry, only openstack supported at this time');\n }\n url = input.get('endpoint');\n switch (input.get('strategy')) {\n case 'keystone':\n case 'oauth':\n if (!/\\/tokens$/.test(url)) {\n url += '/tokens';\n }\n }\n providers = this.access('promise.providers');\n return request.post(url).send(payload).set('Accept', 'application/json').end((function(_this) {\n return function(err, res) {\n var access, provider, ref1, ref2, ref3;\n if ((err != null) || !res.ok) {\n return done(res.error);\n }\n access = res.body.access;\n provider = _this.create('ResourceProvider', {\n token: access != null ? (ref1 = access.token) != null ? ref1.id : void 0 : void 0,\n name: access != null ? (ref2 = access.token) != null ? (ref3 = ref2.tenant) != null ? ref3.name : void 0 : void 0 : void 0\n });\n return provider.invoke('update', access.serviceCatalog).then(function(res) {\n return res.save().then(function() {\n providers.push(res);\n output.set('result', 'ok');\n output.set('provider-id', res.id);\n return done();\n })[\"catch\"](function(err) {\n output.set('error', {\n message: err\n });\n return done();\n });\n })[\"catch\"](function(err) {\n output.set('error', {\n message: err\n });\n return done();\n });\n };\n })(this));\n }" -typedef: ! '' -complex-type: - ResourceElement: - id: ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - ResourceCollection: - id: - - ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - start: - - ! |- - function (prev) { - return prev.set('default', function() { - return (new Date).toJSON(); - }); - } - active: - - ! |- - function (prev) { - return this.computed((function() { - var end, now, start; - now = new Date; - start = new Date(this.get('start')); - end = (function() { - switch (false) { - case (this.get('end')) == null: - return new Date(this.get('end')); - default: - return now; - } - }).call(this); - return (this.get('enabled')) && ((start <= now && now <= end)); - }), { - type: prev - }); - } - ResourceReservation: - id: - - ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - start: - - ! |- - function (prev) { - return prev.set('default', function() { - return (new Date).toJSON(); - }); - } - active: - - ! |- - function (prev) { - return this.computed((function() { - var end, now, start; - now = new Date; - start = new Date(this.get('start')); - end = (function() { - switch (false) { - case (this.get('end')) == null: - return new Date(this.get('end')); - default: - return now; - } - }).call(this); - return (this.get('enabled')) && ((start <= now && now <= end)); - }), { - type: prev - }); - } - end: - - ! |- - function (prev) { - return prev.set('default', function() { - var end, max; - end = new Date(this.get('start')); - max = this.parent.get('promise.policy.reservation.max-duration'); - if (max == null) { - return; - } - end.setTime(end.getTime() + (max * 60 * 60 * 1000)); - return end.toJSON(); - }); - } - allocations: - - ! |- - function (prev) { - return this.computed((function() { - var res; - res = this.store.find('ResourceAllocation', { - reservation: this.id - }); - return res.map(function(x) { - return x.get('id'); - }); - }), { - type: 'array' - }); - } - remaining: - - ! |- - function (prev) { - return this.computed((function() { - var entry, i, k, len, records, total, usage, v; - total = this.get('capacity'); - records = this.store.find('ResourceAllocation', { - id: this.get('allocations'), - active: true - }); - for (i = 0, len = records.length; i < len; i++) { - entry = records[i]; - usage = entry.get('capacity'); - for (k in usage) { - v = usage[k]; - total[k] -= v; - } - } - return total; - }), { - type: prev - }); - } - validate: - - ! |- - function (prev) { - return function(value, resolve, reject) { - var end, hasCapacity, k, now, ref, start, v; - if (value == null) { - value = {}; - } - ref = value.capacity; - for (k in ref) { - v = ref[k]; - if ((v != null) && !!v) { - hasCapacity = true; - } - } - if ((!hasCapacity) && value.elements.length === 0) { - return reject("unable to validate reservation record without anything being reserved"); - } - now = new Date; - if (value.start != null) { - start = new Date(value.start); - } - if (value.end != null) { - end = new Date(value.end); - } - if ((end != null) && end < now) { - return reject("requested end time " + value.end + " cannot be in the past"); - } - if ((start != null) && (end != null) && start > end) { - retun(reject("requested start time must be earlier than end time")); - } - return resolve(this); - }; - } - update: - - ! |- - function (prev) { - return function(req, resolve, reject) { - if (req.start == null) { - req.start = this.get('start'); - } - if (req.end == null) { - req.end = this.get('end'); - } - return this.parent.invoke('query-capacity', { - start: req.start, - end: req.end, - capacity: 'available', - without: this.id - }).then((function(_this) { - return function(res) { - var available, collections, end, entries, i, k, pools, ref, ref1, start, t1, t2, v, x; - collections = res.get('collections'); - if (!(collections.length > 0)) { - return reject('no resource capacity available during requested start/end time'); - } - pools = collections.filter(function(e) { - return /^ResourcePool/.test(e); - }); - entries = res.get('utilization'); - start = new Date(req.start); - end = new Date(req.end); - for (x = i = 0, ref = entries.length - 1; 0 <= ref ? i <= ref : i >= ref; x = 0 <= ref ? ++i : --i) { - t1 = new Date(entries[x].timestamp); - if (!(t1 < end)) { - break; - } - if (x < entries.length - 1) { - t2 = new Date(entries[x + 1].timestamp); - if (!(t2 > start)) { - continue; - } - } - available = entries[x].capacity; - ref1 = req.capacity; - for (k in ref1) { - v = ref1[k]; - if ((v != null) && !!v) { - if (!(available[k] >= v)) { - return reject("requested " + k + "=" + v + " exceeds available " + available[k] + " between " + t1 + " and " + t2); - } - } - } - } - _this.set(req); - _this.set('pools', pools); - return resolve(_this); - }; - })(this))["catch"](function(err) { - return reject(err); - }); - }; - } - save: - - ! |- - function (prev) { - return function(resolve, reject) { - return this.invoke('validate', this.get()).then(function(res) { - var now; - now = (new Date).toJSON(); - if ((res.get('created-on')) == null) { - res.set('created-on', now); - } - res.set('modified-on', now); - return resolve(res); - })["catch"](function(e) { - return reject(e); - }); - }; - } - ResourceAllocation: - id: - - ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - start: - - ! |- - function (prev) { - return prev.set('default', function() { - return (new Date).toJSON(); - }); - } - active: - - ! |- - function (prev) { - return this.computed((function() { - var end, now, start; - now = new Date; - start = new Date(this.get('start')); - end = (function() { - switch (false) { - case (this.get('end')) == null: - return new Date(this.get('end')); - default: - return now; - } - }).call(this); - return (this.get('enabled')) && ((start <= now && now <= end)); - }), { - type: prev - }); - } - priority: - - ! |- - function (prev) { - return this.computed((function() { - switch (false) { - case !((this.get('reservation')) == null): - return 3; - case !!(this.get('active')): - return 2; - default: - return 1; - } - }), { - type: prev - }); - } - ResourcePool: - id: - - ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - start: - - ! |- - function (prev) { - return prev.set('default', function() { - return (new Date).toJSON(); - }); - } - active: - - ! |- - function (prev) { - return this.computed((function() { - var end, now, start; - now = new Date; - start = new Date(this.get('start')); - end = (function() { - switch (false) { - case (this.get('end')) == null: - return new Date(this.get('end')); - default: - return now; - } - }).call(this); - return (this.get('enabled')) && ((start <= now && now <= end)); - }), { - type: prev - }); - } - save: - - ! |- - function (prev) { - return function(resolve, reject) { - var hasCapacity, k, ref, v, value; - value = this.get(); - ref = value.capacity; - for (k in ref) { - v = ref[k]; - if ((v != null) && !!v) { - hasCapacity = true; - } - } - if ((!hasCapacity) && value.elements.length === 0) { - return reject("unable to save pool record without any capacity values"); - } - return resolve(this); - }; - } - ResourceProvider: - id: - - ! |- - function (prev) { - return prev.set('default', function() { - return this.uuid(); - }); - } - token: - - ! |- - function (prev) { - return prev.set('private', true); - } - pools: - - ! |- - function (prev) { - return this.computed((function() { - return (this.store.find('ResourcePool', { - source: this.get('name') - })).map(function(x) { - return x.get('id'); - }); - }), { - type: 'array' - }); - } - update: - - ! |- - function (prev) { - return function(services, resolve, reject) { - var request; - if (services == null) { - services = []; - } - if (!services.length) { - return reject("unable to update provider without list of services"); - } - request = this.store.parent.require('superagent'); - services.forEach((function(_this) { - return function(service) { - var url; - switch (service.type) { - case 'compute': - url = service.endpoints[0].publicURL; - _this.set('services.compute.endpoint', url); - request.get(url + "/limits").set('X-Auth-Token', _this.get('token')).set('Accept', 'application/json').end(function(err, res) { - var capacity, ref; - if ((err != null) || !res.ok) { - console.warn("request to discover capacity limits failed"); - return; - } - capacity = (ref = res.body.limits) != null ? ref.absolute : void 0; - return (_this.access('capacity')).set({ - cores: capacity.maxTotalCores, - ram: capacity.maxTotalRAMSize, - instances: capacity.maxTotalInstances, - addresses: capacity.maxTotalFloatingIps - }); - }); - return request.get(url + "/flavors/detail").set('X-Auth-Token', _this.get('token')).set('Accept', 'application/json').end(function(err, res) { - var er, error, flavors, ref; - if ((err != null) || !res.ok) { - console.warn("request to discover compute flavors failed"); - return; - } - flavors = res.body.flavors; - try { - flavors = flavors.map(function(x) { - return { - ResourceFlavor: x - }; - }); - return (ref = _this.access('services.compute.flavors')).push.apply(ref, flavors); - } catch (error) { - er = error; - return console.warn("failed to update flavors into the provider due to validation errors"); - } - }); - } - }; - })(this)); - return resolve(this); - }; - } - ResourceFlavor: ! '' -pkgdir: /home/plee/hack/opnfv-promise -module: - opnfv-promise: - promise.capacity.total: - - ! |- - function (prev) { - return this.computed((function() { - var combine; - combine = function(a, b) { - var k, ref, v; - ref = b.capacity; - for (k in ref) { - v = ref[k]; - if (!(v != null)) { - continue; - } - if (a[k] == null) { - a[k] = 0; - } - a[k] += v; - } - return a; - }; - return (this.parent.get('pools')).filter(function(entry) { - return entry.active === true; - }).reduce(combine, {}); - }), { - type: prev - }); - } - promise.capacity.reserved: - - ! |- - function (prev) { - return this.computed((function() { - var combine; - combine = function(a, b) { - var k, ref, v; - ref = b.remaining; - for (k in ref) { - v = ref[k]; - if (!(v != null)) { - continue; - } - if (a[k] == null) { - a[k] = 0; - } - a[k] += v; - } - return a; - }; - return (this.parent.get('reservations')).filter(function(entry) { - return entry.active === true; - }).reduce(combine, {}); - }), { - type: prev - }); - } - promise.capacity.usage: - - ! |- - function (prev) { - return this.computed((function() { - var combine; - combine = function(a, b) { - var k, ref, v; - ref = b.capacity; - for (k in ref) { - v = ref[k]; - if (!(v != null)) { - continue; - } - if (a[k] == null) { - a[k] = 0; - } - a[k] += v; - } - return a; - }; - return (this.parent.get('allocations')).filter(function(entry) { - return entry.active === true; - }).reduce(combine, {}); - }), { - type: prev - }); - } - promise.capacity.available: - - ! |- - function (prev) { - return this.computed((function() { - var k, reserved, total, usage, v; - total = this.get('total'); - reserved = this.get('reserved'); - usage = this.get('usage'); - for (k in total) { - v = total[k]; - if (!(v != null)) { - continue; - } - if (reserved[k] != null) { - total[k] -= reserved[k]; - } - if (usage[k] != null) { - total[k] -= usage[k]; - } - } - return total; - }), { - type: prev - }); - } -config: ! '' diff --git a/source/openstack.yaml b/source/openstack.yaml deleted file mode 100644 index 16eb447..0000000 --- a/source/openstack.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# - -name: openstack -description: OpenStack Management Module (WIP) -author: Peter K. Lee -license: Apache-2.0 -yangforge: "0.11.x" - -schema: !yang schema/openstack.yang - -dependencies: - access-control-models: !yang schema/access-control-models.yang - nfv-infrastructure: !yang schema/nfv-infrastructure.yang - -rpc: !require spec/openstack-intents.coffee diff --git a/source/package.json b/source/package.json deleted file mode 100644 index 59d489a..0000000 --- a/source/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "@opnfv/promise", - "version": "1.0.0", - "description": "Resource Management for Virtualized Infrastructure", - "author": "Peter K. Lee ", - "license": "Apache-2.0", - "private": true, - "homepage": "http://wiki.opnfv.org/promise", - "repository": "opnfv/promise", - "keywords": [ - "opnfv", - "promise", - "vim", - "nfvi", - "infrastructure", - "openstack", - "nbi", - "yangforge", - "resource", - "reservation", - "capacity", - "allocation" - ], - "engines": { - "yangforge": ">=0.11.0" - }, - "devDependencies": { - "config": "^1.19.0", - "js-yaml": "^3.5.2", - "mocha": "~2.0.1", - "promise": "^7.1.1", - "should": "~3.1.3", - "yangforge": "^0.11.0" - }, - "main": "./lib/index.js", - "scripts": { - "prepublish": "yfc build -o index.yaml promise.yaml", - "test": "mocha", - "start": "yfc run --express 5050 promise.yaml" - } -} diff --git a/source/promise.yaml b/source/promise.yaml deleted file mode 100644 index 98dcdc4..0000000 --- a/source/promise.yaml +++ /dev/null @@ -1,299 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# - -name: opnfv-promise -description: Resource Management for Virtualized Infrastructure -author: Peter K. Lee -license: Apache-2.0 -homepage: http://wiki.opnfv.org/promise -repository: git://github.com/opnfv/promise.git -yangforge: "0.11.x" -keywords: - - opnfv - - promise - - vim - - nfvi - - infrastructure - - openstack - - nbi - - yangforge - - resource - - reservation - - capacity - - allocation - -schema: !yang schema/opnfv-promise.yang - -# below config provides default parameters -# NOTE: uncomment locally for testing with pre-existing data -#config: !json config/demo.json - -dependencies: - access-control-models: !yang schema/access-control-models.yang - nfv-infrastructure: !yang schema/nfv-infrastructure.yang - -# MODULE model active bindings -module: - opnfv-promise: - # rebind to be a computed property - promise.capacity.total: !coffee/function | - (prev) -> @computed (-> - combine = (a, b) -> - for k, v of b.capacity when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'pools') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - # rebind to be a computed property - promise.capacity.reserved: !coffee/function | - (prev) -> @computed (-> - combine = (a, b) -> - for k, v of b.remaining when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'reservations') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - # rebind to be a computed property - promise.capacity.usage: !coffee/function | - (prev) -> @computed (-> - combine = (a, b) -> - for k, v of b.capacity when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'allocations') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - # rebind to be a computed property - promise.capacity.available: !coffee/function | - (prev) -> @computed (-> - total = @get 'total' - reserved = @get 'reserved' - usage = @get 'usage' - for k, v of total when v? - total[k] -= reserved[k] if reserved[k]? - total[k] -= usage[k] if usage[k]? - total - ), type: prev - -# RPC definitions (INTENT interfaces) -rpc: !require spec/promise-intents.coffee - -# COMPLEX-TYPE model active bindings (controller logic) -complex-type: - ResourceElement: - #properties - id: !coffee/function | - (prev) -> prev.set 'default', -> @uuid() - - ResourceCollection: - # properties - start: !coffee/function | - (prev) -> prev.set 'default', -> (new Date).toJSON() - - active: !coffee/function | - (prev) -> @computed (-> - now = new Date - start = new Date (@get 'start') - end = switch - when (@get 'end')? then new Date (@get 'end') - else now - (@get 'enabled') and (start <= now <= end) - ), type: prev - - ResourceReservation: - end: !coffee/function | - (prev) -> prev.set 'default', -> - end = (new Date @get 'start') - max = @parent.get 'promise.policy.reservation.max-duration' - return unless max? - end.setTime (end.getTime() + (max*60*60*1000)) - end.toJSON() - - allocations: !coffee/function | - (prev) -> @computed (-> - res = (@store.find 'ResourceAllocation', reservation: @id) - res.map (x) -> x.get 'id' - ), type: 'array' - - remaining: !coffee/function | - (prev) -> @computed (-> - total = @get 'capacity' - records = @store.find 'ResourceAllocation', id: (@get 'allocations'), active: true - for entry in records - usage = entry.get 'capacity' - for k, v of usage - total[k] -= v - total - ), type: prev - - # methods - validate: !coffee/function | - (prev) -> (value={}, resolve, reject) -> - # validate that request contains sufficient data - for k, v of value.capacity when v? and !!v - hasCapacity = true - if (not hasCapacity) and value.elements.length is 0 - return reject "unable to validate reservation record without anything being reserved" - # time range verifications - now = new Date - start = (new Date value.start) if value.start? - end = (new Date value.end) if value.end? - # if start? and start < now - # return reject "requested start time #{value.start} cannot be in the past" - if end? and end < now - return reject "requested end time #{value.end} cannot be in the past" - if start? and end? and start > end - retun reject "requested start time must be earlier than end time" - resolve this - - update: !coffee/function | - (prev) -> (req, resolve, reject) -> - req.start ?= @get 'start' - req.end ?= @get 'end' - - # TODO: should validate here... - @parent.invoke 'query-capacity', - start: req.start - end: req.end - capacity: 'available' - without: @id - .then (res) => - collections = res.get 'collections' - unless collections.length > 0 - return reject 'no resource capacity available during requested start/end time' - - pools = collections.filter (e) -> /^ResourcePool/.test e - # should do some policy or check to see if more than one pool acceptable to reservee - - entries = res.get 'utilization' - start = new Date req.start - end = new Date req.end - - for x in [0..entries.length-1] - t1 = new Date entries[x].timestamp - break unless t1 < end - - if x < entries.length-1 - t2 = new Date entries[x+1].timestamp - continue unless t2 > start - - available = entries[x].capacity - for k, v of req.capacity when v? and !!v - unless available[k] >= v - return reject "requested #{k}=#{v} exceeds available #{available[k]} between #{t1} and #{t2}" - - @set req - @set 'pools', pools - resolve this - .catch (err) -> reject err - - save: !coffee/function | - (prev) -> (resolve, reject) -> - @invoke 'validate', @get() - .then (res) -> - # should do something about this reservation record... - now = (new Date).toJSON() - unless (res.get 'created-on')? - res.set 'created-on', now - res.set 'modified-on', now - resolve res - .catch (e) -> reject e - - ResourceAllocation: - # properties - priority: !coffee/function | - (prev) -> @computed (-> - switch - when not (@get 'reservation')? then 3 - when not (@get 'active') then 2 - else 1 - ), type: prev - - ResourcePool: - save: !coffee/function | - (prev) -> (resolve, reject) -> - # validate that record contains sufficient data - value = @get() - - for k, v of value.capacity when v? and !!v - hasCapacity = true - if (not hasCapacity) and value.elements.length is 0 - return reject "unable to save pool record without any capacity values" - - resolve this - - ResourceProvider: - # properties - token: !coffee/function | - (prev) -> prev.set 'private', true - - pools: !coffee/function | - (prev) -> @computed (-> - (@store.find 'ResourcePool', source: (@get 'name')).map (x) -> x.get 'id' - ), type: 'array' - - # methods - # XXX - this method is OpenStack-specific only, will need to revise later - update: !coffee/function | - (prev) -> (services=[], resolve, reject) -> - return reject "unable to update provider without list of services" unless services.length - request = @store.parent.require 'superagent' - services.forEach (service) => - switch service.type - when 'compute' - url = service.endpoints[0].url - @set 'services.compute.endpoint', url - request - .get "#{url}/limits" - .set 'X-Auth-Token', @get 'token' - .set 'Accept', 'application/json' - .end (err, res) => - if err? or !res.ok - console.warn "request to discover capacity limits failed" - return - - capacity = res.body.limits?.absolute - #console.log "\ndiscovered capacity:" - #console.log capacity - - (@access 'capacity').set { - cores: capacity.maxTotalCores - ram: capacity.maxTotalRAMSize - instances: capacity.maxTotalInstances - addresses: capacity.maxTotalFloatingIps - } - request - .get "#{url}/flavors/detail" - .set 'X-Auth-Token', @get 'token' - .set 'Accept', 'application/json' - .end (err, res) => - if err? or !res.ok - console.warn "request to discover compute flavors failed" - return - - flavors = res.body.flavors - # console.log "\ndiscovered flavors:" - # console.log flavors - try - flavors = flavors.map (x) -> ResourceFlavor: x - (@access 'services.compute.flavors').push flavors... - catch er - console.warn "failed to update flavors into the provider due to validation errors" - - # XXX - update should do promise.all - resolve this - diff --git a/source/schema/access-control-models.yang b/source/schema/access-control-models.yang deleted file mode 100644 index 7b4684c..0000000 --- a/source/schema/access-control-models.yang +++ /dev/null @@ -1,92 +0,0 @@ -module access-control-models { - prefix acm; - namespace "urn:opnfv:promise:acm"; - - import complex-types { prefix ct; } - import ietf-yang-types { prefix yang; } - import ietf-inet-types { prefix inet; } - - typedef password { - type string { - length 1..255; - } - } - - grouping access-credentials { - leaf strategy { - type enumeration { - enum oauth; - enum keystone; - } - default oauth; - } - leaf endpoint { - type inet:uri; - description "The target endpoint for authentication"; - mandatory true; - } - leaf username { - type string; - mandatory true; - } - leaf password { - type acm:password; - mandatory true; - } - } - - /********************************************* - * Identity Models - *********************************************/ - - ct:complex-type Identity { - ct:abstract true; - description "Identity represents an administrative access model entity"; - - key "id"; - leaf id { type yang:uuid; mandatory true; } - leaf name { type string; mandatory true; } - leaf description { type string; } - leaf enabled { type boolean; default true; } - } - - ct:complex-type User { - ct:extends Identity; - - leaf credential { - //type instance-identifier { ct:instance-type IdentityCredential; } - type string; - mandatory true; - } - - container contact { - leaf fullName { type string; } - leaf email { type string; } - } - - leaf-list groups { type instance-identifer { ct:instance-type Group; } } - leaf domain { type instance-identifier { ct:instance-type Domain; } } - } - - ct:complex-type Group { - ct:extends Identity; - - leaf-list users { type instance-identifier { ct:instance-type User; } } - leaf domain { type instance-identifier { ct:instance-type Domain; } } - } - - ct:complex-type Domain { - ct:extends Identity; - description - "Domain represent a distinct administrative domain across - collection of users and groups."; - - ct:instance-list users { ct:instance-type User; } - ct:instance-list groups { ct:instance-type Group; } - } - - rpc create-user; - rpc remove-user; - rpc create-group; - rpc remove-group; -} diff --git a/source/schema/nfv-infrastructure.yang b/source/schema/nfv-infrastructure.yang deleted file mode 100644 index ccad269..0000000 --- a/source/schema/nfv-infrastructure.yang +++ /dev/null @@ -1,322 +0,0 @@ -module nfv-infrastructure { - namespace "urn:opnfv:promise:nfv:infrastructure"; - prefix nfvi; - - import access-control-models { prefix acm; } - import ietf-inet-types { prefix inet; } - import ietf-yang-types { prefix yang; } - import complex-types { prefix ct; } - - description - "NFV Infrastructure Data Models with complex types and typed instance - identifiers representing the various ResourceElements available - in the infrastructure across compute, network, and storage."; - - revision 2015-10-13 { - description - "Introduce capacity and element collection into NFVI models"; - } - - revision 2015-08-07 { - description - "This YANG module is modeled using 'yangforge' which natively provides - complex types and typed instance identifiers. This module - provides various collections of resource management data models - for instance based management"; - } - - identity manager { - description "used by specific modules implementing manager role for NFVI"; - } - - grouping compute-capacity { - leaf cores { type int16; default 0; } - leaf ram { type int32; default 0; units 'MB'; } - leaf instances { type int16; default 0; } - } - - grouping network-capacity { - leaf networks { type int16; default 0; } - leaf ports { type int16; default 0; } - leaf routers { type int16; default 0; } - leaf subnets { type int16; default 0; } - leaf addresses { type int32; default 0; } - } - - grouping storage-capacity { - leaf gigabytes { type int32; default 0; units 'GB'; } - leaf snapshots { type int16; default 0; } - leaf volumes { type int16; default 0; } - } - - grouping resource-capacity { - uses compute-capacity; - uses network-capacity; - uses storage-capacity; - } - - grouping resource-collection { - description - "Information model capturing parameters for describing a collection of - resource capacity and resource elements"; - - container capacity { uses resource-capacity; } - leaf-list elements { - type instance-identifier { - ct:instance-type nfvi:ResourceElement; - require-instance true; - } - } - } - - grouping resource-stack { - description - "Information model describing a NFVI resource stack comprising of - various resource elements across compute, network, and storage"; - - ct:instance-list hosts { ct:instance-type nfvi:PhysicalHost; } - ct:instance-list hypervisors { ct:instance-type nfvi:Hypervisor; } - - container compute { - description "Contains compute related resources"; - - ct:instance-list servers { ct:instance-type nfvi:ServerInstance; } - ct:instance-list images { ct:instance-type nfvi:VirtualMachineImage; } - ct:instance-list flavors { ct:instance-type nfvi:ComputeFlavor; } - } - - container network { - description "Contains networking related resources"; - - ct:instance-list networks { ct:instance-type nfvi:Network; } - ct:instance-list subnets { ct:instance-type nfvi:SubNetwork; } - ct:instance-list ports { ct:instance-type nfvi:SwitchPort; } - //ct:instance-list routers { ct:instance-type Router; } - } - } - - /********************************************* - * Abstract Models (top-level) - *********************************************/ - - ct:complex-type ResourceElement { - ct:abstract true; - - key "id"; - leaf id { type yang:uuid; mandatory true; } - leaf name { type string; } - leaf enabled { type boolean; default true; } - leaf protected { type boolean; default false; } - leaf owner { type instance-identifier { ct:instance-type acm:Identity; } } - leaf visibility { - description "Specify visibility level available from the perspective of 'owner'"; - type enumeration { - enum public; - enum domain; - enum project; - enum group; - enum user; - } - default user; - } - leaf-list tags { type string; } - - leaf-list members { - description "Optionally share with explicit list of members of AccessIdentity complex-type"; - type instance-identifier { - ct:instance-type acm:Identity; - } - } - } - - ct:complex-type ResourceInstance { - ct:extends ResourceElement; - ct:abstract true; - - leaf status { - type enumeration { - enum active; - enum inactive; - enum pending; - } - } - leaf progress { - type uint8 { range 0..100; } - default 0; - } - } - - ct:complex-type ResourceContainer { - ct:extends ResourceInstance; - ct:abstract true; - - description - "An abstract resource instance which contains a collection of capacity - and elements."; - - uses resource-collection; - } - - /********************************************* - * Compute Models - *********************************************/ - - ct:complex-type AvailabilityZone { - ct:extends ResourceElement; - } - - ct:complex-type PhysicalHost { - ct:extends ResourceElement; - - leaf type { type string; } - leaf version { type string; } - - leaf cpu { type uint8; } - leaf workload { type uint8; default 0; } - leaf uptime { type string; } - - container ram { - leaf total { type uint32; units 'MB'; } - leaf used { type uint32; units 'MB'; } - leaf free { type uint32; units 'MB'; } - } - container disk { - leaf total { type uint32; units 'GB'; } - leaf used { type uint32; units 'GB'; } - leaf free { type uint32; units 'GB'; } - } - - leaf-list hypervisors { type instance-identifier { ct:instance-type Hypervisor; } } - } - - ct:complex-type Hypervisor { - ct:extends PhysicalHost; - - leaf host { - type instance-identifier { ct:instance-type PhysicalHost; } - mandatory true; - } - container vcpu { - leaf total { type uint16; } - leaf used { type uint16; } - leaf free { type uint16; } - } - leaf-list servers { type instance-identifier { ct:instance-type ServerInstance; } } - } - - ct:complex-type ComputeElement { - ct:extends ResourceElement; - ct:abstract true; - - container constraint { - leaf disk { type uint32; units 'GB'; default 0; } - leaf ram { type uint32; units 'MB'; default 0; } - leaf vcpu { type uint16; default 0; } - } - - leaf-list instances { - description "State info about instances currently using this resource element"; - type instance-identifier { - ct:instance-type ResourceInstance; - } - config false; - } - } - - ct:complex-type VirtualMachineImage { - ct:extends ComputeElement; - - container data { - leaf checksum { type string; mandatory true; } - leaf size { type uint32; units 'Bytes'; mandatory true; } - - container format { - leaf container { - type enumeration { enum ami; enum ari; enum aki; enum bare; enum ovf; } - default bare; - } - leaf disk { - type enumeration { enum ami; enum ari; enum aki; enum vhd; enum vmdk; enum raw; enum qcow2; enum vdi; enum iso; } - } - } - leaf content { - description "should be a 'private' property so only direct access retrieves content"; - type binary; - } - } - } - - ct:complex-type ComputeFlavor { - ct:extends ResourceElement; - - leaf disk { type uint32; units 'GB'; default 0; } - leaf ram { type uint32; units 'MB'; default 0; } - leaf vcpus { type uint16; default 0; } - } - - ct:complex-type ServerInstance { - ct:extends ResourceInstance; - - leaf flavor { - type instance-identifier { ct:instance-type ComputeFlavor; } - mandatory true; - } - leaf image { - type instance-identifier { ct:instance-type VirtualMachineImage; } - mandatory true; - } - - //ct:instance metadata { ct:instance-type MetaData; } - - leaf host { - type instance-identifier { ct:instance-type PhysicalHost; } - } - - leaf-list connections { - description - "References to collection of NetworkingElement class objects such as - Network, Subnet, Port, Router that this ServerInstance is - connected with."; - type instance-identifier { ct:instance-type NetworkElement; } - } - } - - /********************************************* - * Network Models (Work-in-Progress) - *********************************************/ - - ct:complex-type NetworkElement { - ct:extends ResourceElement; - ct:abstract true; - } - - ct:complex-type Network { - ct:extends NetworkElement; - - leaf-list subnets { - type instance-identifier { ct:instance-type SubNetwork; } - } - } - - ct:complex-type SubNetwork { - ct:extends NetworkElement; - - leaf network { type instance-identifier { ct:instance-type Network; } } - - leaf-list nameservers { type string; } - - container dhcp { - leaf enabled { type boolean; } - list pools { - leaf start { type inet:ip-address; } - leaf end { type inet:ip-address; } - } - } - } - - ct:complex-type SwitchPort { - ct:extends NetworkElement; - - leaf subnet { type instance-identifier { ct:instance-type SubNetwork; } } - } -} diff --git a/source/schema/nfv-mano.yang b/source/schema/nfv-mano.yang deleted file mode 100644 index 0e3bbbe..0000000 --- a/source/schema/nfv-mano.yang +++ /dev/null @@ -1,149 +0,0 @@ -module nfv-mano { - namespace "urn:opnfv:promise:nfv:mano"; - prefix mano; - - import access-control-models { prefix acm; } - import nfv-infrastructure { prefix nfvi; } - import complex-types { prefix ct; } - import ietf-inet-types { prefix inet; } - import iana-crypt-hash { prefix ianach; } - - description - "NFV Management and Orchestration Data Models with complex types and typed - instance identifiers representing the NFVO, VNFM, and the VIM."; - - revision 2015-09-03 { - description - "This YANG module is modeled using 'yangforge' which natively provides - complex types and typed instance identifiers. This module - provides various collections of infrastructure management data - models for instance based management"; - } - - grouping provider-credentials { - leaf endpoint { - type inet:uri; - description "The target URL endpoint for the resource provider"; - mandatory true; - } - leaf username { - type string; - mandatory true; - } - leaf password { - type acm:password; - mandatory true; - } - leaf region { - type string; - description "Optional specified region for the provider"; - } - } - - ct:complex-type ServiceOrchestrator { - ct:extends acm:Domain; - ct:abstract true; - // TBD - } - - ct:complex-type ResourceOrchestrator { - ct:extends acm:Domain; - ct:abstract true; - // TBD - } - - ct:complex-type VirtualNetworkFunctionManager { - ct:extends acm:Domain; - ct:abstract true; - // TBD - } - - ct:complex-type VirtualInfrastructureManager { - ct:extends acm:Domain; - ct:abstract true; - - leaf name { type string; mandatory true; } - - container auth { - description 'Conceptual container that will be extended by explicit provider'; - // ct:instance-list credentials { ct:instance-type AccessCredential; } - // ct:instance-list roles { ct:instance-type AccessRole; } - // ct:instance-list policies { ct:instance-type AccessPolicy; } - } - - ct:instance-list hosts { ct:instance-type nfvi:PhysicalHost; } - ct:instance-list hypervisors { ct:instance-type nfvi:Hypervisor; } - - container compute { - if-feature has-compute; - description "Contains compute related resources"; - - ct:instance-list servers { ct:instance-type nfvi:ServerInstance; } - ct:instance-list images { ct:instance-type nfvi:VirtualMachineImage; } - ct:instance-list flavors { ct:instance-type nfvi:ComputeFlavor; } - } - - container network { - if-feature has-networking; - description "Contains networking related resources"; - - ct:instance-list networks { ct:instance-type nfvi:Network; } - ct:instance-list subnets { ct:instance-type nfvi:SubNetwork; } - ct:instance-list ports { ct:instance-type nfvi:SwitchPort; } - //ct:instance-list routers { ct:instance-type Router; } - } - } - - container stack { - container nfvo { - ct:instance service { ct:instance-type ServiceOrchestrator; } - ct:instance resource { ct:instance-type ResourceOrchestrator; } - } - container vnfm { - ct:instance-list managers { ct:instance-type VirtualNetworkFunctionManager; } - } - container vim { - ct:instance-list managers { ct:instance-type VirtualInfrastructureManager; } - } - } - - rpc add-vim { - description "This operation allows you to add a new VirtualInfrastructureManager into the NFVI stack"; - input { - uses provider-credentials; - - leaf provider { - description "Select a specific resource provider"; - mandatory true; - type enumeration { - enum openstack; - enum hp; - enum rackspace; - enum amazon { - status planned; - } - enum joyent { - status planned; - } - enum azure { - status planned; - } - } - } - } - output { - leaf id { - description "Unique identifier for the newly added provider found in /promise/providers"; - type instance-identifier { - ct:instance-type VirtualInfrastructureManager; - } - } - leaf result { - type enumeration { - enum success; - enum error; - } - } - } - } -} diff --git a/source/schema/openstack-compute.yang b/source/schema/openstack-compute.yang deleted file mode 100644 index c3e790c..0000000 --- a/source/schema/openstack-compute.yang +++ /dev/null @@ -1,72 +0,0 @@ -module openstack-compute { - prefix os-com; - - import nfv-infrastructure { prefix nfvi; } - import complex-types { prefix ct; } - - identity nova { base nvfi:compute; } - - feature availability-zone { - description "Specifies whether availability zone functionality is available."; - } - feature extended-status { - description "Specifies whether extended status functionality is available."; - } - feature security-groups { - description "Specifies whether security groups functionality is available."; - } - - ct:complex-type ServerInstance { - ct:extends nfvi:ServerInstance; - - leaf zone { - if-feature availability-zone; - type string; - } - - leaf project { - type instance-identifier { ct:instance-type nfvi:ResourceProject; } - mandatory true; - } - - container extended-status { - if-feature extended-status; - leaf locked-by; - leaf power; - leaf task; - leaf vm; - } - - leaf-list security-groups { - if-feature security-groups; - type instance-identifier { ct:instance-type SecurityGroup; } - } - - } - - choice version { - case v2.1 { - ct:instance-list servers { ct:instance-type ServerInstance; } - } - } - - // OpenStack Nova specific RPC calls - rpc resize { - input { - leaf server { type instance-type { ct:instance-type ServerInstance; } } - // other params for resize - } - } - rpc backup; - rpc migrate; - rpc restore; - rpc evacuate; - rpc lock; - rpc unlock; - rpc suspend; - rpc resume; - rpc pause; - rpc unpause; - rpc inject-network; - rpc reset-network; -} diff --git a/source/schema/openstack-identity.yang b/source/schema/openstack-identity.yang deleted file mode 100644 index 4b92957..0000000 --- a/source/schema/openstack-identity.yang +++ /dev/null @@ -1,84 +0,0 @@ -module openstack-identity { - namespace "urn:opnfv:promise:openstack:identity"; - prefix os-id; - - import access-control-models { prefix acm; } - import nfv-infrastructure { prefix nfvi; } - import complex-types { prefix ct; } - import ietf-yang-types { prefix yang; } - - description - "OpenStack Identity Data Models with complex types and typed instance - identifiers represent the various Access Control Models available - within OpenStack."; - - revision 2015-09-03 { - description - "This YANG module is modeled using 'yangforge' which natively provides - complex types and typed instance identifiers. This module - provides various collections of resource management data models - for instance based management"; - } - - /********************************************* - * OpenStack Identity Models - *********************************************/ - - ct:complex-type Project { - ct:extends acm:Group; - description - "OpenStack Project represent a distinct resource consumption space across - collection of users and groups that can reserve and allocate - resources."; - - leaf-list groups { type instance-identifer { ct:instance-type acm:Group; } } - - container resource { - leaf-list images { - if-feature vm-images; - type instance-identifier { ct:instance-type nfvi:VirtualMachineImage; } - } - - leaf-list flavors { - if-feature compute-flavors; - type instance-identifier { ct:instance-type nfvi:VirtualMachineFlavor; } - } - } - } - - ct:complex-type User { - ct:extends acm:User; - - description - "OpenStack User can also belong to multiple projects."; - - leaf-list projects { type instance-identifier { ct:instance-type Project; } } - } - - ct:complex-type Group { - ct:extends acm:Group; - - description - "OpenStack Group can also belong to multiple projects."; - - leaf-list projects { type instance-identifier { ct:instance-type Project; } } - } - - ct:complex-type Domain { - ct:extends acm:Domain; - - description - "OpenStack Domain represent a distinct administrative domain including projects."; - - ct:instance-list projects { ct:instance-type Project; } - } - - ct:complex-type Token { - leaf key { type yang:uuid; } - leaf identity { type instance-identifier { ct:instance-type Identity; } } - } - - - rpc create-project; - rpc remove-project; -} diff --git a/source/schema/openstack.yang b/source/schema/openstack.yang deleted file mode 100644 index 6878f7e..0000000 --- a/source/schema/openstack.yang +++ /dev/null @@ -1,74 +0,0 @@ -module openstack { - prefix os; - - import nfv-infrastructure { prefix nfvi; } - import access-control-models { prefix acm; } - import ietf-yang-types { prefix yang; } - import ietf-inet-types { prefix inet; } - import complex-types { prefix ct; } - - description - "OpenStack controller module"; - - revision 2016-01-19 { - description "Basic coverage of limited intents needed for Promise"; - } - - identity openstack { base nfvi:manager; } - identity release { base openstack; } - identity distro { base openstack; } - - feature os-system-admin { - description "OpenStack system administration capability"; - } - - grouping os-credentials { - uses acm:access-credentials { - refine strategy { - default keystone; - } - refine endpoint { - default "http://localhost:5000/v2.0"; - } - } - container tenant { - leaf id { type string; } - leaf name { type string; } - } - } - - // OpenStack infrastructure platform (PLACEHOLDER) - container platform { - uses nfvi:resource-stack; - - leaf release { type identityref { base release; } } - leaf distro { type identityref { base distro; } } - - //ct:instance-list services { ct:instance-type OpenStackService; } - //ct:instance-list endpoints { ct:instance-type ServiceEndpoint; } - } - - // OpenStack system administrator configuration tree - container admin { - if-feature os-system-admin; - container auth { - uses os-credentials; - leaf token { type yang:uuid; } - } - } - - rpc authenticate { - if-feature os-system-admin; - input { - uses os-credentials; - } - output { - leaf token { type yang:uuid; } - } - } - - rpc create-tenant { - if-feature os-system-admin; - - } -} diff --git a/source/schema/opnfv-promise.yang b/source/schema/opnfv-promise.yang deleted file mode 100644 index 9ee7564..0000000 --- a/source/schema/opnfv-promise.yang +++ /dev/null @@ -1,642 +0,0 @@ -module opnfv-promise { - namespace "urn:opnfv:promise"; - prefix promise; - - import complex-types { prefix ct; } - import ietf-yang-types { prefix yang; } - import ietf-inet-types { prefix inet; } - import access-control-models { prefix acm; } - import nfv-infrastructure { prefix nfvi; } - - description - "OPNFV Promise Resource Reservation/Allocation controller module"; - - revision 2015-10-05 { - description "Complete coverage of reservation related intents"; - } - - revision 2015-08-06 { - description "Updated to incorporate YangForge framework"; - } - - revision 2015-04-16 { - description "Initial revision."; - } - - feature reservation-service { - description "When enabled, provides resource reservation service"; - } - - feature multi-provider { - description "When enabled, provides resource management across multiple providers"; - } - - typedef reference-identifier { - description "defines valid formats for external reference id"; - type union { - type yang:uuid; - type inet:uri; - type uint32; - } - } - - grouping resource-utilization { - container capacity { - container total { description 'Conceptual container that should be extended'; } - container reserved { description 'Conceptual container that should be extended'; config false; } - container usage { description 'Conceptual container that should be extended'; config false; } - container available { description 'Conceptual container that should be extended'; config false; } - } - } - - grouping temporal-resource-collection { - description - "Information model capturing resource-collection with start/end time window"; - - leaf start { type yang:date-and-time; } - leaf end { type yang:date-and-time; } - - uses nfvi:resource-collection; - } - - grouping resource-usage-request { - description - "Information model capturing available parameters to make a resource - usage request."; - reference "OPNFV-PROMISE, Section 3.4.1"; - - uses temporal-resource-collection { - refine elements { - description - "Reference to a list of 'pre-existing' resource elements that are - required for fulfillment of the resource-usage-request. - - It can contain any instance derived from ResourceElement, - such as ServerInstances or even other - ResourceReservations. If the resource-usage-request is - accepted, the ResourceElement(s) listed here will be placed - into 'protected' mode as to prevent accidental removal. - - If any of these resource elements become 'unavailable' due to - environmental or administrative activity, a notification will - be issued informing of the issue."; - } - } - - leaf zone { - description "Optional identifier to an Availability Zone"; - type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } - } - } - - grouping query-start-end-window { - container window { - description "Matches entries that are within the specified start/end time window"; - leaf start { type yang:date-and-time; } - leaf end { type yang:date-and-time; } - leaf scope { - type enumeration { - enum "exclusive" { - description "Matches entries that start AND end within the window"; - } - enum "inclusive" { - description "Matches entries that start OR end within the window"; - } - } - default "inclusive"; - } - } - } - - grouping query-resource-collection { - uses query-start-end-window { - description "Match for ResourceCollection(s) that are within the specified start/end time window"; - } - leaf-list without { - description "Excludes specified collection identifiers from the result"; - type instance-identifier { ct:instance-type ResourceCollection; } - } - leaf show-utilization { type boolean; default true; } - container elements { - leaf-list some { - description "Query for ResourceCollection(s) that contain some or more of these element(s)"; - type instance-identifier { ct:instance-type nfvi:ResourceElement; } - } - leaf-list every { - description "Query for ResourceCollection(s) that contain all of these element(s)"; - type instance-identifier { ct:instance-type nfvi:ResourceElement; } - } - } - } - - grouping common-intent-output { - leaf result { - type enumeration { - enum "ok"; - enum "conflict"; - enum "error"; - } - } - leaf message { type string; } - } - - grouping utilization-output { - list utilization { - key 'timestamp'; - leaf timestamp { type yang:date-and-time; } - leaf count { type int16; } - container capacity { uses nfvi:resource-capacity; } - } - } - - ct:complex-type ResourceCollection { - ct:extends nfvi:ResourceContainer; - ct:abstract true; - - description - "Describes an abstract ResourceCollection data model, which represents - a grouping of capacity and elements available during a given - window in time which must be extended by other resource - collection related models"; - - leaf start { type yang:date-and-time; } - leaf end { type yang:date-and-time; } - - leaf active { - config false; - description - "Provides current state of this record whether it is enabled and within - specified start/end time"; - type boolean; - } - } - - ct:complex-type ResourcePool { - ct:extends ResourceCollection; - - description - "Describes an instance of an active ResourcePool record, which - represents total available capacity and elements from a given - source."; - - leaf source { - type instance-identifier { - ct:instance-type nfvi:ResourceContainer; - require-instance true; - } - mandatory true; - } - - refine elements { - // following 'must' statement applies to each element - // NOTE: just a non-working example for now... - must "boolean(/source/elements/*[@id=id])" { - error-message "One or more of the ResourceElement(s) does not exist in the provider to be reserved"; - } - } - } - - ct:complex-type ResourceReservation { - ct:extends ResourceCollection; - - description - "Describes an instance of an accepted resource reservation request, - created usually as a result of 'create-reservation' request. - - A ResourceReservation is a derived instance of a generic - ResourceCollection which has additional parameters to map the - pool(s) that were referenced to accept this reservation as well - as to track allocations made referencing this reservation. - - Contains the capacities of various resource attributes being - reserved along with any resource elements that are needed to be - available at the time of allocation(s)."; - - reference "OPNFV-PROMISE, Section 3.4.1"; - - leaf created-on { type yang:date-and-time; config false; } - leaf modified-on { type yang:date-and-time; config false; } - - leaf-list pools { - config false; - description - "Provides list of one or more pools that were referenced for providing - the requested resources for this reservation. This is an - important parameter for informing how/where allocation - requests can be issued using this reservation since it is - likely that the total reserved resource capacity/elements are - made availble from multiple sources."; - type instance-identifier { - ct:instance-type ResourcePool; - require-instance true; - } - } - - container remaining { - config false; - description - "Provides visibility into total remaining capacity for this - reservation based on allocations that took effect utilizing - this reservation ID as a reference."; - - uses nfvi:resource-capacity; - } - - leaf-list allocations { - config false; - description - "Reference to a collection of consumed allocations referencing - this reservation."; - type instance-identifier { - ct:instance-type ResourceAllocation; - require-instance true; - } - } - } - - ct:complex-type ResourceAllocation { - ct:extends ResourceCollection; - - description - "A ResourceAllocation record denotes consumption of resources from a - referenced ResourcePool. - - It does not reflect an accepted request but is created to - represent the actual state about the ResourcePool. It is - created once the allocation(s) have successfully taken effect - on the 'source' of the ResourcePool. - - The 'priority' state indicates the classification for dealing - with resource starvation scenarios. Lower priority allocations - will be forcefully terminated to allow for higher priority - allocations to be fulfilled. - - Allocations without reference to an existing reservation will - receive the lowest priority."; - - reference "OPNFV-PROMISE, Section 3.4.3"; - - leaf reservation { - description "Reference to an existing reservation identifier (optional)"; - - type instance-identifier { - ct:instance-type ResourceReservation; - require-instance true; - } - } - - leaf pool { - description "Reference to an existing resource pool from which allocation is drawn"; - - type instance-identifier { - ct:instance-type ResourcePool; - require-instance true; - } - } - - container instance-ref { - config false; - description - "Reference to actual instance identifier of the provider/server for this allocation"; - leaf provider { - type instance-identifier { ct:instance-type ResourceProvider; } - } - leaf server { type yang:uuid; } - } - - leaf priority { - config false; - description - "Reflects current priority level of the allocation according to classification rules"; - type enumeration { - enum "high" { value 1; } - enum "normal" { value 2; } - enum "low" { value 3; } - } - default "normal"; - } - } - - ct:complex-type ResourceFlavor { - description "currently NOT an extension of ResourceElement."; - key "id"; - leaf id { type string; } - leaf name { type string; } - leaf disk { type uint32; units 'GB'; default 0; } - leaf ram { type uint32; units 'MB'; default 0; } - leaf vcpus { type uint16; default 0; } - } - - ct:complex-type ResourceProvider { - ct:extends nfvi:ResourceContainer; - - key "name"; - leaf token { type string; mandatory true; } - - container services { // read-only - config false; - container compute { - leaf endpoint { type inet:uri; } - ct:instance-list flavors { ct:instance-type ResourceFlavor; } - } - } - - leaf-list pools { - config false; - description - "Provides list of one or more pools that are referencing this provider."; - - type instance-identifier { - ct:instance-type ResourcePool; - require-instance true; - } - } - } - - // MAIN CONTAINER - container promise { - - uses resource-utilization { - description "Describes current state info about capacity utilization info"; - - augment "capacity/total" { uses nfvi:resource-capacity; } - augment "capacity/reserved" { uses nfvi:resource-capacity; } - augment "capacity/usage" { uses nfvi:resource-capacity; } - augment "capacity/available" { uses nfvi:resource-capacity; } - } - - ct:instance-list providers { - if-feature multi-provider; - description "Aggregate collection of all registered ResourceProvider instances for Promise resource management service"; - ct:instance-type ResourceProvider; - } - - ct:instance-list pools { - if-feature reservation-service; - description "Aggregate collection of all ResourcePool instances"; - ct:instance-type ResourcePool; - } - - ct:instance-list reservations { - if-feature reservation-service; - description "Aggregate collection of all ResourceReservation instances"; - ct:instance-type ResourceReservation; - } - - ct:instance-list allocations { - description "Aggregate collection of all ResourceAllocation instances"; - ct:instance-type ResourceAllocation; - } - - container policy { - container reservation { - leaf max-future-start-range { - description - "Enforce reservation request 'start' time is within allowed range from now"; - type uint16 { range 0..365; } - units "days"; - } - leaf max-future-end-range { - description - "Enforce reservation request 'end' time is within allowed range from now"; - type uint16 { range 0..365; } - units "days"; - } - leaf max-duration { - description - "Enforce reservation duration (end-start) does not exceed specified threshold"; - type uint16; - units "hours"; - default 8760; // for now cap it at max one year as default - } - leaf expiry { - description - "Duration in minutes from start when unallocated reserved resources - will be released back into the pool"; - type uint32; - units "minutes"; - } - } - } - } - - //------------------- - // INTENT INTERFACE - //------------------- - - // RESERVATION INTENTS - rpc create-reservation { - if-feature reservation-service; - description "Make a request to the reservation system to reserve resources"; - input { - uses resource-usage-request; - } - output { - uses common-intent-output; - leaf reservation-id { - type instance-identifier { ct:instance-type ResourceReservation; } - } - } - } - - rpc update-reservation { - description "Update reservation details for an existing reservation"; - input { - leaf reservation-id { - type instance-identifier { - ct:instance-type ResourceReservation; - require-instance true; - } - mandatory true; - } - uses resource-usage-request; - } - output { - uses common-intent-output; - } - } - - rpc cancel-reservation { - description "Cancel the reservation and be a good steward"; - input { - leaf reservation-id { - type instance-identifier { ct:instance-type ResourceReservation; } - mandatory true; - } - } - output { - uses common-intent-output; - } - } - - rpc query-reservation { - if-feature reservation-service; - description "Query the reservation system to return matching reservation(s)"; - input { - leaf zone { type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } } - uses query-resource-collection; - } - output { - leaf-list reservations { type instance-identifier { ct:instance-type ResourceReservation; } } - uses utilization-output; - } - } - - // CAPACITY INTENTS - rpc increase-capacity { - description "Increase total capacity for the reservation system between a window in time"; - input { - uses temporal-resource-collection; - leaf source { - type instance-identifier { - ct:instance-type nfvi:ResourceContainer; - } - } - } - output { - uses common-intent-output; - leaf pool-id { - type instance-identifier { ct:instance-type ResourcePool; } - } - } - } - - rpc decrease-capacity { - description "Decrease total capacity for the reservation system between a window in time"; - input { - uses temporal-resource-collection; - leaf source { - type instance-identifier { - ct:instance-type nfvi:ResourceContainer; - } - } - } - output { - uses common-intent-output; - leaf pool-id { - type instance-identifier { ct:instance-type ResourcePool; } - } - } - } - - rpc query-capacity { - description "Check available capacity information about a specified resource collection"; - input { - leaf capacity { - type enumeration { - enum 'total'; - enum 'reserved'; - enum 'usage'; - enum 'available'; - } - default 'available'; - } - leaf zone { type instance-identifier { ct:instance-type nfvi:AvailabilityZone; } } - uses query-resource-collection; - // TBD: additional parameters for query-capacity - } - output { - leaf-list collections { type instance-identifier { ct:instance-type ResourceCollection; } } - uses utilization-output; - } - } - - // ALLOCATION INTENTS (should go into VIM module in the future) - rpc create-instance { - description "Create an instance of specified resource(s) utilizing capacity from the pool"; - input { - leaf provider-id { - if-feature multi-provider; - type instance-identifier { ct:instance-type ResourceProvider; require-instance true; } - } - leaf name { type string; mandatory true; } - leaf image { - type reference-identifier; - mandatory true; - } - leaf flavor { - type reference-identifier; - mandatory true; - } - leaf-list networks { - type reference-identifier; - description "optional, will assign default network if not provided"; - } - - // TODO: consider supporting a template-id (such as HEAT) for more complex instantiation - - leaf reservation-id { - type instance-identifier { ct:instance-type ResourceReservation; require-instance true; } - } - } - output { - uses common-intent-output; - leaf instance-id { - type instance-identifier { ct:instance-type ResourceAllocation; } - } - } - } - - rpc destroy-instance { - description "Destroy an instance of resource utilization and release it back to the pool"; - input { - leaf instance-id { - type instance-identifier { ct:instance-type ResourceAllocation; require-instance true; } - } - } - output { - uses common-intent-output; - } - } - - // PROVIDER INTENTS (should go into VIM module in the future) - rpc add-provider { - description "Register a new resource provider into reservation system"; - input { - leaf provider-type { - description "Select a specific resource provider type"; - mandatory true; - type enumeration { - enum openstack; - enum hp; - enum rackspace; - enum amazon { - status planned; - } - enum joyent { - status planned; - } - enum azure { - status planned; - } - } - default openstack; - } - uses acm:access-credentials { - refine strategy { - default keystone; - } - refine endpoint { - default "http://localhost:5000/v2.0"; - } - } - leaf user-domain-name { type string; } - container project { - leaf id { type string; } - leaf name { type string; } - leaf domain-name { type string; } - } - } - output { - uses common-intent-output; - leaf provider-id { - type instance-identifier { ct:instance-type ResourceProvider; } - } - } - } - - // TODO... - notification reservation-event; - notification capacity-event; - notification allocation-event; -} diff --git a/source/spec/openstack-intents.coffee b/source/spec/openstack-intents.coffee deleted file mode 100644 index 6fd8fe2..0000000 --- a/source/spec/openstack-intents.coffee +++ /dev/null @@ -1,14 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -request = require 'superagent' - -module.exports = - 'create-tenant': - (input, output, done) -> - # TODO - this requires OS-KSADM extension diff --git a/source/spec/promise-intents.coffee b/source/spec/promise-intents.coffee deleted file mode 100644 index 985e81f..0000000 --- a/source/spec/promise-intents.coffee +++ /dev/null @@ -1,379 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -module.exports = - 'create-reservation': - (input, output, done) -> - # 1. create the reservation record (empty) - reservation = @create 'ResourceReservation' - reservations = @access 'promise.reservations' - - # 2. update the record with requested input - reservation.invoke 'update', input.get() - .then (res) -> - # 3. save the record and add to list - res.save() - .then -> - reservations.push res - output.set result: 'ok', message: 'reservation request accepted' - output.set 'reservation-id', res.id - done() - .catch (err) -> - output.set result: 'error', message: err - done() - .catch (err) -> - output.set result: 'conflict', message: err - done() - - 'query-reservation': - (input, output, done) -> - query = input.get() - query.capacity = 'reserved' - @invoke 'query-capacity', query - .then (res) -> - output.set 'reservations', res.get 'collections' - output.set 'utilization', res.get 'utilization' - done() - .catch (e) -> done e - - 'update-reservation': - (input, output, done) -> - # TODO: we shouldn't need this... need to check why leaf mandatory: true not being enforced - unless (input.get 'reservation-id')? - output.set result: 'error', message: "must provide 'reservation-id' parameter" - return done() - - # 1. find the reservation - reservation = @find 'ResourceReservation', input.get 'reservation-id' - unless reservation? - output.set result: 'error', message: 'no reservation found for specified identifier' - return done() - - # 2. update the record with requested input - reservation.invoke 'update', input.get() - .then (res) -> - # 3. save the updated record - res.save() - .then -> - output.set result: 'ok', message: 'reservation update successful' - done() - .catch (err) -> - output.set result: 'error', message: err - done() - .catch (err) -> - output.set result: 'conflict', message: err - done() - - 'cancel-reservation': - (input, output, done) -> - # 1. find the reservation - reservation = @find 'ResourceReservation', input.get 'reservation-id' - unless reservation? - output.set result: 'error', message: 'no reservation found for specified identifier' - return done() - - # 2. destroy all traces of this reservation - reservation.destroy() - .then => - (@access 'promise.reservations').remove reservation.id - output.set 'result', 'ok' - output.set 'message', 'reservation canceled' - done() - .catch (e) -> - output.set 'result', 'error' - output.set 'message', e - done() - - 'query-capacity': - (input, output, done) -> - # 1. we gather up all collections that match the specified window - window = input.get 'window' - metric = input.get 'capacity' - - collections = switch metric - when 'total' then [ 'ResourcePool' ] - when 'reserved' then [ 'ResourceReservation' ] - when 'usage' then [ 'ResourceAllocation' ] - when 'available' then [ 'ResourcePool', 'ResourceReservation', 'ResourceAllocation' ] - - matches = collections.reduce ((a, name) => - res = @find name, - start: (value) -> (not window.end?) or (new Date value) <= (new Date window.end) - end: (value) -> (not window.start?) or (new Date value) >= (new Date window.start) - enabled: true - a.concat res... - ), [] - - if window.scope is 'exclusive' - # yes, we CAN query filter in one shot above but this makes logic cleaner... - matches = matches.where - start: (value) -> (not window.start?) or (new Date value) >= (new Date window.start) - end: (value) -> (not window.end?) or (new Date value) <= (new Date window.end) - - # exclude any identifiers specified - matches = matches.without id: (input.get 'without') - - if metric is 'available' - # excludes allocations with reservation property set (to prevent double count) - matches = matches.without reservation: (v) -> v? - - output.set 'collections', matches - unless (input.get 'show-utilization') is true - return done() - - # 2. we calculate the deltas based on start/end times of each match item - deltas = matches.reduce ((a, entry) -> - b = entry.get() - b.end ?= 'infiniteT' - [ skey, ekey ] = [ (b.start.split 'T')[0], (b.end.split 'T')[0] ] - a[skey] ?= count: 0, capacity: {} - a[ekey] ?= count: 0, capacity: {} - a[skey].count += 1 - a[ekey].count -= 1 - - for k, v of b.capacity when v? - a[skey].capacity[k] ?= 0 - a[ekey].capacity[k] ?= 0 - if entry.name is 'ResourcePool' - a[skey].capacity[k] += v - a[ekey].capacity[k] -= v - else - a[skey].capacity[k] -= v - a[ekey].capacity[k] += v - return a - ), {} - - # 3. we then sort the timestamps and aggregate the deltas - last = count: 0, capacity: {} - usages = for timestamp in Object.keys(deltas).sort() when timestamp isnt 'infinite' - entry = deltas[timestamp] - entry.timestamp = (new Date timestamp).toJSON() - entry.count += last.count - for k, v of entry.capacity - entry.capacity[k] += (last.capacity[k] ? 0) - last = entry - entry - - output.set 'utilization', usages - done() - - 'increase-capacity': - (input, output, done) -> - pool = @create 'ResourcePool', input.get() - pool.save() - .then (res) => - (@access 'promise.pools').push res - output.set result: 'ok', message: 'capacity increase successful' - output.set 'pool-id', res.id - done() - .catch (e) -> - output.set result: 'error', message: e - done() - - 'decrease-capacity': - (input, output, done) -> - request = input.get() - for k, v of request.capacity - request.capacity[k] = -v - pool = @create 'ResourcePool', request - pool.save() - .then (res) => - (@access 'promise.pools').push res - output.set result: 'ok', message: 'capacity decrease successful' - output.set 'pool-id', res.id - done() - .catch (e) -> - output.set result: 'error', message: e - done() - - # TEMPORARY (should go into VIM-specific module) - 'create-instance': - (input, output, done) -> - pid = input.get 'provider-id' - if pid? - provider = @find 'ResourceProvider', pid - unless provider? - output.set result: 'error', message: "no matching provider found for specified identifier: #{pid}" - return done() - else - provider = (@find 'ResourceProvider')[0] - unless provider? - output.set result: 'error', message: "no available provider found for create-instance" - return done() - - # calculate required capacity based on 'flavor' and other params - flavor = provider.access "services.compute.flavors.#{input.get 'flavor'}" - unless flavor? - output.set result: 'error', message: "no such flavor found for specified identifier: #{pid}" - return done() - - required = - instances: 1 - cores: flavor.get 'vcpus' - ram: flavor.get 'ram' - gigabytes: flavor.get 'disk' - - rid = input.get 'reservation-id' - if rid? - reservation = @find 'ResourceReservation', rid - unless reservation? - output.set result: 'error', message: 'no valid reservation found for specified identifier' - return done() - unless (reservation.get 'active') is true - output.set result: 'error', message: "reservation is currently not active" - return done() - available = reservation.get 'remaining' - else - available = @get 'promise.capacity.available' - - # TODO: need to verify whether 'provider' associated with this 'reservation' - - for k, v of required when v? and !!v - unless available[k] >= v - output.set result: 'conflict', message: "required #{k}=#{v} exceeds available #{available[k]}" - return done() - - @create 'ResourceAllocation', - reservation: rid - capacity: required - .save() - .then (instance) => - url = provider.get 'services.compute.endpoint' - payload = - server: - name: input.get 'name' - imageRef: input.get 'image' - flavorRef: input.get 'flavor' - networks = (input.get 'networks').filter (x) -> x? and !!x - if networks.length > 0 - payload.server.networks = networks.map (x) -> uuid: x - - request = @parent.require 'superagent' - request - .post "#{url}/servers" - .send payload - .set 'X-Auth-Token', provider.get 'token' - .set 'Accept', 'application/json' - .end (err, res) => - if err? or !res.ok - instance.destroy() - #console.error err - return done res.error - #console.log JSON.stringify res.body, null, 2 - instance.set 'instance-ref', - provider: provider - server: res.body.server.id - (@access 'promise.allocations').push instance - output.set result: 'ok', message: 'create-instance request accepted' - output.set 'instance-id', instance.id - done() - return instance - .catch (err) -> - output.set result: 'error', mesage: err - done() - - 'destroy-instance': - (input, output, done) -> - # 1. find the instance - instance = @find 'ResourceAllocation', input.get 'instance-id' - unless instance? - output.set result: 'error', message: 'no allocation found for specified identifier' - return done() - - # 2. destroy all traces of this instance - instance.destroy() - .then => - # always remove internally - (@access 'promise.allocations').remove instance.id - ref = instance.get 'instance-ref' - provider = (@access "promise.providers.#{ref.provider}") - url = provider.get 'services.compute.endpoint' - request = @parent.require 'superagent' - request - .delete "#{url}/servers/#{ref.server}" - .set 'X-Auth-Token', provider.get 'token' - .set 'Accept', 'application/json' - .end (err, res) => - if err? or !res.ok - console.error err - return done res.error - output.set 'result', 'ok' - output.set 'message', 'instance destroyed and resource released back to pool' - done() - return instance - .catch (e) -> - output.set 'result', 'error' - output.set 'message', e - done() - - # TEMPORARY (should go into VIM-specific module) - 'add-provider': - (input, output, done) -> - app = @parent - request = app.require 'superagent' - - payload = switch input.get 'provider-type' - when 'openstack' - auth: - identity: - methods: [ "password" ] - password: - user: - name: input.get 'username' - password: input.get 'password' - domain: - name: input.get 'user-domain-name' - scope: - project: - name: input.get 'project.name' - domain: - name: input.get 'project.domain-name' - - unless payload? - return done 'Sorry, only openstack supported at this time' - - url = input.get 'endpoint' - switch input.get 'strategy' - when 'keystone', 'oauth' - url += '/auth/tokens' unless /\/tokens$/.test url - - providers = @access 'promise.providers' - request - .post url - .send payload - .set 'Accept', 'application/json' - .end (err, res) => - if err? or !res.ok then return done res.error - #console.log JSON.stringify res.body, null, 2 - #console.log res.headers - #console.log res.body.token.catalog - provider = @create 'ResourceProvider', - token: res.headers['x-subject-token'] - name: res.body.token.project.name - provider.invoke 'update', res.body.token.catalog - .then (res) -> - res.save() - .then -> - providers.push res - output.set 'result', 'ok' - output.set 'provider-id', res.id - done() - .catch (err) -> - output.set 'error', message: err - done() - .catch (err) -> - output.set 'error', message: err - done() - - # @using 'mano', -> - # @invoke 'add-provider', (input.get 'endpoint', 'region', 'username', 'password') - # .then (res) => - # (@access 'promise.providers').push res - # output.set 'result', 'ok' - # output.set 'provider-id', res.id - # done() diff --git a/source/spec/promise-module.coffee b/source/spec/promise-module.coffee deleted file mode 100644 index f021f6c..0000000 --- a/source/spec/promise-module.coffee +++ /dev/null @@ -1,80 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -module.exports = - '/opnfv-promise/promise/capacity/total': (prev) -> - @computed (-> - combine = (a, b) -> - for k, v of b.capacity when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'pools') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - - '/opnfv-promise/promise/capacity/reserved', (prev) -> - @computed (-> - combine = (a, b) -> - for k, v of b.capacity when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'reservations') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - - # rebind to be a computed property - '/opnfv-promise/promise/capacity/usage': (prev) -> - @computed (-> - combine = (a, b) -> - for k, v of b.capacity when v? - a[k] ?= 0 - a[k] += v - return a - (@parent.get 'allocations') - .filter (entry) -> entry.active is true - .reduce combine, {} - ), type: prev - - # rebind to be a computed property - '/opnfv-promise/promise/capacity/available': (prev) -> - @computed (-> - total = @get 'total' - reserved = @get 'reserved' - usage = @get 'usage' - for k, v of total when v? - total[k] -= reserved[k] if reserved[k]? - total[k] -= usage[k] if usage[k]? - total - ), type: prev - - '/opnfv-promise/create-reservation': - (input, output, done) -> - # 1. create the reservation record (empty) - reservation = @create 'ResourceReservation' - reservations = @access 'promise.reservations' - - # 2. update the record with requested input - reservation.invoke 'update', input.get() - .then (res) -> - # 3. save the record and add to list - res.save() - .then -> - reservations.push res - output.set result: 'ok', message: 'reservation request accepted' - output.set 'reservation-id', res.id - done() - .catch (err) -> - output.set result: 'error', message: err - done() - .catch (err) -> - output.set result: 'conflict', message: err - done() diff --git a/source/test/mocha.opts b/source/test/mocha.opts deleted file mode 100644 index 1e154ee..0000000 --- a/source/test/mocha.opts +++ /dev/null @@ -1,2 +0,0 @@ ---require should ---compilers coffee:coffee-script/register diff --git a/source/test/promise-intents.coffee b/source/test/promise-intents.coffee deleted file mode 100644 index db7e8d6..0000000 --- a/source/test/promise-intents.coffee +++ /dev/null @@ -1,445 +0,0 @@ -# -# Author: Peter K. Lee (peter@corenova.com) -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -# -config = require 'config' -assert = require 'assert' -forge = require 'yangforge' -app = forge.load '!yaml ../promise.yaml', async: false, pkgdir: __dirname - -# this is javascript promise framework and not related to opnfv-promise -promise = require 'promise' - -if process.env.DEBUG - debug = console.log -else - debug = -> - -# in the future with YF 0.12.x -# app = forge.load('..').build('test') -# app.set config -# app.use 'proxy', target: x.x.x.x:5050, interface: 'restjson' - -describe "promise", -> - before -> - # ensure we have valid OpenStack environment to test against - try - config.get 'openstack.auth.endpoint' - catch e - throw new Error "missing OpenStack environmental variables" - - - # below 'provider' is used across test suites - provider = undefined - - # Test Scenario 00 (FUTURE) - # describe "prepare OpenStack for testing", -> - # before (done) -> - # # ensure we have valid OpenStack environment to test against - # try - # config.get 'openstack.auth.url' - # catch e - # throw new Error "missing OpenStack environmental variables" - - # os = forge.load '!yaml ../openstack.yaml', async: false, pkgdir: __dirname - # app.attach 'openstack', os.access 'openstack' - # app.set config - - # describe "authenticate", -> - # it "should retrieve available service catalog", (done) -> - # app.access('openstack').invoke 'authenticate' - # .then (res) -> - - # done() - # .catch (err) -> done err - - # describe "create-tenant", -> - # # create a new tenant for testing purposes - - # describe "upload-image", -> - # # upload a new test image - - - - # Test Scenario 01 - describe "register OpenStack into resource pool", -> - pool = undefined - - # TC-01 - describe "add-provider", -> - it "should add a new OpenStack provider without error", (done) -> - @timeout 5000 - - auth = config.get 'openstack.auth' - auth['provider-type'] = 'openstack' - - app.access('opnfv-promise').invoke 'add-provider', auth - .then (res) -> - res.get('result').should.equal 'ok' - provider = id: res.get('provider-id') - # HACK - we delay by a second to allow time for discovering capacity and flavors - setTimeout done, 1000 - .catch (err) -> done err - - it "should update promise.providers with a new entry", -> - app.get('opnfv-promise.promise.providers').should.have.length(1) - - it "should contain a new ResourceProvider record in the store", -> - assert provider?.id?, "unable to check without ID" - provider = app.access('opnfv-promise').find('ResourceProvider', provider.id) - assert provider? - - # TC-02 - describe "increase-capacity", -> - it "should add more capacity to the reservation service without error", (done) -> - app.access('opnfv-promise').invoke 'increase-capacity', - source: provider - capacity: - cores: 20 - ram: 51200 - instances: 10 - addresses: 10 - .then (res) -> - res.get('result').should.equal 'ok' - pool = id: res.get('pool-id') - done() - .catch (err) -> done err - - it "should update promise.pools with a new entry", -> - app.get('opnfv-promise.promise.pools').should.have.length(1) - - it "should contain a ResourcePool record in the store", -> - assert pool?.id?, "unable to check without ID" - pool = app.access('opnfv-promise').find('ResourcePool', pool.id) - assert pool? - - # TC-03 - describe "query-capacity", -> - it "should report total collections and utilizations", (done) -> - app.access('opnfv-promise').invoke 'query-capacity', - capacity: 'total' - .then (res) -> - res.get('collections').should.be.Array - res.get('collections').length.should.be.above(0) - res.get('utilization').should.be.Array - res.get('utilization').length.should.be.above(0) - done() - .catch (err) -> done err - - it "should contain newly added capacity pool", (done) -> - app.access('opnfv-promise').invoke 'query-capacity', - capacity: 'total' - .then (res) -> - res.get('collections').should.containEql "ResourcePool:#{pool.id}" - done() - .catch (err) -> done err - - # Test Scenario 02 - describe "allocation without reservation", -> - - # TC-04 - describe "create-instance", -> - allocation = undefined - instance_id = undefined - - before -> - # XXX - need to determine image and flavor to use in the given provider for this test - assert provider?, - "unable to execute without registered 'provider'" - - it "should create a new server in target provider without error", (done) -> - @timeout 5000 - test = config.get 'openstack.test' - app.access('opnfv-promise').invoke 'create-instance', - 'provider-id': provider.id - name: 'promise-test-no-reservation' - image: test.image - flavor: test.flavor - networks: [ test.network ] - .then (res) -> - debug res.get() - res.get('result').should.equal 'ok' - instance_id = res.get('instance-id') - done() - .catch (err) -> done err - - it "should update promise.allocations with a new entry", -> - app.get('opnfv-promise.promise.allocations').length.should.be.above(0) - - it "should contain a new ResourceAllocation record in the store", -> - assert instance_id?, "unable to check without ID" - allocation = app.access('opnfv-promise').find('ResourceAllocation', instance_id) - assert allocation? - - it "should reference the created server ID from the provider", -> - assert allocation?, "unable to check without record" - allocation.get('instance-ref').should.have.property('provider') - allocation.get('instance-ref').should.have.property('server') - - it "should have low priority state", -> - assert allocation?, "unable to check without record" - allocation.get('priority').should.equal 'low' - - # Test Scenario 03 - describe "allocation using reservation for immediate use", -> - reservation = undefined - - # TC-05 - describe "create-reservation", -> - it "should create reservation record (no start/end) without error", (done) -> - app.access('opnfv-promise').invoke 'create-reservation', - capacity: - cores: 5 - ram: 25600 - addresses: 3 - instances: 3 - .then (res) -> - res.get('result').should.equal 'ok' - reservation = id: res.get('reservation-id') - done() - .catch (err) -> done err - - it "should update promise.reservations with a new entry", -> - app.get('opnfv-promise.promise.reservations').length.should.be.above(0) - - it "should contain a new ResourceReservation record in the store", -> - assert reservation?.id?, "unable to check without ID" - reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) - assert reservation? - - # TC-06 - describe "create-instance", -> - allocation = undefined - - before -> - assert provider?, - "unable to execute without registered 'provider'" - assert reservation?, - "unable to execute without valid reservation record" - - it "should create a new server in target provider (with reservation) without error", (done) -> - @timeout 5000 - test = config.get 'openstack.test' - app.access('opnfv-promise').invoke 'create-instance', - 'provider-id': provider.id - name: 'promise-test-reservation' - image: test.image - flavor: test.flavor - networks: [ test.network ] - 'reservation-id': reservation.id - .then (res) -> - debug res.get() - res.get('result').should.equal 'ok' - allocation = id: res.get('instance-id') - done() - .catch (err) -> done err - - it "should contain a new ResourceAllocation record in the store", -> - assert allocation?.id?, "unable to check without ID" - allocation = app.access('opnfv-promise').find('ResourceAllocation', allocation.id) - assert allocation? - - it "should be referenced in the reservation record", -> - assert reservation? and allocation?, "unable to check without records" - reservation.get('allocations').should.containEql allocation.id - - it "should have high priority state", -> - assert allocation?, "unable to check without record" - allocation.get('priority').should.equal 'high' - - # Test Scenario 04 - describe "reservation for future use", -> - reservation = undefined - start = new Date - end = new Date - # 7 days in the future - start.setTime (start.getTime() + 7*60*60*1000) - # 8 days in the future - end.setTime (end.getTime() + 8*60*60*1000) - - # TC-07 - describe "create-reservation", -> - it "should create reservation record (for future) without error", (done) -> - app.access('opnfv-promise').invoke 'create-reservation', - start: start.toJSON() - end: end.toJSON() - capacity: - cores: 1 - ram: 12800 - addresses: 1 - instances: 1 - .then (res) -> - res.get('result').should.equal 'ok' - reservation = id: res.get('reservation-id') - done() - .catch (err) -> done err - - it "should update promise.reservations with a new entry", -> - app.get('opnfv-promise.promise.reservations').length.should.be.above(0) - - it "should contain a new ResourceReservation record in the store", -> - assert reservation?.id?, "unable to check without ID" - reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) - assert reservation? - - # TC-08 - describe "query-reservation", -> - it "should contain newly created future reservation", (done) -> - app.access('opnfv-promise').invoke 'query-reservation', - window: - start: start.toJSON() - end: end.toJSON() - .then (res) -> - res.get('reservations').should.containEql reservation.id - done() - .catch (err) -> done err - - # TC-09 - describe "update-reservation", -> - it "should modify existing reservation without error", (done) -> - app.access('opnfv-promise').invoke 'update-reservation', - 'reservation-id': reservation.id - capacity: - cores: 3 - ram: 12800 - addresses: 2 - instances: 2 - .then (res) -> - res.get('result').should.equal 'ok' - done() - .catch (err) -> done err - - # TC-10 - describe "cancel-reservation", -> - it "should modify existing reservation without error", (done) -> - app.access('opnfv-promise').invoke 'cancel-reservation', - 'reservation-id': reservation.id - .then (res) -> - res.get('result').should.equal 'ok' - done() - .catch (err) -> done err - - it "should no longer contain record of the deleted reservation", -> - assert reservation?.id?, "unable to check without ID" - reservation = app.access('opnfv-promise').find('ResourceReservation', reservation.id) - assert not reservation? - - # Test Scenario 05 - describe "capacity planning", -> - - # TC-11 - describe "decrease-capacity", -> - start = new Date - end = new Date - # 30 days in the future - start.setTime (start.getTime() + 30*60*60*1000) - # 45 days in the future - end.setTime (end.getTime() + 45*60*60*1000) - - it "should decrease available capacity from a provider in the future", (done) -> - app.access('opnfv-promise').invoke 'decrease-capacity', - source: provider - capacity: - cores: 5 - ram: 17920 - instances: 5 - start: start.toJSON() - end: end.toJSON() - .then (res) -> - res.get('result').should.equal 'ok' - done() - .catch (err) -> done err - - # TC-12 - describe "increase-capacity", -> - start = new Date - end = new Date - # 14 days in the future - start.setTime (start.getTime() + 14*60*60*1000) - # 21 days in the future - end.setTime (end.getTime() + 21*60*60*1000) - - it "should increase available capacity from a provider in the future", (done) -> - app.access('opnfv-promise').invoke 'decrease-capacity', - source: provider - capacity: - cores: 1 - ram: 3584 - instances: 1 - start: start.toJSON() - end: end.toJSON() - .then (res) -> - res.get('result').should.equal 'ok' - done() - .catch (err) -> done err - - # TC-13 (Should improve this TC) - describe "query-capacity", -> - it "should report available collections and utilizations", (done) -> - app.access('opnfv-promise').invoke 'query-capacity', - capacity: 'available' - .then (res) -> - res.get('collections').should.be.Array - res.get('collections').length.should.be.above(0) - res.get('utilization').should.be.Array - res.get('utilization').length.should.be.above(0) - done() - .catch (err) -> done err - - # Test Scenario 06 - describe "reservation with conflict", -> - # TC-14 - describe "create-reservation", -> - it "should fail to create immediate reservation record with proper error", (done) -> - app.access('opnfv-promise').invoke 'create-reservation', - capacity: - cores: 5 - ram: 17920 - instances: 10 - .then (res) -> - res.get('result').should.equal 'conflict' - done() - .catch (err) -> done err - - it "should fail to create future reservation record with proper error", (done) -> - start = new Date - # 30 days in the future - start.setTime (start.getTime() + 30*60*60*1000) - - app.access('opnfv-promise').invoke 'create-reservation', - capacity: - cores: 5 - ram: 17920 - instances: 10 - start: start.toJSON() - .then (res) -> - res.get('result').should.equal 'conflict' - done() - .catch (err) -> done err - - # Test Scenario 07 - describe "cleanup test allocations", -> - allocations = undefined - before -> - allocations = app.get('opnfv-promise.promise.allocations') - debug provider.get() - debug allocations - allocations.length.should.be.above(0) - - describe "destroy-instance", -> - it "should successfully destroy all allocations", (done) -> - @timeout 5000 - promises = allocations.map (x) -> - app.access('opnfv-promise').invoke 'destroy-instance', - 'instance-id': x.id - promise.all promises - .then (res) -> - res.forEach (x) -> - debug x.get() - x.get('result').should.equal 'ok' - done() - .catch (err) -> done err -- cgit 1.2.3-korg