From c1277826dba7647bfa266f71950a54f931dc2e18 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sat, 17 Oct 2015 16:03:52 -0400 Subject: [PATCH] Retire stackforge/occi-os --- .gitignore | 26 -- Authors | 4 - LICENSE | 176 ----------- README.md | 72 ----- README.rst | 7 + doc/occi.md | 112 ------- occi_os_api/__init__.py | 48 --- occi_os_api/backends/__init__.py | 21 -- occi_os_api/backends/compute.py | 184 ------------ occi_os_api/backends/network.py | 120 -------- occi_os_api/backends/openstack.py | 244 --------------- occi_os_api/backends/storage.py | 168 ----------- occi_os_api/extensions/__init__.py | 21 -- occi_os_api/extensions/os_addon.py | 82 ----- occi_os_api/extensions/os_mixins.py | 58 ---- occi_os_api/nova_glue/__init__.py | 21 -- occi_os_api/nova_glue/net.py | 128 -------- occi_os_api/nova_glue/security.py | 134 --------- occi_os_api/nova_glue/storage.py | 166 ----------- occi_os_api/nova_glue/vm.py | 448 ---------------------------- occi_os_api/registry.py | 422 -------------------------- occi_os_api/wsgi.py | 261 ---------------- run_tests.sh | 53 ---- runme.py | 43 --- setup.py | 58 ---- tests/system_test.py | 438 --------------------------- tests/test_backends_compute.py | 331 -------------------- tests/test_backends_network.py | 200 ------------- tests/test_backends_storage.py | 296 ------------------ 29 files changed, 7 insertions(+), 4335 deletions(-) delete mode 100644 .gitignore delete mode 100644 Authors delete mode 100644 LICENSE delete mode 100644 README.md create mode 100644 README.rst delete mode 100644 doc/occi.md delete mode 100644 occi_os_api/__init__.py delete mode 100644 occi_os_api/backends/__init__.py delete mode 100644 occi_os_api/backends/compute.py delete mode 100644 occi_os_api/backends/network.py delete mode 100644 occi_os_api/backends/openstack.py delete mode 100644 occi_os_api/backends/storage.py delete mode 100644 occi_os_api/extensions/__init__.py delete mode 100644 occi_os_api/extensions/os_addon.py delete mode 100644 occi_os_api/extensions/os_mixins.py delete mode 100644 occi_os_api/nova_glue/__init__.py delete mode 100644 occi_os_api/nova_glue/net.py delete mode 100644 occi_os_api/nova_glue/security.py delete mode 100644 occi_os_api/nova_glue/storage.py delete mode 100644 occi_os_api/nova_glue/vm.py delete mode 100644 occi_os_api/registry.py delete mode 100644 occi_os_api/wsgi.py delete mode 100755 run_tests.sh delete mode 100755 runme.py delete mode 100644 setup.py delete mode 100644 tests/system_test.py delete mode 100644 tests/test_backends_compute.py delete mode 100644 tests/test_backends_network.py delete mode 100644 tests/test_backends_storage.py diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d18d125..0000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -*.py[co] - -# Packages -*.egg -*.egg-info -*.old -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -# Installer logs -pip-log.txt -# Unit test / coverage reports -.coverage -.tox -#Translations -*.mo -#Mr Developer -.mr.developer.cfg -.idea/* -/.idea/ diff --git a/Authors b/Authors deleted file mode 100644 index 1f89b4f..0000000 --- a/Authors +++ /dev/null @@ -1,4 +0,0 @@ -Thijs Metsch -Andy Edmonds -Álvaro López García -Björn Hagemeier diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +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. - diff --git a/README.md b/README.md deleted file mode 100644 index 01c6140..0000000 --- a/README.md +++ /dev/null @@ -1,72 +0,0 @@ -OCCI for OpenStack -================== - -This is a clone and continuation of https://github.com/dizz/nova - it -provides a python egg which can be easily deployed in [OpenStack](http://www -.openstack.org) and will thereby add the 3rd party [OCCI](http://www.occi-wg -.org) interface to OpenStack. For usage examples, [see the OpenStack wiki] -(http://wiki.openstack.org/occi). - -Usage ------ - -0. Install dependencies: `pip install pyssf` -1. Install this egg: `python setup.py install` (or `pip install -openstackocci-grizzly`) -2. Configure OpenStack - Add application to `api-paste.ini` of nova and -enable the API - -***Note***: do not install the [occi](http://pypi.python.org/pypi/occi/0.6) -package via `pip`. This is a seperate project and not related to OpenStack & - OCCI. - -### Configuration - -Make sure an application is configured in `api-paste.ini` (name can be -picked yourself): - - ######## - # OCCI # - ######## - - [composite:occiapi] - use = egg:Paste#urlmap - /: occiapppipe - - [pipeline:occiapppipe] - pipeline = authtoken keystonecontext occiapp - # with request body size limiting and rate limiting - # pipeline = sizelimit authtoken keystonecontext ratelimit occiapp - - [app:occiapp] - use = egg:openstackocci-grizzly#occi_app - -Make sure the API (name from above) is enabled in `nova.conf`: - - [...] - enabled_apis=ec2,occiapi,osapi_compute,osapi_volume,metadata - [...] - -#### Hacking the port number - -(Optional) You can set the port option via the `nova.conf` configuration -file - default is 8787: - - [...] - occiapi_listen_port=9999 - [...] - -There is further documentation on [setting up your development environment -in the wiki](https://github.com/tmetsch/occi-os/wiki/DevEnv). - -#Versioning - -The general naming scheme for the Python eggs is: - -* openstackocci - for the latest and greatest -* openstackocci-\ - for OpenStack release specific stable releases - -# Deployment using Puppet -This library can be integrated using puppet as a configuration management tool. -See [this blog post for more details](http://www.cloudcomp.ch/2012/09/automating-occi-installations/). - diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..9006052 --- /dev/null +++ b/README.rst @@ -0,0 +1,7 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git source code +management system. To see the contents of this repository before it reached +its end of life, please check out the previous commit with +"git checkout HEAD^1". + diff --git a/doc/occi.md b/doc/occi.md deleted file mode 100644 index ddfd298..0000000 --- a/doc/occi.md +++ /dev/null @@ -1,112 +0,0 @@ -# Note: -This documentation may not be current in places. There is also further documentation at the [openstack wiki](https://wiki.openstack.org/wiki/Occi) - - -# OCCI and OpenStack: What can I do? -This guide will explain what you can do with the current OCCI implementation for OpenStack - -## First up, prerequisites: -### Get a running instance of OpenStack -Lots of ways to do this: - - * Install via apt-get - * Install with puppet - * Install with chef - * Install with crowbar - * Install with devstack - -The easiest is devstack. -### Get the OCCI code - -#### OCCI Library -On the machine(s) that you run the OCCI API, likely the same as the machine(s) as you run the OS-API, run the following: - ->```pip install pyssf``` - -#### OCCI API Implementation -On the machine(s) that you want to run the OCCI API, likely the same as the machine(s) as you run the OS-API, run the following: - ->```cd $YOUR_NOVA_INSTALL_LOCATION``` - ->```git add remote occi-upstream git://git@github.com/dizz/nova``` - ->```git fetch occi-upstream``` - ->```git merge occi-upstream/master``` - -### Configure devstack to run the volume service. Edit localrc and insert: ->```ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-sch,n-novnc,n-xvnc,n-cauth,horizon,mysql,rabbit,n-vol,openstackx``` - -### Run the OS-OCCI API ->```./bin/nova-api-occi --verbose --glance_api_servers=10.211.55.27:9292 --rabbit_host=10.211.55.27 --rabbit_password=admin --sql_connection=mysql://root:admin@10.211.55.27/nova``` - -### Get Authentication Credentials from Keystone ->```curl -d '{"auth":{"passwordCredentials":{"username": "admin", "password": "admin"}}}' -H "Content-type: application/json" http://10.211.55.27:35357/v2.0/tokens -``` - ->```export $KID=<>``` - -## OCCI-ness - -_Note:_ some confusion will happen if a content-type is not specified. - -### See What Can be Provisioned ->```curl -v -H 'X-Auth-Token: '$KID -H -X GET 0.0.0.0:8787/-/ -``` - -### Create a VM ->```curl -v -X POST localhost:8787/compute/ -H 'Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"' -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: m1.tiny; scheme="http://schemas.openstack.org/template/resource#"; class="mixin"' -H 'Category: cirros-0.3.0-x86_64-blank; scheme="http://schemas.openstack.org/template/os#"; class="mixin"' -``` - -### Get a Listing of VMs ->```curl -v -X GET localhost:8787/compute/ -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -``` - -### Get an Individual VM's details ->```curl -v -X GET localhost:8787/compute/d54b4344-16be-486a-9871-2c566ef2263d -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -``` - -### Execute a Stop Action Upon a VM ->```curl -v -X POST localhost:8787/compute/d54b4344-16be-486a-9871-2c566ef2263d?action=stop -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: stop; scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#"; class="action"' -``` - -### Execute a Start Action Upon a VM -_Note: this will probably result in an error state. Currently looking into the issue._ - ->```curl -v -X POST localhost:8787/compute/888fc64a-4500-4543-bed4-8ddf3938dcb5?action=start -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: start; scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#"; class="action"' -``` - -### Delete a VM ->```curl -v -X DELETE localhost:8787/compute/d54b4344-16be-486a-9871-2c566ef2263d -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -``` - -### Create some a block storage volume ->```curl -v -X POST localhost:8787/storage/ -H 'Category: storage; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"' -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'occi.storage.size = 1.0' -``` - -### Link and associate that volume to the new instance ->```curl -v -X POST localhost:8787/storage/link/ -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: storagelink; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"' -H 'X-OCCI-Attribute: occi.core.source="http://localhost:8787/compute/e7a34bc4-02e7-43e3-a543-8aec630b5364"' -H 'X-OCCI-Attribute: occi.core.target="http://localhost:8787/storage/1"' -H 'X-OCCI-Attribute: occi.storagelink.mountpoint="/dev/vdb"' -H 'Content-Type: text/occi'``` - -### Unlink and disassociate that volume with the new instance ->```curl -v -X DELETE localhost:8787/storage/link/6cb97f63-7d8a-4474-87cb-4d1c9c581de1 -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Content-Type: text/occi'``` - -## Upcoming -### Update a VM: Scale up! -Let's bump the current instance from tiny (512) to a custom flavour (768R, 1C). -_Notes:_ - -* This is a partial update with respect to OCCI. -* This only works with Xen currently - * otherwise it fails silently - ->```curl -v -X POST localhost:8787/compute/2ee26373-db62-4bbf-9325-ff68a81097e3 -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: m1.medium; scheme="http://schemas.openstack.org/template/resource#"; class="mixin"' -``` - -### Update a VM: Change the OS! -Let's use SmartOS as the new OS -_Notes:_ - -* this is in effect a partial update. - ->```curl -v -X POST localhost:8787/compute/d54b4344-16be-486a-9871-2c566ef2263d -H 'Content-Type: text/occi' -H 'X-Auth-Token: '$KID -H 'X-Auth-Project-ID: 1' -H 'Category: SmartOS; scheme="http://schemas.openstack.org/template/os#"; class="mixin"' -``` diff --git a/occi_os_api/__init__.py b/occi_os_api/__init__.py deleted file mode 100644 index 2aa2eab..0000000 --- a/occi_os_api/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -# coding=utf-8 - -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -This it the entry point for paste. - -Paste config file needs to point to egg::: - - use = egg:occi-os#sample_app - -sample_app entry point is defined in setup.py: - - entry_points=''' - [paste.app_factory] - sample_app = occiosapi:main - ''', - -which point to this function call (:function). -""" - -# W0613:unused args -# pylint: disable=W0613 - -from occi_os_api import wsgi - - -#noinspection PyUnusedLocal -def main(global_config, **settings): - """ - This is the entry point for paste into the OCCI OS world. - """ - return wsgi.OCCIApplication() diff --git a/occi_os_api/backends/__init__.py b/occi_os_api/backends/__init__.py deleted file mode 100644 index a5898c4..0000000 --- a/occi_os_api/backends/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Package for all the backends! -""" diff --git a/occi_os_api/backends/compute.py b/occi_os_api/backends/compute.py deleted file mode 100644 index 3e9d48c..0000000 --- a/occi_os_api/backends/compute.py +++ /dev/null @@ -1,184 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -The compute resource backend for OpenStack. -""" - -#pylint: disable=W0232,R0201 - -import logging - -from occi_os_api.extensions import os_mixins -from occi_os_api.extensions import os_addon -from occi_os_api.nova_glue import vm -from occi_os_api.nova_glue import storage - -from occi.backend import KindBackend, ActionBackend -from occi.extensions import infrastructure - -LOG = logging.getLogger(__name__) - - -class ComputeBackend(KindBackend, ActionBackend): - """ - The compute backend. - """ - - def create(self, entity, extras): - """ - Create a VM. - """ - LOG.debug('Creating an Virtual machine') - - # ignore some attributes - done via templating - if 'occi.compute.cores' in entity.attributes or \ - 'occi.compute.speed' in entity.attributes or \ - 'occi.compute.memory' in entity.attributes or \ - 'occi.compute.architecture' in entity.attributes: - raise AttributeError('There are unsupported attributes in the ' - 'request.') - - # create the VM - context = extras['nova_ctx'] - instance = vm.create_vm(entity, context) - uid = instance['uuid'] - entity.identifier = '/compute/' + uid - - # set some attributes - entity.attributes['occi.compute.hostname'] = instance['hostname'] - entity.attributes['occi.compute.architecture'] = \ - storage.get_image_architecture(uid, extras['nova_ctx']) - entity.attributes['occi.compute.cores'] = str(instance['vcpus']) - entity.attributes['occi.compute.speed'] = str(0.0) # N/A in instance - value = str(float(instance['memory_mb']) / 1024) - entity.attributes['occi.compute.memory'] = value - entity.attributes['occi.compute.state'] = 'inactive' - - # set valid actions - entity.actions = [infrastructure.STOP, - infrastructure.SUSPEND, - infrastructure.RESTART] - - # Tell the world that is is an VM in OpenStack... - entity.mixins.append(os_addon.OS_VM) - - def retrieve(self, entity, extras): - """ - Retrieve a VM. - """ - uid = entity.attributes['occi.core.id'] - context = extras['nova_ctx'] - instance = vm.get_vm(uid, context) - - LOG.debug('Retrieving an Virtual machine: ' + repr(uid)) - - # set state and applicable actions! - state, actions = vm.get_occi_state(uid, context) - entity.attributes['occi.compute.state'] = state - entity.actions = actions - - # set up to date attributes - entity.attributes['occi.compute.hostname'] = instance['hostname'] - entity.attributes['occi.compute.architecture'] =\ - storage.get_image_architecture(uid, extras['nova_ctx']) - entity.attributes['occi.compute.cores'] = str(instance['vcpus']) - entity.attributes['occi.compute.speed'] = str(0.0) # N/A in instance - value = str(float(instance['memory_mb']) / 1024) - entity.attributes['occi.compute.memory'] = value - - def update(self, old, new, extras): - """ - Update an VM. - """ - context = extras['nova_ctx'] - uid = old.attributes['occi.core.id'] - - LOG.debug('Updating an Virtual machine: ' + repr(uid)) - - # for now we will only handle one mixin change per request - if len(new.mixins) != 1: - raise AttributeError('Only updates with one mixin in request are' - ' currently supported') - - mixin = new.mixins[0] - if isinstance(mixin, os_mixins.ResourceTemplate): - flavor_id = mixin.res_id - vm.resize_vm(uid, flavor_id, context) - old.attributes['occi.compute.state'] = 'inactive' - # now update the mixin info - old.mixins.append(mixin) - elif isinstance(mixin, os_mixins.OsTemplate): - image_href = mixin.os_id - vm.rebuild_vm(uid, image_href, context) - old.attributes['occi.compute.state'] = 'inactive' - # now update the mixin info - old.mixins.append(mixin) - else: - msg = 'Unrecognized mixin. %s' % str(mixin) - LOG.error(msg) - raise AttributeError(msg) - - def replace(self, old, new, extras): - """ - XXX:not doing anything - full updates are hard :-) - """ - pass - - def delete(self, entity, extras): - """ - Remove a VM. - """ - msg = 'Removing representation of virtual machine with id: %s' %\ - entity.identifier - LOG.info(msg) - - context = extras['nova_ctx'] - uid = entity.attributes['occi.core.id'] - - vm.delete_vm(uid, context) - - def action(self, entity, action, attributes, extras): - """ - Perform an action. - """ - # As there is no callback mechanism to update the state - # of computes known by occi, a call to get the latest representation - # must be made. - context = extras['nova_ctx'] - uid = entity.attributes['occi.core.id'] - - # set state and applicable actions - so even if the user hasn't done - # a GET het can still the most applicable action now... - state, actions = vm.get_occi_state(uid, context) - entity.attributes['occi.compute.state'] = state - entity.actions = actions - - if action not in entity.actions: - raise AttributeError("This action is currently not applicable.") - elif action == infrastructure.START: - vm.start_vm(uid, context) - elif action == infrastructure.STOP: - vm.stop_vm(uid, context) - elif action == infrastructure.RESTART: - if not 'method' in attributes: - raise AttributeError('Please provide a method!') - method = attributes['method'] - vm.restart_vm(uid, method, context) - elif action == infrastructure.SUSPEND: - vm.suspend_vm(uid, context) diff --git a/occi_os_api/backends/network.py b/occi_os_api/backends/network.py deleted file mode 100644 index 3bc84dd..0000000 --- a/occi_os_api/backends/network.py +++ /dev/null @@ -1,120 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Network resource backend. -""" - -#W0613:unused arguments,R0201:mth could be func,R0903:too few pub mthd. -#W0232:no init -#pylint: disable=W0613,R0201,R0903,W0232 - - -from occi import backend -from occi_os_api.extensions import os_addon -from occi_os_api.nova_glue import net - - -class NetworkBackend(backend.KindBackend, backend.ActionBackend): - """ - Backend to handle network resources. - """ - - def create(self, entity, extras): - """ - Currently unsupported. - """ - raise AttributeError('Currently not supported.') - - def action(self, entity, action, attributes, extras): - """ - Currently unsupported. - """ - raise AttributeError('Currently not supported.') - - -class IpNetworkBackend(backend.MixinBackend): - """ - A mixin backend for the IPnetworking. - """ - - def create(self, entity, extras): - """ - Currently unsupported. - """ - raise AttributeError('Currently not supported.') - - -class IpNetworkInterfaceBackend(backend.MixinBackend): - """ - A mixin backend for the IpNetworkingInterface (covered by - NetworkInterfaceBackend). - """ - - pass - - -class NetworkInterfaceBackend(backend.KindBackend): - """ - A backend for network links. - """ - - def create(self, link, extras): - """ - As nova does not support creation of L2 networks we don't. - """ - if link.target.identifier == '/network/public': - # public means floating IP in OS! - # if the os_net_link mixin is avail. a pool must be provided: - if not 'org.openstack.network.floating.pool' in link.attributes\ - and os_addon.OS_NET_LINK in link.mixins: - raise AttributeError('Please specify the pool name when using' - ' this mixin!') - elif os_addon.OS_NET_LINK in link.mixins: - pool = link.attributes['org.openstack.network.floating.pool'] - else: - pool = None - address = net.add_floating_ip(link.source.attributes['occi.' - 'core.id'], - pool, - extras['nova_ctx']) - link.attributes['occi.networkinterface.interface'] = 'eth0' - link.attributes['occi.networkinterface.mac'] = 'aa:bb:cc:dd:ee:ff' - link.attributes['occi.networkinterface.state'] = 'active' - link.attributes['occi.networkinterface.address'] = address - link.attributes['occi.networkinterface.gateway'] = '0.0.0.0' - link.attributes['occi.networkinterface.allocation'] = 'static' - else: - raise AttributeError('Currently not supported.') - - def update(self, old, new, extras): - """ - Allows for the update of network links. - """ - raise AttributeError('Currently not supported.') - - def delete(self, link, extras): - """ - Remove a floating ip! - """ - if link.target.identifier == '/network/public': - # public means floating IP in OS! - net.remove_floating_ip(link.source.attributes['occi.core.id'], - link.attributes['occi.networkinterface.' - 'address'], - extras['nova_ctx']) diff --git a/occi_os_api/backends/openstack.py b/occi_os_api/backends/openstack.py deleted file mode 100644 index fd802a3..0000000 --- a/occi_os_api/backends/openstack.py +++ /dev/null @@ -1,244 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -The compute resource backend for OpenStack. -""" - -#pylint: disable=W0232,R0201 -import random -from occi import backend -from occi import exceptions - -from occi_os_api.extensions import os_addon -from occi_os_api.nova_glue import vm -from occi_os_api.nova_glue import security - - -class OsComputeBackend(backend.MixinBackend, backend.ActionBackend): - """ - The OpenStackCompute backend. - """ - - def retrieve(self, entity, extras): - """ - Add OpenStack related actions. - """ - uid = entity.attributes['occi.core.id'] - context = extras['nova_ctx'] - - # set additional actions - if 'occi.compute.state' in entity.attributes and entity.attributes[ - 'occi.compute.state'] == 'active': - entity.actions.append(os_addon.OS_CREATE_IMAGE) - entity.actions.append(os_addon.OS_CHG_PWD) - - # add VNC link if available - console = vm.get_vnc(uid, context) - if console: - entity.attributes['org.openstack.compute.console.vnc'] =\ - console['url'] - else: - entity.attributes['org.openstack.compute.console.vnc'] = 'N/A' - - # also expose the exact openstack state - entity.attributes['org.openstack.compute.state'] = \ - vm.get_vm(uid, context)['vm_state'] - - def action(self, entity, action, attributes, extras): - """ - This is called by pyssf when an action request is issued. - """ - context = extras['nova_ctx'] - uid = entity.attributes['occi.core.id'] - - if action == os_addon.OS_CHG_PWD: - if 'org.openstack.credentials.admin_pwd' not in attributes: - msg = 'org.openstack.credentials.admin_pwd was not supplied'\ - ' in the request.' - raise AttributeError(msg) - - new_password = attributes['org.openstack.credentials.admin_pwd'] - vm.set_password_for_vm(uid, new_password, context) - elif action == os_addon.OS_CREATE_IMAGE: - if 'org.openstack.snapshot.image_name' not in attributes: - raise AttributeError('Missing image name') - - image_name = attributes['org.openstack.snapshot.image_name'] - vm.snapshot_vm(uid, image_name, context) - else: - raise AttributeError('Not an applicable action.') - - -class OsNetLinkBackend(backend.MixinBackend, backend.ActionBackend): - """ - The OpenStack network link backend. - """ - - pass - - -class SecurityGroupBackend(backend.UserDefinedMixinBackend): - """ - Security Group backend. - """ - - def init_sec_group(self, category, extras): - """ - Creates the security group as specified in the request. - """ - #do not recreate default openstack security groups - if category.scheme == \ - 'http://schemas.openstack.org/infrastructure/security/group#': - return - - context = extras['nova_ctx'] - - group_name = category.term.strip() - group_description = (category.title.strip() - if category.title else group_name) - - security.create_group(group_name, group_description, context) - - def destroy(self, category, extras): - """ - Deletes the specified security group. - """ - context = extras['nova_ctx'] - security_group = security.retrieve_group(category.term, - extras['nova_ctx']) - security.remove_group(security_group.id, context) - - -class SecurityRuleBackend(backend.KindBackend): - """ - Security rule backend. - """ - - def create(self, entity, extras): - """ - Creates a security rule. - The group to add the rule to must exist. - In OCCI-speak this means the mixin must be supplied with the request - """ - sec_mixin = get_sec_mixin(entity) - context = extras['nova_ctx'] - security_group = security.retrieve_group(sec_mixin.term, - context) - sg_rule = make_sec_rule(entity, security_group['id']) - - if security_group_rule_exists(security_group, sg_rule): - #This rule already exists in group - msg = 'This rule already exists in group. %s' %\ - str(security_group) - raise AttributeError(msg) - - security.create_rule(sg_rule, context) - - def delete(self, entity, extras): - """ - Deletes the security rule. - """ - try: - context = extras['nova_ctx'] - rule = security.retrieve_rule(entity.attributes['occi.core.id'], - context) - - security.remove_rule(rule, context) - except Exception as error: - raise exceptions.HTTPError(500, str(error)) - - -def make_sec_rule(entity, sec_grp_id): - """ - Create and validate the security rule. - """ - name = random.randrange(0, 99999999) - sg_rule = {'id': name, - 'parent_group_id': sec_grp_id} - entity.attributes['occi.core.id'] = str(sg_rule['id']) - prot = \ - entity.attributes['occi.network.security.protocol'].lower().strip() - if prot in ('tcp', 'udp', 'icmp'): - sg_rule['protocol'] = prot - else: - raise AttributeError('Invalid protocol defined:' + prot) - from_p = entity.attributes['occi.network.security.to'].strip() - from_p = int(from_p) - if (type(from_p) is int) and 0 < from_p <= 65535: - sg_rule['from_port'] = from_p - else: - raise AttributeError('No valid from port defined.') - to_p = entity.attributes['occi.network.security.to'].strip() - to_p = int(to_p) - if (type(to_p) is int) and 0 < to_p <= 65535: - sg_rule['to_port'] = to_p - else: - raise AttributeError('No valid to port defined.') - if from_p > to_p: - raise AttributeError('From port is bigger than to port defined.') - cidr = entity.attributes['occi.network.security.range'].strip() - if len(cidr) <= 0: - cidr = '0.0.0.0/0' - if True: - sg_rule['cidr'] = cidr - else: - raise AttributeError('No valid CIDR defined.') - sg_rule['group'] = {} - return sg_rule - - -def get_sec_mixin(entity): - """ - Get the security mixin of the supplied entity. - """ - sec_mixin_present = 0 - sec_mixin = None - for mixin in entity.mixins: - if os_addon.SEC_GROUP in mixin.related: - sec_mixin = mixin - sec_mixin_present += 1 - - if not sec_mixin_present: - # no mixin of the type security group was found - msg = 'No security group mixin was found' - raise AttributeError(msg) - if sec_mixin_present > 1: - msg = 'More than one security group mixin was found' - raise AttributeError(msg) - - return sec_mixin - - -def security_group_rule_exists(security_group, values): - """ - Indicates whether the specified rule values are already - defined in the given security group. - """ - # Taken directly from security_groups.py as that method is not - # directly import-able. - for rule in security_group['rules']: - is_duplicate = True - keys = ('group_id', 'cidr', 'from_port', 'to_port', 'protocol') - for key in keys: - if rule.get(key) != values.get(key): - is_duplicate = False - break - if is_duplicate: - return True - return False diff --git a/occi_os_api/backends/storage.py b/occi_os_api/backends/storage.py deleted file mode 100644 index 56a350a..0000000 --- a/occi_os_api/backends/storage.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Backends for the storage resource. -""" - -#pylint: disable=R0201,W0232,W0613 -from datetime import date - -import logging -import uuid - -from occi import backend -from occi import exceptions -from occi.extensions import infrastructure - -from occi_os_api.nova_glue import storage -from occi_os_api.nova_glue import vm - -LOG = logging.getLogger(__name__) - - -class StorageBackend(backend.KindBackend, backend.ActionBackend): - """ - Backend to handle storage resources. - """ - - def create(self, entity, extras): - """ - Creates a new volume. - """ - context = extras['nova_ctx'] - if 'occi.storage.size' not in entity.attributes: - raise AttributeError('size attribute not found!') - - new_volume = storage.create_storage(entity.attributes['occi.storage' - '.size'], - context) - vol_id = new_volume['id'] - - # Work around problem that instance is lazy-loaded... - new_volume = storage.get_storage(vol_id, context) - - if new_volume['status'] == 'error': - raise exceptions.HTTPError(500, 'There was an error creating the ' - 'volume') - entity.attributes['occi.core.id'] = str(vol_id) - entity.identifier = infrastructure.STORAGE.location + vol_id - - if new_volume['status'] == 'available': - entity.attributes['occi.storage.state'] = 'active' - - entity.actions = [infrastructure.OFFLINE, infrastructure.BACKUP, - infrastructure.SNAPSHOT, infrastructure.RESIZE] - - def retrieve(self, entity, extras): - """ - Gets a representation of the storage volume and presents it ready for - rendering by pyssf. - """ - v_id = entity.attributes['occi.core.id'] - - volume = storage.get_storage(v_id, extras['nova_ctx']) - - entity.attributes['occi.storage.size'] = str(float(volume['size'])) - - # OS volume states: - # available, creating, deleting, in-use, error, error_deleting - if volume['status'] == 'available' or volume['status'] == 'in-use': - entity.attributes['occi.storage.state'] = 'online' - entity.actions = [infrastructure.OFFLINE, infrastructure.BACKUP, - infrastructure.SNAPSHOT, infrastructure.RESIZE] - else: - entity.attributes['occi.storage.state'] = 'offline' - entity.actions = [infrastructure.ONLINE] - - def update(self, old, new, extras): - """ - Updates simple attributes of a storage resource: - occi.core.title, occi.core.summary - """ - # update attributes. - if len(new.attributes) > 0: - # support only title and summary changes now. - if 'occi.core.title' in new.attributes and \ - len(new.attributes['occi.core.title']) > 0: - old.attributes['occi.core.title'] = \ - new.attributes['occi.core.title'] - if 'occi.core.title' in new.attributes and \ - len(new.attributes['occi.core.summary']) > 0: - old.attributes['occi.core.summary'] = \ - new.attributes['occi.core.summary'] - - def delete(self, entity, extras): - """ - Deletes the storage resource - """ - context = extras['nova_ctx'] - volume_id = entity.attributes['occi.core.id'] - - storage.delete_storage_instance(volume_id, context) - - def action(self, entity, action, attributes, extras): - """ - Executes actions against the target storage resource. - """ - if action not in entity.actions: - raise AttributeError("This action is currently no applicable.") - elif action in [infrastructure.ONLINE, infrastructure.OFFLINE, - infrastructure.BACKUP, infrastructure.RESIZE]: - LOG.warn('The operations online, offline, backup and resize are ' - 'currently not supported!') - elif action == infrastructure.SNAPSHOT: - volume_id = entity.attributes['occi.core.id'] - name = volume_id + date.today().isoformat() - if 'occi.core.summary' in entity.attributes: - description = entity.attributes['occi.core.summary'] - else: - description = 'N/A' - storage.snapshot_storage_instance(volume_id, name, description, - extras['nova_ctx']) - - -class StorageLinkBackend(backend.KindBackend): - """ - A backend for the storage links. - """ - - def create(self, link, extras): - """ - Creates a link from a compute instance to a storage volume. - The user must specify what the device id is to be. - """ - context = extras['nova_ctx'] - instance_id = link.source.attributes['occi.core.id'] - volume_id = link.target.attributes['occi.core.id'] - mount_point = link.attributes['occi.storagelink.deviceid'] - - vm.attach_volume(instance_id, volume_id, mount_point, context) - - link.attributes['occi.core.id'] = str(uuid.uuid4()) - link.attributes['occi.storagelink.deviceid'] = \ - link.attributes['occi.storagelink.deviceid'] - link.attributes['occi.storagelink.mountpoint'] = '' - link.attributes['occi.storagelink.state'] = 'active' - - def delete(self, link, extras): - """ - Unlinks the the compute from the storage resource. - """ - volume_id = link.target.attributes['occi.core.id'] - vm.detach_volume(volume_id, extras['nova_ctx']) diff --git a/occi_os_api/extensions/__init__.py b/occi_os_api/extensions/__init__.py deleted file mode 100644 index e901cf8..0000000 --- a/occi_os_api/extensions/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -A package containing extensions for OCCI. -""" diff --git a/occi_os_api/extensions/os_addon.py b/occi_os_api/extensions/os_addon.py deleted file mode 100644 index 1e0acca..0000000 --- a/occi_os_api/extensions/os_addon.py +++ /dev/null @@ -1,82 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Set of extensions to get OCCI work with OpenStack. -""" - -#pylint: disable=W0232,R0912,R0201,R0903 - -from occi import core_model - -# Network security rule extension to specify firewall rules -_SEC_RULE_ATTRIBUTES = { - 'occi.network.security.protocol': '', - 'occi.network.security.to': '', - 'occi.network.security.from': '', - 'occi.network.security.range': '', -} -SEC_RULE = core_model.Kind( - 'http://schemas.openstack.org/occi/infrastructure/network/security#', - 'rule', - [core_model.Resource.kind], - None, - 'Network security rule kind', - _SEC_RULE_ATTRIBUTES, - '/network/security/rule/') - -# Network security rule group -SEC_GROUP = core_model.Mixin( - 'http://schemas.ogf.org/occi/infrastructure/security#', - 'group', attributes=None) - -# OS change adminstrative password action -_OS_CHG_PWD_ATTRIBUTES = {'org.openstack.credentials.admin_pwd': '', } -OS_CHG_PWD = core_model.Action( - 'http://schemas.openstack.org/instance/action#', - 'chg_pwd', 'Changes Admin password.', - _OS_CHG_PWD_ATTRIBUTES) - -# OS create image from VM action -_OS_CREATE_IMAGE_ATTRIBUTES = {'org.openstack.snapshot.image_name': '', } -OS_CREATE_IMAGE = core_model.Action( - 'http://schemas.openstack.org/instance/action#', - 'create_image', 'Creates a new image for the given server.', - _OS_CREATE_IMAGE_ATTRIBUTES) - -# A Mixin for OpenStack VMs -_OS_VM_ATTRIBUTES = {'org.openstack.compute.console.vnc': 'immutable', - 'org.openstack.compute.state': 'immutable'} -OS_VM = core_model.Mixin( - 'http://schemas.openstack.org/compute/instance#', - 'os_vms', actions=[OS_CHG_PWD, OS_CREATE_IMAGE], - attributes=_OS_VM_ATTRIBUTES) - -# OS Key pair extension -_OS_KEY_PAIR_ATTRIBUTES = {'org.openstack.credentials.publickey.name': '', - 'org.openstack.credentials.publickey.data': '', } -OS_KEY_PAIR_EXT = core_model.Mixin( - 'http://schemas.openstack.org/instance/credentials#', - 'public_key', attributes=_OS_KEY_PAIR_ATTRIBUTES) - -# A Mixin for OpenStack Network links -_OS_NET_LINK_ATTRIBUTES = {'org.openstack.network.floating.pool': 'required'} -OS_NET_LINK = core_model.Mixin( - 'http://schemas.openstack.org/network/instance#', - 'os_net_link', actions=[], - attributes=_OS_NET_LINK_ATTRIBUTES) diff --git a/occi_os_api/extensions/os_mixins.py b/occi_os_api/extensions/os_mixins.py deleted file mode 100644 index bd86b67..0000000 --- a/occi_os_api/extensions/os_mixins.py +++ /dev/null @@ -1,58 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Set of templates. -""" - -#pylint: disable=R0913,E1002,R0903,W0232 - -from occi import core_model - - -class OsTemplate(core_model.Mixin): - """ - Represents the OS Template mechanism as per OCCI specification. - An OS template is equivalent to an image in OpenStack - """ - def __init__(self, scheme, term, os_id=None, related=None, actions=None, - title='', attributes=None, location=None): - super(OsTemplate, self).__init__(scheme, term, related, actions, - title, attributes, location) - self.os_id = os_id - - -class ResourceTemplate(core_model.Mixin): - """ - Here to make identification of template type easier in backends. - """ - - def __init__(self, scheme, term, flavor_id=None, related=None, - actions=None, title='', - attributes=None, location=None): - super(ResourceTemplate, self).__init__(scheme, term, related, - actions, title, attributes, - location) - self.res_id = flavor_id - - -class UserSecurityGroupMixin(core_model.Mixin): - """ - Empty Mixin. - """ - pass diff --git a/occi_os_api/nova_glue/__init__.py b/occi_os_api/nova_glue/__init__.py deleted file mode 100644 index ba2b4e9..0000000 --- a/occi_os_api/nova_glue/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Package which connects everything to the nova layer... -""" diff --git a/occi_os_api/nova_glue/net.py b/occi_os_api/nova_glue/net.py deleted file mode 100644 index 83cf105..0000000 --- a/occi_os_api/nova_glue/net.py +++ /dev/null @@ -1,128 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Network related 'glue' :-) -""" - -import logging - -from nova import network -from nova import exception -from nova import compute -from nova.compute import utils - -from occi_os_api.nova_glue import vm - -# Connect to nova :-) - -NETWORK_API = network.API() -COMPUTE_API = compute.API() - -LOG = logging.getLogger(__name__) - - -def get_network_details(uid, context): - """ - Extracts the VMs network adapter information. - - uid -- Id of the VM. - context -- The os context. - """ - vm_instance = vm.get_vm(uid, context) - - result = {'public': [], 'admin': []} - try: - net_info = NETWORK_API.get_instance_nw_info(context, vm_instance)[0] - except IndexError: - LOG.warn('Unable to retrieve network information - this is because ' - 'of OpenStack!!') - return result - gw = net_info['network']['subnets'][0]['gateway']['address'] - mac = net_info['address'] - - if len(net_info['network']['subnets'][0]['ips']) == 0: - tmp = {'floating_ips': [], 'address': '0.0.0.0'} - else: - tmp = net_info['network']['subnets'][0]['ips'][0] - for item in tmp['floating_ips']: - result['public'].append({'interface': 'eth0', - 'mac': 'aa:bb:cc:dd:ee:ff', - 'state': 'active', - 'address': item['address'], - 'gateway': '0.0.0.0', - 'allocation': 'static'}) - result['admin'].append({'interface': 'eth0', - 'mac': mac, - 'state': 'active', - 'address': tmp['address'], - 'gateway': gw, - 'allocation': 'static'}) - - return result - - -def add_floating_ip(uid, pool_name, context): - """ - Adds an ip to an VM instance. - - uid -- id of the VM. - pool_name -- name of the pool - context -- The os context. - """ - vm_instance = vm.get_vm(uid, context) - - cached_nwinfo = utils.get_nw_info_for_instance(vm_instance) - if not cached_nwinfo: - raise AttributeError('No nw_info cache associated with instance') - - fixed_ips = cached_nwinfo.fixed_ips() - if not fixed_ips: - raise AttributeError('No fixed ips associated to instance') - - float_address = NETWORK_API.allocate_floating_ip(context, pool_name) - - try: - address = fixed_ips[0]['address'] - NETWORK_API.associate_floating_ip(context, vm_instance, - float_address, address) - except exception.FloatingIpAssociated: - msg = 'floating ip is already associated' - raise AttributeError(msg) - except exception.NoFloatingIpInterface: - msg = 'l3driver call to add floating ip failed' - raise AttributeError(msg) - return float_address - - -def remove_floating_ip(uid, address, context): - """ - Remove a given address from an VM instance. - - uid -- Id of the VM. - address -- The ip address. - context -- The os context. - """ - vm_instance = vm.get_vm(uid, context) - - try: - NETWORK_API.disassociate_floating_ip(context, vm_instance, address) - NETWORK_API.release_floating_ip(context, address) - except exception.FloatingIpNotAssociated: - raise AttributeError('Unable to disassociate an unassociated ' - 'floating up!') diff --git a/occi_os_api/nova_glue/security.py b/occi_os_api/nova_glue/security.py deleted file mode 100644 index 31780c1..0000000 --- a/occi_os_api/nova_glue/security.py +++ /dev/null @@ -1,134 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Security related 'glue' -""" - -# L8R: Check exception handling of this routines! - -from nova import compute -from nova import db -from nova.flags import FLAGS -from nova.openstack.common import importutils - -from occi import exceptions - -# connect to nova -COMPUTE_API = compute.API() - -SEC_HANDLER = importutils.import_object(FLAGS.security_group_handler) - - -def create_group(name, description, context): - """ - Create a OS security group. - - name -- Name of the group. - description -- Description. - context -- The os context. - """ - if db.security_group_exists(context, context.project_id, name): - raise AttributeError('Security group already exists: ' + name) - - group = {'user_id': context.user_id, - 'project_id': context.project_id, - 'name': name, - 'description': description} - db.security_group_create(context, group) - SEC_HANDLER.trigger_security_group_create_refresh(context, group) - - -def remove_group(group_id, context): - """ - Remove a security group. - - group_id -- the group. - context -- The os context. - """ - try: - #if db.security_group_in_use(context, group_id): - # raise AttributeError('Security group is still in use') - - db.security_group_destroy(context, group_id) - SEC_HANDLER.trigger_security_group_destroy_refresh( - context, group_id) - - except Exception as error: - raise AttributeError(error) - - -def retrieve_group(mixin_term, context): - """ - Retrieve the security group associated with the security mixin. - - mixin_term -- The term of the mixin representing the group. - context -- The os context. - """ - try: - sec_group = db.security_group_get_by_name(context, context.project_id, - mixin_term) - except Exception as err: - msg = err.message - raise AttributeError(msg) - - return sec_group - - -def create_rule(rule, context): - """ - Create a security rule. - - rule -- The rule. - context -- The os context. - """ - try: - db.security_group_rule_create(context, rule) - except Exception as err: - raise AttributeError('Unable to create rule: ' + str(err)) - - -def remove_rule(rule, context): - """ - Remove a security rule. - - rule -- The rule - context -- The os context. - """ - group_id = rule['parent_group_id'] - - try: - db.security_group_rule_destroy(context, rule['id']) - SEC_HANDLER.trigger_security_group_rule_destroy_refresh(context, - [rule['id']]) - except Exception as err: - raise AttributeError('Unable to remove rule: ' + str(err)) - - -def retrieve_rule(uid, context): - """ - Retrieve a rule. - - uid -- Id of the rule (entity.attributes['occi.core.id']) - context -- The os context. - """ - try: - return db.security_group_rule_get(context, - int(uid)) - except Exception: - raise exceptions.HTTPError(404, 'Rule not found!') diff --git a/occi_os_api/nova_glue/storage.py b/occi_os_api/nova_glue/storage.py deleted file mode 100644 index e49e447..0000000 --- a/occi_os_api/nova_glue/storage.py +++ /dev/null @@ -1,166 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Storage related glue :-) -""" - -import random - -from nova import exception -from nova import volume -from nova.image import glance - -from cinder import exception as cinder_ex - -from occi import exceptions - -# Connection to the nova APIs -from occi_os_api.nova_glue import vm - -VOLUME_API = volume.API() - -IMAGE_API = glance.get_default_image_service() - - -def create_storage(size, context, name=None, description=None): - """ - Create a storage instance. - - size -- Size of the storage. ('occi.storage.size') - context -- The os context. - name -- defaults to a random number if needed. - description -- defaults to the name - """ - # L8R: A blueprint? - # OpenStack deals with size in terms of integer. - # Need to convert float to integer for now and only if the float - # can be losslessly converted to integer - # e.g. See nova/quota.py:allowed_volumes(...) - if not float(size).is_integer: - raise AttributeError('Volume sizes cannot be specified as fractional' - ' floats.') - size = int(float(size)) - - disp_name = '' - if name is not None: - disp_name = name - else: - disp_name = str(random.randrange(0, 99999999)) + '-storage.occi-wg.org' - if description is not None: - disp_descr = description - else: - disp_descr = disp_name - - try: - return VOLUME_API.create(context, - size, - disp_name, - disp_descr) - except cinder_ex.VolumeSizeExceedsAvailableQuota: - raise AttributeError('The volume size quota has been reached!') - except cinder_ex.VolumeLimitExceeded: - raise AttributeError('The # of volumes quota has been reached!') - - -def delete_storage_instance(uid, context): - """ - Delete a storage instance. - - uid -- Id of the volume. - context -- The os context. - """ - try: - instance = get_storage(uid, context) - VOLUME_API.delete(context, instance) - except cinder_ex.InvalidVolume: - raise AttributeError('Volume is in wrong state or still attached!') - - -def snapshot_storage_instance(uid, name, description, context): - """ - Snapshots an storage instance. - - uid -- Id of the volume. - context -- The os context. - """ - try: - instance = get_storage(uid, context) - VOLUME_API.create_snapshot(context, instance, name, description) - except cinder_ex.InvalidVolume: - raise AttributeError('Volume is in wrong state!') - - -def get_image(uid, context): - """ - Return details on an image. - """ - try: - return IMAGE_API.show(context, uid) - except exception.ImageNotFound as err: - raise AttributeError(str(err)) - - -def get_image_architecture(uid, context): - """ - Extract architecture from either: - - image name, title or metadata. The architecture is sometimes - encoded in the image's name - - db::glance::image_properties could be used reliably so long as the - information is supplied when registering an image with glance. - - else return a default of x86 - - uid -- id of the instance! - context -- The os context. - """ - instance = vm.get_vm(uid, context) - - arch = '' - uid = instance['image_ref'] - img = IMAGE_API.show(context, uid) - img_properties = img['properties'] - if 'arch' in img_properties: - arch = img['properties']['arch'] - elif 'architecture' in img_properties: - arch = img['properties']['architecture'] - - if arch == '': - # if all attempts fail set it to a default value - arch = 'x86' - return arch - - -def get_storage(uid, context): - """ - Retrieve an Volume instance from nova. - - uid -- id of the instance - context -- the os context - """ - try: - instance = VOLUME_API.get(context, uid) - except exception.NotFound: - raise exceptions.HTTPError(404, 'Volume not found!') - return instance - - -def get_storage_volumes(context): - """ - Retrieve all storage entities from user. - """ - return VOLUME_API.get_all(context) diff --git a/occi_os_api/nova_glue/vm.py b/occi_os_api/nova_glue/vm.py deleted file mode 100644 index 1accdda..0000000 --- a/occi_os_api/nova_glue/vm.py +++ /dev/null @@ -1,448 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -VM related 'glue' :-) -""" - -#pylint: disable=R0914,W0142,R0912,R0915 - - -from nova import compute, volume -from nova import exception -from nova import utils -from nova.compute import vm_states -from nova.compute import task_states -from nova.compute import instance_types -from nova.exception import InstancePasswordSetFailed -from nova.flags import FLAGS - -from occi import exceptions -from occi.extensions import infrastructure - -from occi_os_api.extensions import os_mixins -from occi_os_api.extensions import os_addon -from occi_os_api.nova_glue import security - -import logging - -# Connection to the nova APIs - -COMPUTE_API = compute.API() -VOLUME_API = volume.API() - -LOG = logging.getLogger(__name__) - -# NOTE(aloga): we need to import the option -FLAGS.import_opt('vnc_enabled', 'nova.vnc') - - -def create_vm(entity, context): - """ - Create a VM for an given OCCI entity. - - entity -- the OCCI resource entity. - context -- the os context. - """ - if 'occi.compute.hostname' in entity.attributes: - name = entity.attributes['occi.compute.hostname'] - else: - name = None - key_name = key_data = None - password = utils.generate_password(FLAGS.password_length) - access_ip_v4 = None - access_ip_v6 = None - user_data = None - metadata = {} - injected_files = [] - min_count = max_count = 1 - requested_networks = None - sg_names = [] - availability_zone = None - config_drive = None - block_device_mapping = None - kernel_id = ramdisk_id = None - auto_disk_config = None - scheduler_hints = None - - resource_template = None - os_template = None - for mixin in entity.mixins: - if isinstance(mixin, os_mixins.ResourceTemplate): - resource_template = mixin - elif isinstance(mixin, os_mixins.OsTemplate): - os_template = mixin - elif mixin == os_addon.OS_KEY_PAIR_EXT: - attr = 'org.openstack.credentials.publickey.name' - key_name = entity.attributes[attr] - attr = 'org.openstack.credentials.publickey.data' - key_data = entity.attributes[attr] - # Look for security group. If the group is non-existant, the - # call to create will fail. - if os_addon.SEC_GROUP in mixin.related: - secgroup = security.retrieve_group(mixin.term, context) - sg_names.append(secgroup["name"]) - - if not os_template: - raise AttributeError('Please provide a valid OS Template.') - - if resource_template: - inst_type = compute.instance_types.\ - get_instance_type_by_flavor_id(resource_template.res_id) - else: - inst_type = compute.instance_types.get_default_instance_type() - msg = ('No resource template was found in the request. ' - 'Using the default: %s') % inst_type['name'] - LOG.warn(msg) - # make the call - try: - (instances, _reservation_id) = COMPUTE_API.create( - context=context, - instance_type=inst_type, - image_href=os_template.os_id, - kernel_id=kernel_id, - ramdisk_id=ramdisk_id, - min_count=min_count, - max_count=max_count, - display_name=name, - display_description=name, - key_name=key_name, - key_data=key_data, - security_group=sg_names, - availability_zone=availability_zone, - user_data=user_data, - metadata=metadata, - injected_files=injected_files, - admin_password=password, - block_device_mapping=block_device_mapping, - access_ip_v4=access_ip_v4, - access_ip_v6=access_ip_v6, - requested_networks=requested_networks, - config_drive=config_drive, - auto_disk_config=auto_disk_config, - scheduler_hints=scheduler_hints) - except Exception as error: - raise AttributeError(str(error)) - - # return first instance - return instances[0] - - -def rebuild_vm(uid, image_href, context): - """ - Rebuilds the specified VM with the supplied OsTemplate mixin. - - uid -- id of the instance - image_href -- image reference. - context -- the os context - """ - instance = get_vm(uid, context) - - admin_password = utils.generate_password(FLAGS.password_length) - kwargs = {} - try: - COMPUTE_API.rebuild(context, instance, image_href, admin_password, - **kwargs) - except exception.InstanceInvalidState: - raise AttributeError('VM is in an invalid state.') - except exception.ImageNotFound: - raise AttributeError('Cannot find image for rebuild') - - -def resize_vm(uid, flavor_id, context): - """ - Resizes a VM up or down - - Update: libvirt now supports resize see: - http://wiki.openstack.org/HypervisorSupportMatrix - - uid -- id of the instance - flavor_id -- image reference. - context -- the os context - """ - instance = get_vm(uid, context) - kwargs = {} - try: - flavor = instance_types.get_instance_type_by_flavor_id(flavor_id) - COMPUTE_API.resize(context, instance, flavor_id=flavor['flavorid'], - **kwargs) - ready = False - i = 0 - while not ready or i < 15: - i += 1 - state = get_vm(uid, context)['vm_state'] - if state == 'resized': - ready = True - import time - time.sleep(1) - instance = get_vm(uid, context) - COMPUTE_API.confirm_resize(context, instance) - except exception.FlavorNotFound: - raise AttributeError('Unable to locate requested flavor.') - except exception.InstanceInvalidState as error: - raise AttributeError('VM is in an invalid state: ' + str(error)) - - -def delete_vm(uid, context): - """ - Destroy a VM. - - uid -- id of the instance - context -- the os context - """ - instance = get_vm(uid, context) - - if FLAGS.reclaim_instance_interval: - COMPUTE_API.soft_delete(context, instance) - else: - COMPUTE_API.delete(context, instance) - - -def suspend_vm(uid, context): - """ - Suspends a VM. Use the start action to unsuspend a VM. - - uid -- id of the instance - context -- the os context - """ - instance = get_vm(uid, context) - - try: - COMPUTE_API.pause(context, instance) - except Exception as error: - raise exceptions.HTTPError(500, str(error)) - - -def snapshot_vm(uid, image_name, context): - """ - Snapshots a VM. Use the start action to unsuspend a VM. - - uid -- id of the instance - image_name -- name of the new image - context -- the os context - """ - instance = get_vm(uid, context) - try: - COMPUTE_API.snapshot(context, - instance, - image_name) - - except exception.InstanceInvalidState: - raise AttributeError('VM is not in an valid state.') - - -def start_vm(uid, context): - """ - Starts a vm that is in the stopped state. Note, currently we do not - use the nova start and stop, rather the resume/suspend methods. The - start action also unpauses a paused VM. - - uid -- id of the instance - state -- the state the VM is in (str) - context -- the os context - """ - instance = get_vm(uid, context) - try: - COMPUTE_API.resume(context, instance) - except Exception as error: - raise exceptions.HTTPError(500, 'Error while starting VM: ' + - str(error)) - - -def stop_vm(uid, context): - """ - Stops a VM. Rather than use stop, suspend is used. - OCCI -> graceful, acpioff, poweroff - OS -> unclear - - uid -- id of the instance - context -- the os context - """ - instance = get_vm(uid, context) - - try: - # There are issues with the stop and start methods of OS. For now - # we'll use suspend. - # self.compute_api.stop(context, instance) - COMPUTE_API.suspend(context, instance) - except Exception as error: - raise exceptions.HTTPError(500, 'Error while stopping VM: ' + - str(error)) - - -def restart_vm(uid, method, context): - """ - Restarts a VM. - OS types == SOFT, HARD - OCCI -> graceful, warm and cold - mapping: - - SOFT -> graceful, warm - - HARD -> cold - - uid -- id of the instance - method -- how the machine should be restarted. - context -- the os context - """ - instance = get_vm(uid, context) - - if method in ('graceful', 'warm'): - reboot_type = 'SOFT' - elif method is 'cold': - reboot_type = 'HARD' - else: - raise AttributeError('Unknown method.') - try: - COMPUTE_API.reboot(context, instance, reboot_type) - except exception.InstanceInvalidState: - raise exceptions.HTTPError(406, 'VM is in an invalid state.') - - -def attach_volume(instance_id, volume_id, mount_point, context): - """ - Attaches a storage volume. - - instance_id -- Id of the VM. - volume_id -- Id of the storage volume. - mount_point -- Where to mount. - context -- The os security context. - """ - instance = get_vm(instance_id, context) - try: - vol_instance = VOLUME_API.get(context, volume_id) - volume_id = vol_instance['id'] - COMPUTE_API.attach_volume( - context, - instance, - volume_id, - mount_point) - except exception.NotFound: - raise exceptions.HTTPError(404, 'Volume not found!') - except exception.InvalidDevicePath: - raise AttributeError('Invalid device path!') - - -def detach_volume(volume_id, context): - """ - Detach a storage volume. - - volume_id -- Id of the volume. - context -- the os context. - """ - try: - COMPUTE_API.detach_volume(context, volume_id) - except exception.InvalidVolume: - raise AttributeError('Invalid volume!') - except exception.VolumeUnattached: - raise AttributeError('Volume is not attached!') - - -def set_password_for_vm(uid, password, context): - """ - Set new password for an VM. - - uid -- Id of the instance. - password -- The new password. - context -- The os context. - """ - instance = get_vm(uid, context) - try: - COMPUTE_API.set_admin_password(context, instance, password) - except InstancePasswordSetFailed as error: - LOG.warn('Unable to set password - driver might not support it! ' + - str(error)) - - -def get_vnc(uid, context): - """ - Retrieve VNC console or None is unavailable. - - uid -- id of the instance - context -- the os context - """ - console = None - if FLAGS.vnc_enabled: - instance = get_vm(uid, context) - try: - console = COMPUTE_API.get_vnc_console(context, instance, 'novnc') - except exception.InstanceNotFound: - LOG.warn('Console info is not available atm!') - return console - - -def get_vm(uid, context): - """ - Retrieve an VM instance from nova. - - uid -- id of the instance - context -- the os context - """ - try: - instance = COMPUTE_API.get(context, uid) - except exception.NotFound: - raise exceptions.HTTPError(404, 'VM not found!') - return instance - - -def get_vms(context): - """ - Retrieve all VMs in a given context. - """ - opts = {'deleted': False} - tmp = COMPUTE_API.get_all(context, search_opts=opts) - return tmp - - -def get_occi_state(uid, context): - """ - See nova/compute/vm_states.py nova/compute/task_states.py - - Mapping assumptions: - - active == VM can service requests from network. These requests - can be from users or VMs - - inactive == the oppose! :-) - - suspended == machine in a frozen state e.g. via suspend or pause - - uid -- Id of the VM. - context -- the os context. - """ - instance = get_vm(uid, context) - state = 'inactive' - actions = [] - - if instance['vm_state'] in [vm_states.ACTIVE]: - state = 'active' - actions.append(infrastructure.STOP) - actions.append(infrastructure.SUSPEND) - actions.append(infrastructure.RESTART) - elif instance['vm_state'] in [vm_states.BUILDING]: - state = 'inactive' - elif instance['vm_state'] in [vm_states.PAUSED, vm_states.SUSPENDED, - vm_states.STOPPED]: - state = 'inactive' - actions.append(infrastructure.START) - elif instance['vm_state'] in [vm_states.RESCUED, - vm_states.ERROR, - vm_states.DELETED]: - state = 'inactive' - - # Some task states require a state - if instance['vm_state'] in [task_states.IMAGE_SNAPSHOT]: - state = 'inactive' - actions = [] - - return state, actions diff --git a/occi_os_api/registry.py b/occi_os_api/registry.py deleted file mode 100644 index 687f93f..0000000 --- a/occi_os_api/registry.py +++ /dev/null @@ -1,422 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -OCCI registry -""" - -#R0201:method could be func.E1002:old style obj,R0914-R0912:# of branches -#E1121:# positional args. -#pylint: disable=R0201,E1002,R0914,R0912,E1121 - -import uuid - -from occi import registry as occi_registry -from occi import core_model -from occi.extensions import infrastructure - -from occi_os_api.backends import openstack -from occi_os_api.extensions import os_addon - -from occi_os_api.nova_glue import vm -from occi_os_api.nova_glue import storage -from occi_os_api.nova_glue import net - -from nova.flags import FLAGS - - -class OCCIRegistry(occi_registry.NonePersistentRegistry): - """ - Registry for OpenStack. - - Idea is the following: Create the OCCI entities (Resource and their - links) here and let the backends handle actions, attributes etc. - """ - - def __init__(self): - super(OCCIRegistry, self).__init__() - self.cache = {} - self.adm_net = core_model.Resource('/network/admin', - infrastructure.NETWORK, - [infrastructure.IPNETWORK]) - self.pub_net = core_model.Resource('/network/public', - infrastructure.NETWORK, - [infrastructure.IPNETWORK]) - - self._setup_network() - - def set_hostname(self, hostname): - if FLAGS.occi_custom_location_hostname: - hostname = FLAGS.occi_custom_location_hostname - super(OCCIRegistry, self).set_hostname(hostname) - - def get_extras(self, extras): - """ - Get data which is encapsulated in the extras. - """ - sec_extras = None - if extras is not None: - sec_extras = {'user_id': extras['nova_ctx'].user_id, - 'project_id': extras['nova_ctx'].project_id} - return sec_extras - - # The following two are here to deal with the security group mixins - - def delete_mixin(self, mixin, extras): - """ - Allows for the deletion of user defined mixins. - If the mixin is a security group mixin then that mixin's - backend is called. - """ - if (hasattr(mixin, 'related') and - os_addon.SEC_GROUP in mixin.related): - backend = self.get_backend(mixin, extras) - backend.destroy(mixin, extras) - - super(OCCIRegistry, self).delete_mixin(mixin, extras) - - def set_backend(self, category, backend, extras): - """ - Assigns user id and tenant id to user defined mixins - """ - if (hasattr(category, 'related') and - os_addon.SEC_GROUP in category.related): - backend = openstack.SecurityGroupBackend() - backend.init_sec_group(category, extras) - - super(OCCIRegistry, self).set_backend(category, backend, extras) - - # The following two deal with the creation and deletion os links. - - def add_resource(self, key, resource, extras): - """ - Just here to prevent the super class from filling up an unused dict. - """ - if (key, extras['nova_ctx'].user_id) not in self.cache and \ - core_model.Link.kind in resource.kind.related: - # don't need to cache twice, only adding links :-) - self.cache[(key, extras['nova_ctx'].user_id)] = resource - elif (key, extras['nova_ctx'].user_id) not in self.cache and \ - resource.kind == os_addon.SEC_RULE: - # don't need to cache twice, only adding links :-) - self.cache[(key, extras['nova_ctx'].user_id)] = resource - - def delete_resource(self, key, extras): - """ - Just here to prevent the super class from messing up. - """ - if (key, extras['nova_ctx'].user_id) in self.cache: - self.cache.pop((key, extras['nova_ctx'].user_id)) - - # the following routines actually retrieve the info form OpenStack. Note - # that a cache is used. The cache is stable - so delete resources - # eventually also get deleted form the cache. - - def get_resource(self, key, extras): - """ - Retrieve a single resource. - """ - context = extras['nova_ctx'] - iden = key[key.rfind('/') + 1:] - - vms = vm.get_vms(context) - vm_res_ids = [item['uuid'] for item in vms] - stors = storage.get_storage_volumes(context) - stor_res_ids = [item['id'] for item in stors] - - if (key, context.user_id) in self.cache: - # I have seen it - need to update or delete if gone in OS! - # I have already seen it - cached_item = self.cache[(key, context.user_id)] - if not iden in vm_res_ids and cached_item.kind == \ - infrastructure.COMPUTE: - # it was delete in OS -> remove links, cache + KeyError! - # can delete it because it was my item! - for link in cached_item.links: - self.cache.pop((link.identifier, repr(extras))) - self.cache.pop((key, repr(extras))) - raise KeyError - if not iden in stor_res_ids and cached_item.kind == \ - infrastructure.STORAGE: - # it was delete in OS -> remove from cache + KeyError! - # can delete it because it was my item! - self.cache.pop((key, repr(extras))) - raise KeyError - elif iden in vm_res_ids: - # it also exists in OS -> update it (take links, mixins - # from cached one) - result = self._update_occi_compute(cached_item, extras) - elif iden in stor_res_ids: - # it also exists in OS -> update it! - result = self._update_occi_storage(cached_item, extras) - else: - # return cached item (links) - return cached_item - elif (key, None) in self.cache: - # return shared entities from cache! - return self.cache[(key, None)] - else: - # construct it. - if iden in vm_res_ids: - # create new & add to cache! - result = self._construct_occi_compute(iden, extras)[0] - elif iden in stor_res_ids: - result = self._construct_occi_storage(iden, extras)[0] - else: - # doesn't exist! - raise KeyError - - if result.identifier != key: - raise AttributeError('Key/identifier mismatch! Requested: ' + - key + ' Got: ' + result.identifier) - return result - - def get_resource_keys(self, extras): - """ - Retrieve the keys of all resources. - """ - keys = [] - for item in self.cache.values(): - if item.extras is not None and item.extras != extras: - # filter out items not belonging to this user! - continue - else: - # add identifier - keys.append(item.identifier) - - return keys - - def get_resources(self, extras): - """ - Retrieve a set of resources. - """ - - # TODO: add security rules! - - context = extras['nova_ctx'] - result = [] - - vms = vm.get_vms(context) - vm_res_ids = [item['uuid'] for item in vms] - - stors = storage.get_storage_volumes(context) - stor_res_ids = [item['id'] for item in stors] - - for item in self.cache.values(): - if item.extras is not None and item.extras['user_id'] != \ - context.user_id: - # filter out items not belonging to this user! - continue - item_id = item.identifier[item.identifier.rfind('/') + 1:] - if item.extras is None: - # add to result set - result.append(item) - elif item_id in vm_res_ids and item.kind == \ - infrastructure.COMPUTE: - # check & update (take links, mixins from cache) - # add compute and it's links to result - self._update_occi_compute(item, extras) - result.append(item) - result.extend(item.links) - elif item_id in stor_res_ids and item.kind == \ - infrastructure.STORAGE: - # check & update (take links, mixins from cache) - # add compute and it's links to result - self._update_occi_storage(item, extras) - result.append(item) - elif item_id not in vm_res_ids and item.kind == \ - infrastructure.COMPUTE: - # remove item and it's links from cache! - for link in item.links: - self.cache.pop((link.identifier, item.extras['user_id'])) - self.cache.pop((item.identifier, item.extras['user_id'])) - elif item_id not in stor_res_ids and item.kind == \ - infrastructure.STORAGE: - # remove item - self.cache.pop((item.identifier, item.extras['user_id'])) - for item in vms: - if (infrastructure.COMPUTE.location + item['uuid'], - context.user_id) in self.cache: - continue - else: - # construct (with links and mixins and add to cache! - # add compute and it's linke to result - ent_list = self._construct_occi_compute(item['uuid'], extras) - result.extend(ent_list) - for item in stors: - if (infrastructure.STORAGE.location + item['id'], - context.user_id) in self.cache: - continue - else: - # construct (with links and mixins and add to cache! - # add compute and it's linke to result - ent_list = self._construct_occi_storage(item['id'], extras) - result.extend(ent_list) - - return result - - # Not part of parent - - def _update_occi_compute(self, entity, extras): - """ - Update an occi compute resource instance. - """ - # TODO: implement update of mixins and links (remove old mixins and - # links)! - return entity - - def _construct_occi_compute(self, identifier, extras): - """ - Construct a OCCI compute instance. - - First item in result list is entity self! - - Adds it to the cache too! - """ - result = [] - context = extras['nova_ctx'] - - instance = vm.get_vm(identifier, context) - - # 1. get identifier - iden = infrastructure.COMPUTE.location + identifier - entity = core_model.Resource(iden, infrastructure.COMPUTE, - [os_addon.OS_VM]) - result.append(entity) - - # 2. os and res templates - flavor_id = instance['instance_type'].flavorid - res_tmp = self.get_category('/' + flavor_id + '/', extras) - if res_tmp: - entity.mixins.append(res_tmp) - - os_id = instance['image_ref'] - image_id = storage.get_image(os_id, context)['id'] - image_tmp = self.get_category('/' + image_id + '/', extras) - if image_tmp: - entity.mixins.append(image_tmp) - - # 3. network links & get links from cache! - net_links = net.get_network_details(identifier, context) - for item in net_links['public']: - link = self._construct_network_link(item, entity, self.pub_net, - extras) - result.append(link) - for item in net_links['admin']: - link = self._construct_network_link(item, entity, self.adm_net, - extras) - result.append(link) - - # core.id and cache it! - entity.attributes['occi.core.id'] = identifier - entity.extras = self.get_extras(extras) - self.cache[(entity.identifier, context.user_id)] = entity - - return result - - def _update_occi_storage(self, entity, extras): - """ - Update a storage resource instance. - """ - return entity - - def _construct_occi_storage(self, identifier, extras): - """ - Construct a OCCI storage instance. - - First item in result list is entity self! - - Adds it to the cache too! - """ - result = [] - context = extras['nova_ctx'] - stor = storage.get_storage(identifier, context) - - # id, display_name, size, status - iden = infrastructure.STORAGE.location + identifier - entity = core_model.Resource(iden, infrastructure.STORAGE, []) - result.append(entity) - - # create links on VM resources - if stor['status'] == 'in-use': - source = self.get_resource(infrastructure.COMPUTE.location + - str(stor['instance_uuid']), extras) - link = core_model.Link(infrastructure.STORAGELINK.location + - str(uuid.uuid4()), - infrastructure.STORAGELINK, [], source, - entity) - link.extras = self.get_extras(extras) - source.links.append(link) - result.append(link) - self.cache[(link.identifier, context.user_id)] = link - - # core.id and cache it! - entity.attributes['occi.core.id'] = identifier - entity.extras = self.get_extras(extras) - self.cache[(entity.identifier, context.user_id)] = entity - - return result - - def _setup_network(self): - """ - Add a public and an admin network interface. - """ - # TODO: read from openstack! - self.pub_net.attributes = {'occi.network.vlan': 'external', - 'occi.network.label': 'default', - 'occi.network.state': 'active', - 'occi.networkinterface.address': '192' - '.168' - '.0.0/24', - 'occi.networkinterface.gateway': '192.168' - '.0.1', - 'occi.networkinterface.allocation': - 'static'} - self.adm_net.attributes = {'occi.network.vlan': 'admin', - 'occi.network.label': 'default', - 'occi.network.state': 'active', - 'occi.networkinterface.address': '10.0.0' - '.0/24', - 'occi.networkinterface.gateway': '10.0.0' - '.1', - 'occi.networkinterface.allocation': - 'static'} - self.cache[(self.adm_net.identifier, None)] = self.adm_net - self.cache[(self.pub_net.identifier, None)] = self.pub_net - - def _construct_network_link(self, net_desc, source, target, extras): - """ - Construct a network link and add to cache! - """ - link = core_model.Link(infrastructure.NETWORKINTERFACE.location + - str(uuid.uuid4()), - infrastructure.NETWORKINTERFACE, - [infrastructure.IPNETWORKINTERFACE], source, - target) - link.attributes = { - 'occi.networkinterface.interface': net_desc['interface'], - 'occi.networkinterface.mac': net_desc['mac'], - 'occi.networkinterface.state': net_desc['state'], - 'occi.networkinterface.address': net_desc['address'], - 'occi.networkinterface.gateway': net_desc['gateway'], - 'occi.networkinterface.allocation': net_desc['allocation'] - } - link.extras = self.get_extras(extras) - source.links.append(link) - self.cache[(link.identifier, extras['nova_ctx'].user_id)] = link - return link diff --git a/occi_os_api/wsgi.py b/occi_os_api/wsgi.py deleted file mode 100644 index 1e06e9b..0000000 --- a/occi_os_api/wsgi.py +++ /dev/null @@ -1,261 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -OCCI WSGI app :-) -""" - -# W0613:unused args,R0903:too few pub methods -# pylint: disable=W0613,R0903 - -import logging - -from nova import flags -from nova import wsgi -from nova import db -from nova.image import glance -from nova.compute import instance_types -from nova.openstack.common import cfg - -from occi_os_api import registry -from occi_os_api.backends import compute -from occi_os_api.backends import openstack -from occi_os_api.backends import network -from occi_os_api.backends import storage -from occi_os_api.extensions import os_mixins -from occi_os_api.extensions import os_addon - -from occi import backend -from occi import core_model -from occi import wsgi as occi_wsgi -from occi.extensions import infrastructure - -from urllib import quote - -LOG = logging.getLogger(__name__) - -#Setup options -OCCI_OPTS = [ - cfg.IntOpt("occiapi_listen_port", - default=8787, - help="Port OCCI interface will listen on."), - cfg.StrOpt("occi_custom_location_hostname", - default=None, - help="Override OCCI location hostname with custom value") -] - -FLAGS = flags.FLAGS -FLAGS.register_opts(OCCI_OPTS) - -MIXIN_BACKEND = backend.MixinBackend() - - -class OCCIApplication(occi_wsgi.Application, wsgi.Application): - """ - Adapter which 'translates' represents a nova WSGI application into and OCCI - WSGI application. - """ - - def __init__(self): - """ - Initialize the WSGI OCCI application. - """ - super(OCCIApplication, self).__init__(registry=registry.OCCIRegistry()) - self._register_backends() - - def _register_backends(self): - """ - Registers the OCCI infrastructure resources to ensure compliance - with GFD184 - """ - compute_backend = compute.ComputeBackend() - network_backend = network.NetworkBackend() - networkinterface_backend = network.NetworkInterfaceBackend() - ipnetwork_backend = network.IpNetworkBackend() - ipnetworking_backend = network.IpNetworkInterfaceBackend() - - storage_backend = storage.StorageBackend() - storage_link_backend = storage.StorageLinkBackend() - - # register kinds with backends - self.register_backend(infrastructure.COMPUTE, compute_backend) - self.register_backend(infrastructure.START, compute_backend) - self.register_backend(infrastructure.STOP, compute_backend) - self.register_backend(infrastructure.RESTART, compute_backend) - self.register_backend(infrastructure.SUSPEND, compute_backend) - self.register_backend(infrastructure.OS_TEMPLATE, MIXIN_BACKEND) - self.register_backend(infrastructure.RESOURCE_TEMPLATE, MIXIN_BACKEND) - - self.register_backend(infrastructure.NETWORK, network_backend) - self.register_backend(infrastructure.UP, network_backend) - self.register_backend(infrastructure.DOWN, network_backend) - self.register_backend(infrastructure.NETWORKINTERFACE, - networkinterface_backend) - self.register_backend(infrastructure.IPNETWORK, ipnetwork_backend) - self.register_backend(infrastructure.IPNETWORKINTERFACE, - ipnetworking_backend) - - self.register_backend(infrastructure.STORAGE, storage_backend) - self.register_backend(infrastructure.ONLINE, storage_backend) - self.register_backend(infrastructure.OFFLINE, storage_backend) - self.register_backend(infrastructure.BACKUP, storage_backend) - self.register_backend(infrastructure.SNAPSHOT, storage_backend) - self.register_backend(infrastructure.RESIZE, storage_backend) - self.register_backend(infrastructure.STORAGELINK, storage_link_backend) - - # add extensions for occi. - self.register_backend(os_addon.SEC_GROUP, - openstack.SecurityGroupBackend()) - self.register_backend(os_addon.SEC_RULE, - openstack.SecurityRuleBackend()) - self.register_backend(os_addon.OS_VM, - openstack.OsComputeBackend()) - self.register_backend(os_addon.OS_CREATE_IMAGE, - openstack.OsComputeBackend()) - self.register_backend(os_addon.OS_KEY_PAIR_EXT, - openstack.OsComputeBackend()) - self.register_backend(os_addon.OS_CHG_PWD, - openstack.OsComputeBackend()) - self.register_backend(os_addon.OS_NET_LINK, - openstack.OsNetLinkBackend()) - - def __call__(self, environ, response): - """ - This will be called as defined by WSGI. - Deals with incoming requests and outgoing responses - - Takes the incoming request, sends it on to the OCCI WSGI application, - which finds the appropriate backend for it and then executes the - request. The backend then is responsible for the return content. - - environ -- The environ. - response -- The response. - """ - extras = {'nova_ctx': environ['nova.context']} - - # register/refresh openstack images - self._refresh_os_mixins(extras) - # register/refresh openstack instance types (flavours) - self._refresh_resource_mixins(extras) - # register/refresh the openstack security groups as Mixins - self._refresh_security_mixins(extras) - - return self._call_occi(environ, response, nova_ctx=extras['nova_ctx'], - registry=self.registry) - - def _refresh_os_mixins(self, extras): - """ - Register images as OsTemplate mixins from - information retrieved from glance (shared and user-specific). - """ - template_schema = 'http://schemas.openstack.org/template/os#' - image_service = glance.get_default_image_service() - - images = image_service.detail(extras['nova_ctx']) - - for img in images: - # If the image is a kernel or ram one - # and we're not to filter them out then register it. - if (((img['container_format'] or img['disk_format']) in ('ari', - 'aki'))): - msg = 'Not registering kernel/RAM image.' - LOG.debug(msg) - continue - ctg_term = occify_terms(img['name']) - os_template = os_mixins.OsTemplate(term=ctg_term, - scheme=template_schema, - os_id=img['id'], - related=[infrastructure. - OS_TEMPLATE], - attributes=None, - title='This is an OS ' + - img['name'] + ' VM image', - location='/' + ctg_term + '/') - - try: - self.registry.get_backend(os_template, extras) - except AttributeError: - msg = 'Registering an OS image type as: %s' % str(os_template) - LOG.debug(msg) - self.register_backend(os_template, MIXIN_BACKEND) - - def _refresh_resource_mixins(self, extras): - """ - Register the flavors as ResourceTemplates to which the user has access. - """ - template_schema = 'http://schemas.openstack.org/template/resource#' - os_flavours = instance_types.get_all_types() - - for itype in os_flavours.values(): - ctg_term = occify_terms(itype['name']) - resource_template = os_mixins.ResourceTemplate( - term=quote(ctg_term), - flavor_id=itype['flavorid'], - scheme=template_schema, - related=[infrastructure.RESOURCE_TEMPLATE], - title='This is an openstack ' + itype['name'] + ' flavor.', - location='/' + quote(ctg_term) + '/') - - try: - self.registry.get_backend(resource_template, extras) - except AttributeError: - msg = 'Registering an OpenStack flavour/instance type: %s' % \ - str(resource_template) - LOG.debug(msg) - self.register_backend(resource_template, MIXIN_BACKEND) - - def _refresh_security_mixins(self, extras): - """ - Registers security groups as security mixins - """ - # ensures that preexisting openstack security groups are - # added and only once. - # collect these and add them to an exclusion list so they're - # not created again when listing non-user-defined sec. groups - excld_grps = [] - for cat in self.registry.get_categories(extras): - if (isinstance(cat, core_model.Mixin) and - os_addon.SEC_GROUP in cat.related): - excld_grps.append(cat.term) - - groups = db.security_group_get_by_project(extras['nova_ctx'], - extras['nova_' - 'ctx'].project_id) - sec_grp = 'http://schemas.openstack.org/infrastructure/security/group#' - - for group in groups: - if group['name'] not in excld_grps: - sec_mix = os_mixins.UserSecurityGroupMixin( - term=str(group["id"]), - scheme=sec_grp, - related=[os_addon.SEC_GROUP], - attributes=None, - title=group['name'], - location='/security/' + quote(str(group['name'])) + '/') - try: - self.registry.get_backend(sec_mix, extras) - except AttributeError: - self.register_backend(sec_mix, MIXIN_BACKEND) - - -def occify_terms(term_name): - ''' - Occifies a term_name so that it is compliant with GFD 185. - ''' - term = term_name.strip().replace(' ', '_').replace('.', '-').lower() - return term diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 84c5c54..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -rm -rf build/html -mkdir -p build/html - -echo '\n PyLint report \n****************************************\n' - -pylint -d W0511,I0011,E1101,E0611,F0401 -i y --report no **/*.py - -echo '\n Unittest coverage \n****************************************\n' - -nc -z localhost 8787 -if [ "$?" -ne 0 ]; then - echo "Unable to connect to OCCI endpoint localhost 8787 - will not run - system test." - nosetests --with-coverage --cover-erase --cover-package=occi_os_api --exclude=system -else - echo "Please make sure that the following line is available in nova.conf:" - echo "allow_resize_to_same_host=True libvirt_inject_password=True enabled_apis=ec2,occiapi,osapi_compute,osapi_volume,metadata )" - - source ../devstack/openrc - nova-manage flavor create --name=itsy --cpu=1 --memory=32 --flavor=98 --root_gb=1 --ephemeral_gb=1 - nova-manage flavor create --name=bitsy --cpu=1 --memory=64 --flavor=99 --root_gb=1 --ephemeral_gb=1 - nosetests --with-coverage --cover-erase --cover-package=occi_os_api -fi - -echo '\n Code style \n****************************************\n' - -pep8 --repeat --statistics --count occi_os_api tests - -echo '\n Issues report \n****************************************\n' - -pyflakes occi_os_api -vulture occi_os_api - -echo '\n Pychecker report \n****************************************\n' - -pychecker -# 99 occi_os_api/*.py occi_os_api/backends/*.py -occi_os_api/nova_glue/*.py occi_os_api/extensions/*.py - -# TODO: create project! -#epydoc epydoc.prj - -# Fix: -#tmetsch@ubuntu:~/devstack$ cat /etc/tgt/targets.conf -#include /etc/tgt/conf.d/cinder.conf -# -# in devstack/files/horizon_settings: -#HORIZON_CONFIG = { -# #'dashboards': ('nova', 'syspanel', 'settings',), -# 'dashboards': ('project', 'admin', 'settings',), -# 'default_dashboard': 'project', -#} diff --git a/runme.py b/runme.py deleted file mode 100755 index 9a5d8e2..0000000 --- a/runme.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python - -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# 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. - -"""Starter script for Nova OCCI API.""" - -import eventlet -eventlet.monkey_patch(os=False) - -import os -import sys - - -TOPDIR = os.path.normpath(os.path.join(os.path.abspath( - sys.argv[0]), os.pardir, os.pardir)) -if os.path.exists(os.path.join(TOPDIR, "nova", "__init__.py")): - sys.path.insert(0, TOPDIR) - -from nova import flags -from nova import service -from nova import utils -from nova.openstack.common import log as logging - -if __name__ == '__main__': - flags.parse_args(sys.argv) - logging.setup("nova") - utils.monkey_patch() - SERVER = service.WSGIService('occiapi') - service.serve(SERVER) - service.wait() diff --git a/setup.py b/setup.py deleted file mode 100644 index 41cfc59..0000000 --- a/setup.py +++ /dev/null @@ -1,58 +0,0 @@ -# coding=utf-8 - -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Setupstools script which defines an entry point which can be used for OCCI -app later. -""" - -from setuptools import setup - - -setup( - name='openstackocci-grizzly', - version='1.0', - description='OCCI interface for Openstack (stable/grizzly).', - long_description=''' - This is a clone of https://github.com/dizz/nova - it provides a - python egg which can be deployed in OpenStack and will thereby add the - 3rd party OCCI interface to OpenStack. - ''', - classifiers=[ - 'Programming Language :: Python', - 'Development Status :: 5 - Production/Stable', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - ], - keywords='', - author='Intel Performance Learning Solutions Ltd.', - author_email='thijsx.metsch@intel.com', - url='http://intel.com', - license='Apache License, Version 2.0', - include_package_data=True, - packages=['occi_os_api','occi_os_api.backends','occi_os_api.extensions', - 'occi_os_api.nova_glue'], - zip_safe=False, - install_requires=[ - 'setuptools', - ], - entry_points=''' - [paste.app_factory] - occi_app = occi_os_api:main - ''', -) diff --git a/tests/system_test.py b/tests/system_test.py deleted file mode 100644 index 89200f7..0000000 --- a/tests/system_test.py +++ /dev/null @@ -1,438 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# 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. - -""" -Will test the OS occiosapi against a local running instance. -""" - -#pylint: disable=W0102,C0103,R0904 - -import json -import sys -import time -import httplib -import logging -import unittest -import random - - -HEADS = {'Content-Type': 'text/occi', - 'Accept': 'text/occi'} - -KEYSTONE_HOST = '127.0.0.1:5000' -OCCI_HOST = '127.0.0.1:8787' - -# Init a simple logger... -logging.basicConfig(level=logging.DEBUG) -CONSOLE = logging.StreamHandler() -CONSOLE.setLevel(logging.DEBUG) -LOG = logging.getLogger() -LOG.addHandler(CONSOLE) - - -def do_request(verb, url, headers): - """ - Do an HTTP request defined by a HTTP verb, an URN and a dict of headers. - """ - conn = httplib.HTTPConnection(OCCI_HOST) - conn.request(verb, url, None, headers) - response = conn.getresponse() - if response.status not in [200, 201]: - LOG.error(response.reason) - LOG.warn(response.read()) - sys.exit(1) - - heads = response.getheaders() - result = {} - for item in heads: - if item[0] in ['category', 'link', 'x-occi-attribute', - 'x-occi-location', 'location']: - tmp = [] - for val in item[1].split(','): - tmp.append(val.strip()) - result[item[0]] = tmp - - conn.close() - return result - - -def get_os_token(username, password): - """ - Get a security token from Keystone. - """ - body = '{"auth": {"tenantName": "' + username + '", ' \ - '"passwordCredentials":{"username": "' + username + '", ' \ - '"password": "' + password + '"}}}' - - heads = {'Content-Type': 'application/json'} - conn = httplib.HTTPConnection(KEYSTONE_HOST) - conn.request("POST", "/v2.0/tokens", body, heads) - response = conn.getresponse() - data = response.read() - tokens = json.loads(data) - token = tokens['access']['token']['id'] - return token - - -def get_qi_listing(token): - """ - Retrieve categories from QI. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - result = do_request('GET', '/-/', heads) - LOG.debug(result['category']) - - -def create_node(token, category_list, attributes=[]): - """ - Create a VM. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - - for cat in category_list: - if 'Category' in heads: - heads['Category'] += ', ' + cat - else: - heads['Category'] = cat - - for attr in attributes: - if 'X-OCCI-Attribute' in heads: - heads['X-OCCI-Attribute'] += ', ' + attr - else: - heads['X-OCCI-Attribute'] = attr - - heads = do_request('POST', '/compute/', heads) - loc = heads['location'][0] - loc = loc[len('http://' + OCCI_HOST):] - LOG.debug('Location is: ' + loc) - return loc - - -def list_nodes(token, url): - """ - List a bunch of resource. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - heads = do_request('GET', url, heads) - return heads['x-occi-location'] - - -def get_node(token, location): - """ - Retrieve a single resource. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - heads = do_request('GET', location, heads) - return heads - - -def destroy_node(token, location): - """ - Destroy a single node. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - heads = do_request('DELETE', location, heads) - return heads - - -def trigger_action(token, url, action_cat, action_param=None): - """ - Trigger an OCCI action. - """ - heads = HEADS.copy() - heads['X-Auth-Token'] = token - heads['Category'] = action_cat - if action_param is not None: - heads['X-OCCI-Attribute'] = action_param - - do_request('POST', url, heads) - - -class SystemTest(unittest.TestCase): - """ - Do a simple set of test. - """ - - def setUp(self): - """ - Setup the test. - """ - # Get a security token: - self.token = get_os_token('admin', 'os4all') - LOG.info('security token is: ' + self.token) - - def test_compute_node(self): - """ - Test ops on a compute node! - """ - # QI listing - get_qi_listing(self.token) - - # create VM - cats = ['m1-tiny; scheme="http://schemas.openstack' - '.org/template/resource#"', - 'cirros-0-3-0-x86_64-uec; scheme="http://schemas.openstack' - '.org/template/os#"', - 'compute; scheme="http://schemas.ogf' - '.org/occi/infrastructure#"'] - vm_location = create_node(self.token, cats) - # list computes - if 'http://' + OCCI_HOST + vm_location not \ - in list_nodes(self.token, '/compute/'): - LOG.error('VM should be listed!') - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # trigger stop - trigger_action(self.token, vm_location + '?action=stop', - 'stop; scheme="http://schemas.ogf.org/occi/' - 'infrastructure/compute/action#"') - - # wait - cont = False - while not cont: - if 'occi.compute.state="inactive"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # trigger start - trigger_action(self.token, vm_location + '?action=start', - 'start; scheme="http://schemas.ogf.org/occi/' - 'infrastructure/compute/action#"') - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # delete - destroy_node(self.token, vm_location) - - def test_security_grouping(self): - """ - Test some security and accessibility stuff! - """ - # create sec group - heads = HEADS.copy() - heads['X-Auth-Token'] = self.token - name = 'my_grp' + str(random.randint(1, 999999)) - heads['Category'] = name + '; scheme="http://www.mystuff.org/sec#"; ' \ - 'rel="http://schemas.ogf.org/occi/' \ - 'infrastructure/security#group"; ' \ - 'location="/mygroups/"' - do_request('POST', '/-/', heads) - - # create sec rule - cats = [name + '; scheme="http://www.mystuff.org/sec#";', - 'rule; scheme="http://schemas.openstack' - '.org/occi/infrastructure/network/security#";'] - attrs = ['occi.network.security.protocol="tcp"', - 'occi.network.security.to="22"', - 'occi.network.security.from="22"', - 'occi.network.security.range="0.0.0.0/0"'] - sec_rule_loc = create_node(self.token, cats, attrs) - - # list - LOG.error(list_nodes(self.token, '/mygroups/')) - LOG.debug(do_request('GET', sec_rule_loc, heads)) - - # FIXME: add VM to sec group - see #22 - #heads['X-OCCI-Location'] = vm_location - #print do_request('POST', '/mygroups/', heads) - - # create new VM - cats = ['m1-tiny; scheme="http://schemas.openstack' - '.org/template/resource#"', - 'cirros-0-3-0-x86_64-uec; scheme="http://schemas.openstack' - '.org/template/os#"', - name + '; scheme="http://www.mystuff.org/sec#"', - 'compute; scheme="http://schemas.ogf' - '.org/occi/infrastructure#"'] - vm_location = create_node(self.token, cats) - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # allocate floating IP - cats = ['networkinterface; scheme="http://schemas.ogf' - '.org/occi/infrastructure#"', 'ipnetworkinterface; ' - 'scheme="http://schemas.ogf' - '.org/occi/infrastructure/networkinterface#"'] - attrs = ['occi.core.source=http://"' + OCCI_HOST + vm_location + '"', - 'occi.core.target=http://"' + OCCI_HOST + - '/network/public"'] - float_ip_location = create_node(self.token, cats, attrs) - - time.sleep(15) - - # Deallocate Floating IP to VM - destroy_node(self.token, float_ip_location) - - # change pw - LOG.debug(trigger_action(self.token, vm_location + '?action=chg_pwd', - 'chg_pwd; scheme="http://schemas.' - 'openstack.org/instance/action#"', - 'org.openstack.credentials.admin_pwd' - '="new_pass"')) - - # clean VM - destroy_node(self.token, vm_location) - - # delete rule - destroy_node(self.token, sec_rule_loc) - - time.sleep(5) - - # FIXME: delete sec group - see #18 - heads = HEADS.copy() - heads['X-Auth-Token'] = self.token - heads['Category'] = name + '; scheme="http://www.mystuff.org/sec#"' - #do_request('DELETE', '/-/', heads) - - def test_storage_stuff(self): - """ - Test attaching and detaching storage volumes + snapshotting etc. - """ - - # create new VM - cats = ['m1-tiny; scheme="http://schemas.openstack' - '.org/template/resource#"', - 'cirros-0-3-0-x86_64-uec; scheme="http://schemas.openstack' - '.org/template/os#"', - 'compute; scheme="http://schemas.ogf.org/occi/' - 'infrastructure#"'] - vm_location = create_node(self.token, cats) - - # create volume - cats = ['storage; scheme="http://schemas.ogf' - '.org/occi/infrastructure#"'] - attrs = ['occi.storage.size = 1.0'] - vol_location = create_node(self.token, cats, attrs) - - time.sleep(25) - - # get individual node. - LOG.debug(get_node(self.token, vol_location)['x-occi-attribute']) - - # snapshot volume - # snapshot will work - but than deletion of volume is impossible :-/ - #trigger_action(self.token, vol_location + - # '?action=snapshot', - # 'snapshot; scheme="http://schemas.ogf' - # '.org/occi/infrastructure/storage/action#"') - - # link volume and compute - cats = ['storagelink; scheme="http://schemas.ogf' - '.org/occi/infrastructure#"'] - attrs = ['occi.core.source=http://"' + OCCI_HOST + vm_location + '"', - 'occi.core.target=http://"' + OCCI_HOST + vol_location + '"', - 'occi.storagelink.deviceid="/dev/vdc"'] - link_location = create_node(self.token, cats, attrs) - - # retrieve link - LOG.debug(get_node(self.token, link_location)['x-occi-attribute']) - - time.sleep(30) - - # deassociate storage vol - see #15 - destroy_node(self.token, link_location) - - time.sleep(15) - - destroy_node(self.token, vol_location) - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # Create a Image from an Active VM - LOG.debug(trigger_action(self.token, vm_location + '?action=' - 'create_image', - 'create_image; scheme="http://schemas.' - 'openstack.org/instance/action#"', - 'org.openstack.snapshot.image_name=' - '"awesome_ware"')) - - destroy_node(self.token, vm_location) - - def test_scaling(self): - """ - Test the scaling operations - """ - # create new VM - cats = ['itsy; scheme="http://schemas.openstack' - '.org/template/resource#"', - 'cirros-0-3-0-x86_64-uec; scheme="http://schemas.openstack' - '.org/template/os#"', - 'compute; scheme="http://schemas.ogf.org/occi/' - 'infrastructure#"'] - vm_location = create_node(self.token, cats) - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - # scale up VM - see #17 - heads = HEADS.copy() - heads['X-Auth-Token'] = self.token - heads['Category'] = 'bitsy; scheme="http://schemas.openstack' \ - '.org/template/resource#"' - do_request('POST', vm_location, heads) - - # wait - cont = False - while not cont: - if 'occi.compute.state="active"' in \ - get_node(self.token, vm_location)['x-occi-attribute']: - cont = True - else: - time.sleep(5) - - destroy_node(self.token, vm_location) diff --git a/tests/test_backends_compute.py b/tests/test_backends_compute.py deleted file mode 100644 index 773dcb9..0000000 --- a/tests/test_backends_compute.py +++ /dev/null @@ -1,331 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# 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. - -""" -Unittest for the Compute Backend. -""" - -#pylint: disable=W0102,C0103,R0904 - -import unittest - -# depenency from nova :-) -import mox -from nova.compute import vm_states - -from occi import core_model -from occi.extensions import infrastructure - -from occi_os_api import nova_glue -from occi_os_api.backends import compute -from occi_os_api.extensions import os_mixins - - -class TestComputeBackend(unittest.TestCase): - """ - Tests the compute backend. - """ - - os_template = os_mixins.OsTemplate('http://example.com', 'unix') - os_template2 = os_mixins.OsTemplate('http://example.com', 'windows') - - res_template = os_mixins.ResourceTemplate('http://example.com', 'itsy') - res_template2 = os_mixins.ResourceTemplate('http://example.com', 'bitsy') - - def setUp(self): - """ - Setup tests. - """ - self.backend = compute.ComputeBackend() - self.sec_obj = {'nova_ctx': None} - self.mox = mox.Mox() - - def tearDown(self): - """ - Cleanup mocks. - """ - self.mox.UnsetStubs() - - # Test for failure - - def test_create_for_failure(self): - """ - Test for proper error handling. - """ - # msg OS template - res = core_model.Resource('/foo/bar', infrastructure.COMPUTE, []) - - self.assertRaises(AttributeError, self.backend.create, res, - self.sec_obj) - - # provide immutable attr - res = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template]) - res.attributes = {'occi.compute.cores': 2} - - self.assertRaises(AttributeError, self.backend.create, res, - self.sec_obj) - - def test_update_for_failure(self): - """ - Test if correct errors are thrown. - """ - # msg mixin - res1 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, []) - res1.attributes = {'occi.core.id': 'bar'} - res2 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, []) - - self.assertRaises(AttributeError, self.backend.update, res1, res2, - self.sec_obj) - - res2 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [core_model.Category('http://foo.com', - 'bar', '', '', '')]) - - self.assertRaises(AttributeError, self.backend.update, res1, res2, - self.sec_obj) - - def test_action_for_failure(self): - """ - Test if correct errors are thrown. - """ - # wrong action - res1 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, []) - res1.attributes = {'occi.core.id': 'bar'} - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.STOPPED - }) - self.mox.ReplayAll() - self.assertRaises(AttributeError, self.backend.action, res1, - infrastructure.STOP, {}, self.sec_obj) - self.mox.VerifyAll() - - # missing method! - self.mox.UnsetStubs() - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.ACTIVE - }) - self.mox.ReplayAll() - self.assertRaises(AttributeError, self.backend.action, res1, - infrastructure.RESTART, {}, self.sec_obj) - self.mox.VerifyAll() - - # Test for Sanity - - def test_create_for_sanity(self): - """ - Simulate a create call! - """ - res = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template]) - - self.mox.StubOutWithMock(nova_glue.vm, 'create_vm') - nova_glue.vm.create_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'uuid': 'foo', - 'hostname': 'Server foo', - 'vcpus': 1, - 'memory_mb': 256 - }) - self.mox.StubOutWithMock(nova_glue.storage, 'get_image_architecture') - nova_glue.storage.get_image_architecture(mox.IsA(object), - mox.IsA(object)).\ - AndReturn('foo') - - self.mox.ReplayAll() - - self.backend.create(res, self.sec_obj) - - # check if all attrs are there! - self.assertIn('occi.compute.hostname', res.attributes) - self.assertIn('occi.compute.architecture', res.attributes) - self.assertIn('occi.compute.cores', res.attributes) - self.assertIn('occi.compute.speed', res.attributes) - self.assertIn('occi.compute.memory', res.attributes) - self.assertIn('occi.compute.state', res.attributes) - - self.assertEqual('inactive', res.attributes['occi.compute.state']) - - self.assertListEqual([infrastructure.STOP, infrastructure.SUSPEND, - infrastructure.RESTART], res.actions) - - self.mox.VerifyAll() - - def test_retrieve_for_sanity(self): - """ - Simulate a retrieve call! - """ - res = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template]) - res.attributes = {'occi.core.id': 'bar'} - - self.mox.StubOutWithMock(nova_glue.vm, 'get_occi_state') - nova_glue.vm.get_occi_state(mox.IsA(object), - mox.IsA(object)).\ - AndReturn(('active', [infrastructure.STOP, - infrastructure.SUSPEND, - infrastructure.RESTART])) - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'hostname': 'bar', - 'vcpus': 1, - 'memory_mb': 256 - }) - self.mox.StubOutWithMock(nova_glue.storage, 'get_image_architecture') - nova_glue.storage.get_image_architecture(mox.IsA(object), - mox.IsA(object)).\ - AndReturn('foo') - self.mox.ReplayAll() - - self.backend.retrieve(res, self.sec_obj) - - # check if all attrs are there! - self.assertIn('occi.compute.hostname', res.attributes) - self.assertIn('occi.compute.architecture', res.attributes) - self.assertIn('occi.compute.cores', res.attributes) - self.assertIn('occi.compute.speed', res.attributes) - self.assertIn('occi.compute.memory', res.attributes) - self.assertIn('occi.compute.state', res.attributes) - - self.assertIn('occi.core.id', res.attributes) - - self.assertEqual('active', res.attributes['occi.compute.state']) - - self.assertListEqual([infrastructure.STOP, infrastructure.SUSPEND, - infrastructure.RESTART], res.actions) - - self.mox.VerifyAll() - - def test_update_for_sanity(self): - """ - Simulate a update call! - """ - res1 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template]) - res1.attributes = {'occi.core.id': 'bar'} - - # case 1 - rebuild VM with different OS - res2 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template2]) - - self.mox.StubOutWithMock(nova_glue.vm, 'rebuild_vm') - nova_glue.vm.rebuild_vm(mox.IsA(object), mox.IsA(object), - mox.IsA(object)) - self.mox.ReplayAll() - self.backend.update(res1, res2, self.sec_obj) - - self.assertIn(self.os_template2, res1.mixins) - - self.mox.VerifyAll() - - # case 2 - resize the VM - res2 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.res_template2]) - - self.mox.StubOutWithMock(nova_glue.vm, 'resize_vm') - nova_glue.vm.resize_vm(mox.IsA(object), mox.IsA(object), - mox.IsA(object)) - self.mox.ReplayAll() - self.backend.update(res1, res2, self.sec_obj) - - self.assertIn(self.res_template2, res1.mixins) - - self.mox.VerifyAll() - - def test_replace_for_sanity(self): - """ - Simulate a replace call - does nothing atm. - """ - self.backend.replace(None, None, self.sec_obj) - - def test_delete_for_sanity(self): - """ - Simulate a delete call. - """ - res = core_model.Resource('/foo/bar', infrastructure.COMPUTE, - [self.os_template]) - res.attributes = {'occi.core.id': 'bar'} - - self.mox.StubOutWithMock(nova_glue.vm, 'delete_vm') - nova_glue.vm.delete_vm(mox.IsA(object), mox.IsA(object)) - self.mox.ReplayAll() - self.backend.delete(res, self.sec_obj) - - self.mox.VerifyAll() - - def test_action_for_sanity(self): - """ - Test actions - """ - res1 = core_model.Resource('/foo/bar', infrastructure.COMPUTE, []) - res1.attributes = {'occi.core.id': 'bar'} - - # start - self.mox.StubOutWithMock(nova_glue.vm, 'start_vm') - nova_glue.vm.start_vm(mox.IsA(object), mox.IsA(object)) - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.STOPPED - }) - self.mox.ReplayAll() - self.backend.action(res1, infrastructure.START, {}, self.sec_obj) - self.mox.VerifyAll() - - # stop - self.mox.UnsetStubs() - self.mox.StubOutWithMock(nova_glue.vm, 'stop_vm') - nova_glue.vm.stop_vm(mox.IsA(object), mox.IsA(object)) - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.ACTIVE - }) - self.mox.ReplayAll() - self.backend.action(res1, infrastructure.STOP, {}, self.sec_obj) - self.mox.VerifyAll() - - # reboot - self.mox.UnsetStubs() - self.mox.StubOutWithMock(nova_glue.vm, 'restart_vm') - nova_glue.vm.restart_vm(mox.IsA(object), mox.IsA(str), - mox.IsA(object)) - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.ACTIVE - }) - self.mox.ReplayAll() - self.backend.action(res1, infrastructure.RESTART, - {'method': 'graceful'}, self.sec_obj) - self.mox.VerifyAll() - - # suspend - self.mox.UnsetStubs() - self.mox.StubOutWithMock(nova_glue.vm, 'suspend_vm') - nova_glue.vm.suspend_vm(mox.IsA(object), mox.IsA(object)) - self.mox.StubOutWithMock(nova_glue.vm, 'get_vm') - nova_glue.vm.get_vm(mox.IsA(object), mox.IsA(object)).AndReturn( - { - 'vm_state': vm_states.ACTIVE - }) - self.mox.ReplayAll() - self.backend.action(res1, infrastructure.SUSPEND, {}, self.sec_obj) - self.mox.VerifyAll() diff --git a/tests/test_backends_network.py b/tests/test_backends_network.py deleted file mode 100644 index 43d411e..0000000 --- a/tests/test_backends_network.py +++ /dev/null @@ -1,200 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Test network resource backend. -""" - -#pylint: disable=W0102,C0103,R0904 - -import mox -import unittest -from occi import core_model - -from occi_os_api import nova_glue -from occi_os_api.backends import network -from occi_os_api.extensions import os_addon - - -class TestNetworkInterfaceBackend(unittest.TestCase): - """ - Tests the network interface backend! - """ - - def setUp(self): - """ - Setup the tests. - """ - self.backend = network.NetworkInterfaceBackend() - self.sec_obj = {'nova_ctx': None} - self.mox = mox.Mox() - - def tearDown(self): - """ - Cleanup mocks. - """ - self.mox.UnsetStubs() - - # Test for failure - - def test_create_for_failure(self): - """ - Test create for failure! - """ - source = mox.MockObject(core_model.Resource) - source.attributes = {'occi.core.id': 'bar'} - target = mox.MockObject(core_model.Resource) - target.identifier = '/network/admin' - - link = core_model.Link('foo', None, [], source, target) - - self.mox.ReplayAll() - - self.assertRaises(AttributeError, self.backend.create, link, - self.sec_obj) - - self.mox.VerifyAll() - - # should have pool name in attribute... - target.identifier = '/network/public' - link = core_model.Link('foo', None, [os_addon.OS_NET_LINK], source, - target) - - self.mox.ReplayAll() - self.assertRaises(AttributeError, self.backend.create, link, - self.sec_obj) - - self.mox.VerifyAll() - - def test_update_for_failure(self): - """ - No updates allowed! - """ - self.assertRaises(AttributeError, self.backend.update, None, None, - None) - - # Test for sanity! - - def test_create_for_sanity(self): - """ - Test create for sanity! - """ - source = mox.MockObject(core_model.Resource) - source.attributes = {'occi.core.id': 'bar'} - target = mox.MockObject(core_model.Resource) - target.identifier = '/network/public' - - link = core_model.Link('foo', None, [os_addon.OS_NET_LINK], source, - target) - link.attributes = {'org.openstack.network.floating.pool': 'nova'} - - self.mox.StubOutWithMock(nova_glue.net, 'add_floating_ip') - nova_glue.net.add_floating_ip(mox.IsA(str), mox.IsA(str), - mox.IsA(object)).AndReturn('10.0.0.1') - - self.mox.ReplayAll() - self.backend.create(link, self.sec_obj) - - # verify all attrs and mixins! - self.assertIn('occi.networkinterface.interface', link.attributes) - self.assertIn('occi.networkinterface.mac', link.attributes) - self.assertIn('occi.networkinterface.state', link.attributes) - self.assertIn('occi.networkinterface.address', link.attributes) - self.assertIn('occi.networkinterface.gateway', link.attributes) - self.assertIn('occi.networkinterface.allocation', link.attributes) - - # self.assertIn(infrastructure.IPNETWORKINTERFACE, link.mixins) - # self.assertIn(infrastructure.NETWORKINTERFACE, link.mixins) - - # test without pool name... - self.mox.UnsetStubs() - link = core_model.Link('foo', None, [], source, target) - - self.mox.StubOutWithMock(nova_glue.net, 'add_floating_ip') - - nova_glue.net.add_floating_ip(mox.IsA(str), mox.IsA(None), - mox.IsA(object)).AndReturn('10.0.0.2') - - self.mox.ReplayAll() - self.backend.create(link, self.sec_obj) - self.mox.VerifyAll() - - def test_delete_for_sanity(self): - """ - Test create for sanity! - """ - source = mox.MockObject(core_model.Resource) - source.attributes = {'occi.core.id': 'bar'} - target = mox.MockObject(core_model.Resource) - target.identifier = '/network/public' - - link = core_model.Link('foo', None, [], source, target) - link.attributes = {'occi.networkinterface.address': '10.0.0.1'} - - self.mox.StubOutWithMock(nova_glue.net, 'remove_floating_ip') - nova_glue.net.remove_floating_ip(mox.IsA(object), mox.IsA(object), - mox.IsA(object)) - - self.mox.ReplayAll() - - self.backend.delete(link, self.sec_obj) - - self.mox.VerifyAll() - - -class TestNetworkBackend(unittest.TestCase): - """ - Some tests for network resources. - """ - - def setUp(self): - """ - Initialize test. - """ - self.backend = network.NetworkBackend() - - def test_create_for_failure(self): - """ - Expecting an error! - """ - self.assertRaises(AttributeError, self.backend.create, None, None) - - def test_action_for_failure(self): - """ - Expecting an error! - """ - self.assertRaises(AttributeError, self.backend.action, None, - None, None, None) - - -class TestIpNetworkBackend(unittest.TestCase): - """ - Some tests for network resources. - """ - - def setUp(self): - """ - Initialize test. - """ - self.backend = network.IpNetworkBackend() - - def test_create_for_failure(self): - """ - Expecting an error! - """ - self.assertRaises(AttributeError, self.backend.create, None, None) diff --git a/tests/test_backends_storage.py b/tests/test_backends_storage.py deleted file mode 100644 index 90fd6ca..0000000 --- a/tests/test_backends_storage.py +++ /dev/null @@ -1,296 +0,0 @@ -# coding=utf-8 -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# -# Copyright (c) 2012, Intel Performance Learning Solutions Ltd. -# -# 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. - -""" -Test network resource backend. -""" - -#pylint: disable=W0102,C0103,R0904,R0801 - - -import mox -import unittest - -from occi import core_model, exceptions -from occi.extensions import infrastructure - -from occi_os_api import nova_glue -from occi_os_api.backends import storage - - -class TestStorageBackend(unittest.TestCase): - """ - Tests the storage backend! - """ - - def setUp(self): - """ - Setup the tests. - """ - self.backend = storage.StorageBackend() - self.sec_obj = {'nova_ctx': None} - self.mox = mox.Mox() - - def tearDown(self): - """ - Cleanup mocks. - """ - self.mox.UnsetStubs() - - # Test for failure - - def test_create_for_failure(self): - """ - Test attachement. - """ - # msg size attribute - res = mox.MockObject(core_model.Resource) - res.attributes = {} - self.assertRaises(AttributeError, self.backend.create, res, - self.sec_obj) - - # error in volume creation - res.attributes = {'occi.storage.size': '1'} - - self.mox.StubOutWithMock(nova_glue.storage, 'create_storage') - nova_glue.storage.create_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'id': '1'}) - self.mox.StubOutWithMock(nova_glue.storage, 'get_storage') - nova_glue.storage.get_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'status': 'error'}) - - self.mox.ReplayAll() - - self.assertRaises(exceptions.HTTPError, self.backend.create, res, - self.sec_obj) - - self.mox.VerifyAll() - - def test_action_for_failure(self): - """ - Test actions - """ - res = mox.MockObject(core_model.Resource) - res.actions = [] - - # snapshot - self.assertRaises(AttributeError, self.backend.action, res, - infrastructure.SNAPSHOT, {}, self.sec_obj) - - # Test for sanity - - def test_create_for_sanity(self): - """ - Test creation. - """ - res = mox.MockObject(core_model.Resource) - res.attributes = {'occi.storage.size': '1'} - - self.mox.StubOutWithMock(nova_glue.storage, 'create_storage') - nova_glue.storage.create_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'id': '1'}) - self.mox.StubOutWithMock(nova_glue.storage, 'get_storage') - nova_glue.storage.get_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'status': 'available'}) - - self.mox.ReplayAll() - - self.backend.create(res, self.sec_obj) - - # verify all attrs. - self.assertEqual(res.attributes['occi.storage.state'], 'active') - self.assertListEqual([infrastructure.OFFLINE, infrastructure.BACKUP, - infrastructure.SNAPSHOT, infrastructure.RESIZE], - res.actions) - - self.mox.VerifyAll() - - def test_retrieve_for_sanity(self): - """ - Test retrieval. - """ - res = mox.MockObject(core_model.Resource) - res.attributes = {'occi.core.id': '1'} - - self.mox.StubOutWithMock(nova_glue.storage, 'get_storage') - nova_glue.storage.get_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'status': 'available', 'size': '1'}) - - self.mox.ReplayAll() - - self.backend.retrieve(res, self.sec_obj) - - # verify all attrs. - self.assertEqual(res.attributes['occi.storage.state'], 'online') - self.assertListEqual([infrastructure.OFFLINE, infrastructure.BACKUP, - infrastructure.SNAPSHOT, infrastructure.RESIZE], - res.actions) - - self.mox.VerifyAll() - - self.mox.UnsetStubs() - self.mox.StubOutWithMock(nova_glue.storage, 'get_storage') - nova_glue.storage.get_storage(mox.IsA(object), - mox.IsA(object)).\ - AndReturn({'status': 'bla', 'size': '1'}) - - self.mox.ReplayAll() - - self.backend.retrieve(res, self.sec_obj) - - # verify all attrs. - self.assertEqual(res.attributes['occi.storage.state'], 'offline') - self.assertTrue(len(res.actions) == 1) - self.mox.VerifyAll() - - def test_update_for_sanity(self): - """ - Test updating. - """ - res1 = mox.MockObject(core_model.Resource) - res1.attributes = {} - res2 = mox.MockObject(core_model.Resource) - res2.attributes = {'occi.core.title': 'foo', - 'occi.core.summary': 'bar'} - - self.mox.ReplayAll() - - self.backend.update(res1, res2, self.sec_obj) - - # verify all attrs. - self.assertEqual(res1.attributes['occi.core.title'], 'foo') - self.assertEqual(res1.attributes['occi.core.summary'], 'bar') - - self.mox.VerifyAll() - - def test_remove_for_sanity(self): - """ - Test removal. - """ - res = mox.MockObject(core_model.Resource) - res.attributes = {'occi.core.id': '1'} - - self.mox.StubOutWithMock(nova_glue.storage, 'delete_storage_instance') - nova_glue.storage.delete_storage_instance(mox.IsA(object), - mox.IsA(object)) - - self.mox.ReplayAll() - - self.backend.delete(res, self.sec_obj) - - self.mox.VerifyAll() - - def test_action_for_sanity(self): - """ - Test actions - """ - res = mox.MockObject(core_model.Resource) - res.attributes = {'occi.core.id': '1', - 'occi.core.summary': 'foo'} - res.actions = [infrastructure.SNAPSHOT, infrastructure.BACKUP] - - # snapshot - self.mox.StubOutWithMock(nova_glue.storage, - 'snapshot_storage_instance') - nova_glue.storage.snapshot_storage_instance(mox.IsA(object), - mox.IsA(object), - mox.IsA(object), - mox.IsA(object)) - self.mox.ReplayAll() - self.backend.action(res, infrastructure.SNAPSHOT, {}, self.sec_obj) - self.mox.VerifyAll() - - # some other action - self.mox.ReplayAll() - self.backend.action(res, infrastructure.BACKUP, {}, self.sec_obj) - self.mox.VerifyAll() - - -class TestStorageLinkBackend(unittest.TestCase): - """ - Tests storage linking. - """ - - def setUp(self): - """ - Setup the tests. - """ - self.backend = storage.StorageLinkBackend() - self.sec_obj = {'nova_ctx': None} - self.mox = mox.Mox() - - def tearDown(self): - """ - Cleanup mocks. - """ - self.mox.UnsetStubs() - - # Test for sanity - - def test_create_for_sanity(self): - """ - Test attachement. - """ - source = mox.MockObject(core_model.Resource) - source.attributes = {'occi.core.id': 'foo'} - target = mox.MockObject(core_model.Resource) - target.attributes = {'occi.core.id': 'bar'} - - link = core_model.Link('foo', None, [], source, target) - link.attributes = {'occi.storagelink.deviceid': '/dev/sda'} - - self.mox.StubOutWithMock(nova_glue.vm, 'attach_volume') - nova_glue.vm.attach_volume(mox.IsA(object), mox.IsA(object), - mox.IsA(object), mox.IsA(object)).\ - AndReturn({}) - - self.mox.ReplayAll() - - self.backend.create(link, self.sec_obj) - - # verify all attrs. - self.assertEqual(link.attributes['occi.storagelink.deviceid'], - '/dev/sda') - self.assertIn('occi.storagelink.mountpoint', link.attributes) - self.assertEqual(link.attributes['occi.storagelink.state'], 'active') - - self.mox.VerifyAll() - - def test_delete_for_sanity(self): - """ - Test deattachement. - """ - source = mox.MockObject(core_model.Resource) - target = mox.MockObject(core_model.Resource) - target.attributes = {'occi.core.id': 'bar'} - - link = core_model.Link('foo', None, [], source, target) - - self.mox.StubOutWithMock(nova_glue.vm, 'detach_volume') - nova_glue.vm.detach_volume(mox.IsA(object), mox.IsA(object)) - - self.mox.ReplayAll() - - self.backend.delete(link, self.sec_obj) - - self.mox.VerifyAll()