Merge "Auto Generated INFO.yaml file"
authorRandy Levensalor <r.levensalor@cablelabs.com>
Tue, 18 Sep 2018 16:37:08 +0000 (16:37 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Tue, 18 Sep 2018 16:37:08 +0000 (16:37 +0000)
92 files changed:
docs/how-to-use/APITests.rst
docs/how-to-use/IntegrationTests.rst
docs/how-to-use/LibraryUsage.rst
docs/how-to-use/Testing.rst
docs/how-to-use/VirtEnvDeploy.rst
docs/release/release-notes.rst [new file with mode: 0644]
examples/complex-network/deploy-complex-network.yaml
examples/external-network/deploy-ext-net.yaml
examples/inst-w-volume/deploy-vm-with-volume.yaml
examples/simple/deploy-simple.yaml
examples/two-network/deploy-two-net-centos.yaml
examples/two-network/deploy-two-net-ubuntu.yaml
requirements.txt
snaps/config/network.py
snaps/config/project.py
snaps/config/router.py
snaps/config/security_group.py
snaps/config/stack.py
snaps/config/tests/network_tests.py
snaps/config/tests/project_tests.py
snaps/config/tests/router_tests.py
snaps/config/tests/volume_tests.py
snaps/config/volume.py
snaps/domain/network.py
snaps/domain/stack.py
snaps/domain/test/network_tests.py
snaps/domain/test/stack_tests.py
snaps/domain/test/vm_inst_tests.py
snaps/domain/test/volume_tests.py
snaps/domain/vm_inst.py
snaps/domain/volume.py
snaps/file_utils.py
snaps/openstack/cluster_template.py
snaps/openstack/create_flavor.py
snaps/openstack/create_image.py
snaps/openstack/create_instance.py
snaps/openstack/create_keypairs.py
snaps/openstack/create_network.py
snaps/openstack/create_project.py
snaps/openstack/create_qos.py
snaps/openstack/create_router.py
snaps/openstack/create_security_group.py
snaps/openstack/create_stack.py
snaps/openstack/create_user.py
snaps/openstack/create_volume.py
snaps/openstack/create_volume_type.py
snaps/openstack/openstack_creator.py
snaps/openstack/os_credentials.py
snaps/openstack/tests/cluster_template_tests.py
snaps/openstack/tests/conf/os_credentials_tests.py
snaps/openstack/tests/conf/os_env.yaml.template
snaps/openstack/tests/create_flavor_tests.py
snaps/openstack/tests/create_image_tests.py
snaps/openstack/tests/create_instance_tests.py
snaps/openstack/tests/create_keypairs_tests.py
snaps/openstack/tests/create_network_tests.py
snaps/openstack/tests/create_project_tests.py
snaps/openstack/tests/create_qos_tests.py
snaps/openstack/tests/create_router_tests.py
snaps/openstack/tests/create_security_group_tests.py
snaps/openstack/tests/create_stack_tests.py
snaps/openstack/tests/create_user_tests.py
snaps/openstack/tests/create_volume_tests.py
snaps/openstack/tests/create_volume_type_tests.py
snaps/openstack/tests/heat/agent-group.yaml
snaps/openstack/tests/heat/floating_ip_heat_template.yaml
snaps/openstack/tests/openstack_tests.py
snaps/openstack/tests/os_source_file_test.py
snaps/openstack/utils/__init__.py
snaps/openstack/utils/cinder_utils.py
snaps/openstack/utils/glance_utils.py
snaps/openstack/utils/heat_utils.py
snaps/openstack/utils/keystone_utils.py
snaps/openstack/utils/launch_utils.py
snaps/openstack/utils/magnum_utils.py
snaps/openstack/utils/neutron_utils.py
snaps/openstack/utils/nova_utils.py
snaps/openstack/utils/settings_utils.py
snaps/openstack/utils/tests/cinder_utils_tests.py
snaps/openstack/utils/tests/glance_utils_tests.py
snaps/openstack/utils/tests/heat_utils_tests.py
snaps/openstack/utils/tests/keystone_utils_tests.py
snaps/openstack/utils/tests/magnum_utils_tests.py
snaps/openstack/utils/tests/neutron_utils_tests.py
snaps/openstack/utils/tests/nova_utils_tests.py
snaps/openstack/utils/tests/settings_utils_tests.py
snaps/provisioning/ansible_utils.py
snaps/provisioning/tests/ansible_utils_tests.py
snaps/test_runner.py
snaps/test_suite_builder.py
snaps/tests/file_utils_tests.py
snaps/thread_utils.py [new file with mode: 0644]

index 50cd437..9f46839 100644 (file)
@@ -104,6 +104,9 @@ create_project_tests.py - CreateProjectSuccessTests
 | test_create_project              | 2 & 3         | Tests the creation of a project via the OpenStackProject  |
 |                                  |               | class                                                     |
 +----------------------------------+---------------+-----------------------------------------------------------+
+| test_create_project_quota        | 2 & 3         | Tests the creation of a project via the OpenStackProject  |
+| _override                        |               | class with overriding the default quota values            |
++----------------------------------+---------------+-----------------------------------------------------------+
 | test_create_project_2x           | 2 & 3         | Tests the creation of a project a second time via the     |
 |                                  |               | OpenStackProject class to ensure it is only created once  |
 +----------------------------------+---------------+-----------------------------------------------------------+
@@ -435,7 +438,16 @@ nova_utils_tests.py - NovaUtilsInstanceVolumeTests
 | Test Name                             | Nova API      | Description                                               |
 +=======================================+===============+===========================================================+
 | test_add_remove_volume                | 2             | Ensures that a VM instance can properly attach and detach |
-|                                       |               | a volume using the nova interface                         |
+|                                       |               | a volume using the nova interface while waiting for       |
+|                                       |               | the update to fully occur                                 |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_attach_volume_nowait             | 2             | Ensures that the call to nova_utils.attach_volume raises  |
+|                                       |               | an exception when the timeout is too short to return an   |
+|                                       |               | properly updated VmInst object                            |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_detach_volume_nowait             | 2             | Ensures that the call to nova_utils.detach_volume raises  |
+|                                       |               | an exception when the timeout is too short to return an   |
+|                                       |               | properly updated VmInst object                            |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
 create_flavor_tests.py - CreateFlavorTests
index 59ec8a9..79ef8ef 100644 (file)
@@ -46,6 +46,17 @@ create_security_group_tests.py - CreateSecurityGroupTests
 |                                       |               | setting object                                            |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
+create_security_group_tests.py - CreateMultipleSecurityGroupTests
+-----------------------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | API Versions  | Description                                               |
++=======================================+===============+===========================================================+
+| test_sec_grp_same_name_diff_proj      | Keysone 2 & 3 | Ensures the OpenStackSecurityGroup class does not         |
+|                                       | Neutron 2     | initialize security groups with the same name from other  |
+|                                       |               | project/tenants                                           |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
 create_image_tests.py - CreateImageSuccessTests
 -----------------------------------------------
 
@@ -185,6 +196,25 @@ create_network_tests.py - CreateNetworkSuccessTests
 |                                       |               | 'admin' project ID                                        |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
+create_network_tests.py - CreateNetworkGatewayTests
+---------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | Neutron API   | Description                                               |
++=======================================+===============+===========================================================+
+| test_create_subnet_default_gateway_ip | 2             | Ensures that a network can be created with a Subnet that  |
+|                                       |               | has the gateway_ip automatically assigned                 |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_subnet_valid_gateway_ip   | 2             | Ensures that a network can be created with a Subnet that  |
+|                                       |               | has the gateway_ip statically assigned with a valid IP    |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_subnet_no_gateway         | 2             | Ensures that a network can be created where no gateway_ip |
+|                                       |               | is assigned                                               |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_subnet_invalid_gateway_ip | 2             | Ensures that a network cannot be created with a Subnet    |
+|                                       |               | has an invalid gateway_ip value such as 'foo'             |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
 create_network_tests.py - CreateNetworkIPv6Tests
 ------------------------------------------------
 
@@ -197,6 +227,21 @@ create_network_tests.py - CreateNetworkIPv6Tests
 |                                       |               | IPv6 subnet                                               |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
+create_network_tests.py - CreateMultipleNetworkTests
+----------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | Neutron API   | Description                                               |
++=======================================+===============+===========================================================+
+| test_network_same_name_diff_proj      | 2             | Ensures that a network with the same name can be created  |
+|                                       |               | against different projects                                |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_network_create_by_admin_to       | 2             | Ensures that a network can be created by the admin user   |
+| _different_project                    |               | to another project and that a creator with the credentials|
+|                                       |               | to the other project will not create a new network with   |
+|                                       |               | the same name                                             |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
 create_router_tests.py - CreateRouterSuccessTests
 -------------------------------------------------
 
@@ -215,6 +260,12 @@ create_router_tests.py - CreateRouterSuccessTests
 | test_create_delete_router             | 2             | Ensures that a router can be deleted via the              |
 |                                       |               | OpenStackRouter.clean() method                            |
 +---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_with_internal_sub         | 2             | Ensures that a router can be joined to a subnet created by|
+|                                       |               | the same user who created the subnet                      |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_with_invalid_internal_sub | 2             | Ensures that a router cannot be created when attempting to|
+|                                       |               | join a subnet created by the admin user                   |
++---------------------------------------+---------------+-----------------------------------------------------------+
 | test_create_router_admin_state_false  | 2             | Ensures that a router can created with                    |
 |                                       |               | admin_state_up = False                                    |
 +---------------------------------------+---------------+-----------------------------------------------------------+
@@ -227,6 +278,9 @@ create_router_tests.py - CreateRouterSuccessTests
 | test_create_router_external_network   | 2             | Ensures that a router can be created that is connected to |
 |                                       |               | both external and private internal networks               |
 +---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_router_with_ext_port      | 2             | Ensures that a router can be created by an 'admin' user   |
+|                                       |               | with a port to an external network                        |
++---------------------------------------+---------------+-----------------------------------------------------------+
 
 create_router_tests.py - CreateRouterNegativeTests
 --------------------------------------------------
@@ -240,6 +294,51 @@ create_router_tests.py - CreateRouterNegativeTests
 | test_create_router_invalid_gateway_name| 2             | Ensures that an exception is raised when attempting to    |
 |                                        |               | create a router to an external network that does not exist|
 +----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_router_admin_ports         | 2             | Ensures that an exception is raised when attempting to    |
+|                                        |               | create a router with ports to networks owned by another   |
+|                                        |               | project                                                   |
++----------------------------------------+---------------+-----------------------------------------------------------+
+
+create_router_tests.py - CreateMultipleRouterTests
+--------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | Neutron API   | Description                                               |
++=======================================+===============+===========================================================+
+| test_router_same_name_diff_proj       | 2             | Ensures that a router with the same name can be created   |
+|                                       |               | against different projects                                |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_router_create_by_admin_to        | 2             | Ensures that a router can be created by the admin user    |
+| _different_project                    |               | to another project and that a creator with the credentials|
+|                                       |               | to the other project will not create a new router with    |
+|                                       |               | the same name                                             |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
+create_router_tests.py - CreateRouterSecurityGroupTests
+-------------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | Neutron API   | Description                                               |
++=======================================+===============+===========================================================+
+| test_create_router_secure_port        | 2             | Ensures that a router's port can have a security group    |
+|                                       |               | applied to it                                             |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
+create_router_tests.py - CreateRouterSharedNetworksTests
+--------------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | Neutron API   | Description                                               |
++=======================================+===============+===========================================================+
+| test_create_router_external           | 2             | Ensures that a router can be joined to an external network|
+|                                       |               | that was created by an admin user                         |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_router_port_external      | 2             | Ensures that a router can have a port created to an       |
+|                                       |               | external network that was created by an admin user        |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_router_port_shared        | 2             | Ensures that a router can have a port created to an       |
+|                                       |               | shared network that was created by an admin user          |
++---------------------------------------+---------------+-----------------------------------------------------------+
 
 create_qos_tests.py - CreateQoSTests
 ------------------------------------
@@ -332,9 +431,6 @@ create_volume_tests.py - CreateSimpleVolumeFailureTests
 | test_create_volume_bad_image           | 2 & 3         | Tests to ensure that attempting to create a volume with an|
 |                                        |               | image that does not exist raises a BadRequest exception   |
 +----------------------------------------+---------------+-----------------------------------------------------------+
-| test_create_volume_bad_zone            | 2 & 3         | Tests to ensure that attempting to create a volume with an|
-|                                        |               | invalid availability zone raises a BadRequest exception   |
-+----------------------------------------+---------------+-----------------------------------------------------------+
 
 create_volume_tests.py - CreateVolumeWithTypeTests
 --------------------------------------------------
@@ -368,6 +464,25 @@ create_volume_tests.py - CreateVolumeWithImageTests
 |                                        |               | volume when associating with a valid image                |
 +----------------------------------------+---------------+-----------------------------------------------------------+
 
+create_volume_tests.py - CreateVolMultipleCredsTests
+----------------------------------------------------
+
++----------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                              |  Cinder API   | Description                                               |
++========================================+===============+===========================================================+
+| test_create_by_admin_to_other_proj     | 2 & 3         | Tests to ensure the creation of a Volume as a user with   |
+|                                        |               | an 'admin' role can create a volume to another project    |
+|                                        |               | and a creator with the credentails to that project will   |
+|                                        |               | not create another with the same name                     |
+|                                        |               | Currently inactive due to                                 |
+|                                        |               | https://bugs.launchpad.net/cinder/+bug/1641982            |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_two_vol_same_name_diff_proj| 2 & 3         | Tests to ensure the creation of a Volume with the same    |
+|                                        |               | name by two different creators with different credentials |
+|                                        |               | will create two different volumes with the same name      |
+|                                        |               | that are applied to each project in question              |
++----------------------------------------+---------------+-----------------------------------------------------------+
+
 create_stack_tests.py - CreateStackSuccessTests
 -----------------------------------------------
 
@@ -418,6 +533,12 @@ create_stack_tests.py - CreateStackFloatingIpTests
 |                                       |               | VM with a floating IP that can be accessed via            |
 |                                       |               | OpenStackVmInstance                                       |
 +---------------------------------------+---------------+-----------------------------------------------------------+
+| test_connect_via_ssh_heat_vm_derived  | 1             | Ensures that an OpenStackHeatStack instance can create a  |
+|                                       |               | VM with a floating IP where a generated initialized       |
+|                                       |               | OpenStackHeatStack can return an initialized              |
+|                                       |               | OpenStackVmInstance object that will be used to access the|
+|                                       |               | VM via SSH                                                |
++---------------------------------------+---------------+-----------------------------------------------------------+
 
 create_stack_tests.py - CreateStackNestedResourceTests
 ------------------------------------------------------
@@ -431,6 +552,17 @@ create_stack_tests.py - CreateStackNestedResourceTests
 |                                       |               | initialized OpenStackVmInstance objects                   |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
+create_stack_tests.py - CreateStackUpdateTests
+----------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             |   Heat API    | Description                                               |
++=======================================+===============+===========================================================+
+| test_update                           | 1             | Ensures that an OpenStackHeatStack can have the number of |
+|                                       |               | VMs updated and they are spawned and access can be        |
+|                                       |               | obtained with SSH over floating IPs                       |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
 create_stack_tests.py - CreateStackRouterTests
 ----------------------------------------------
 
@@ -516,7 +648,21 @@ create_instance_tests.py - CreateInstanceSimpleTests
 | Test Name                             | API Versions  | Description                                               |
 +=======================================+===============+===========================================================+
 | test_create_delete_instance           | Nova 2        | Ensures that the OpenStackVmInstance.clean() method       |
-|                                       | Neutron 2     | deletes the instance                                      |
+|                                       | Neutron 2     | deletes the instance as well as ensuring the VmInst       |
+|                                       |               | availability_zone is populated and compute_host is None   |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_admin_instance            | Nova 2        | Ensures that the VmInst object members availability_zone  |
+|                                       | Neutron 2     | and compute_host return a value                           |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
+create_instance_tests.py - CreateInstanceExternalNetTests
+---------------------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                             | API Versions  | Description                                               |
++=======================================+===============+===========================================================+
+| test_create_instance_public_net       | Nova 2        | Ensures that an OpenStackVmInstance initialized as a user |
+|                                       | Neutron 2     | of type 'admin' can create a VM against an external net   |
 +---------------------------------------+---------------+-----------------------------------------------------------+
 
 create_instance_tests.py - SimpleHealthCheck
@@ -576,6 +722,12 @@ create_instance_tests.py - CreateInstancePortManipulationTests
 | test_set_custom_valid_ip_one_subnet   | Nova 2        | Ensures that an instance's can have a valid static IP is  |
 |                                       | Neutron 2     | properly assigned                                         |
 +---------------------------------------+---------------+-----------------------------------------------------------+
+| test_set_one_port_two_ip_one_subnet   | Nova 2        | Ensures that an instance can have two static IPs on a     |
+|                                       | Neutron 2     | single port from a single subnet                          |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_set_one_port_two_ip_two_subnets  | Nova 2        | Ensures that an instance can have two static IPs on a     |
+|                                       | Neutron 2     | single port from different subnets on a network           |
++---------------------------------------+---------------+-----------------------------------------------------------+
 | test_set_custom_invalid_ip_one_subnet | Nova 2        | Ensures that an instance's port with an invalid static IP |
 |                                       | Neutron 2     | raises an exception                                       |
 +---------------------------------------+---------------+-----------------------------------------------------------+
index aa7bf91..3183305 100644 (file)
@@ -154,6 +154,10 @@ Create Flavor
       -  is\_public - flag that denotes whether or not other projects
          can access image (default=True)
       -  metadata - freeform dict() for special metadata (optional)
+                  - freeform dict() for values of basic elements
+                    (e.g. ram, vcpu, disk, etc) could be added.
+                    As result the hard coded values of those elements will be
+                    overwritten by the new ones (optional)
 
 .. code:: python
 
index 92340ab..8e08abb 100644 (file)
@@ -26,6 +26,8 @@ Execute the tests
 | \* -f [optional - When set, will execute tests requiring Floating
   IPS]
 | \* -im [optional - File containing image endpoints to override
-| \* -fm [optional - JSON string containing a dict() for flavor metadata default='{\"hw:mem_page_size\": \"any\"}']
+| \* -fm [optional - JSON string containing a dict(): - for flavor metadata default='{\"hw:mem_page_size\": \"any\"}'
+                                                      - for values of basic elements (e.g. ram, vcpu, disk, etc) could be added.
+                                                        As result the hard coded values of those elements will be overwritten by the new ones]
 | \* -ci [optional - runs the tests required by SNAPS-OO CI]
 | \* -r [optional with default value of '1' - The number of test iterations to execute]
index 6c99992..0345f34 100644 (file)
@@ -121,7 +121,11 @@ Use launcher.py to deploy and clean up example environments.  These examples are
           -  rxtx\_factor: the receive/transmit factor to be set on ports if
              backend supports QoS extension (default 1.0)
           -  is\_public: denotes whether or not the flavor is public (default = True)
-          -  metadata: freeform dict() for special metadata (optional)
+          -  metadata: - freeform dict() for special metadata (optional)
+                       - freeform dict() for values of basic elements
+                         (e.g. ram, vcpu, disk, etc) could be added.
+                         As result the hard coded values of those elements will be
+                         overwritten by the new ones (optional)
 
    -  qos_specs: the QoS Specs to create
 
diff --git a/docs/release/release-notes.rst b/docs/release/release-notes.rst
new file mode 100644 (file)
index 0000000..d682dd9
--- /dev/null
@@ -0,0 +1,25 @@
+=================
+SNAPS-OO in OPNFV
+=================
+
+Introduction
+============
+
+SNAPS-OO is a object-oriented library designed for managing objects deployed
+on OpenStack. In addition to its ability to deploy and manage objects, this
+project also contains many API and integration tests that can be used to
+validate your OpenStack cloud. Also included is a lightweight orchestrator that
+can be used for rapid prototyping virtual environments.
+
+Installation
+============
+
+To use SNAPS-OO, it must first be installed into your Python 2.7-3.5 runtime.
+To install:
+
+pip install -e <SNAPS-OO directory>
+
+Using SNAPS-OO
+==============
+
+Please refer to the RST documents in ../how-to-use
\ No newline at end of file
index 7915c38..be38794 100644 (file)
@@ -70,8 +70,14 @@ openstack:
         name: mgr-router
         external_gateway: external
         internal_subnets:
-          - mgr-subnet
-          - mgr-subnet-2
+          - subnet:
+              project_name: admin
+              network_name: mgr-net
+              subnet_name: mgr-subnet
+          - subnet:
+              project_name: admin
+              network_name: mgr-net
+              subnet_name: mgr-subnet-2
         interfaces:
           - port:
               name: mgr-router-to-site1
@@ -83,12 +89,18 @@ openstack:
         name: site1-router
         external_gateway: external
         internal_subnets:
-          - site1-subnet
+          - subnet:
+              project_name: admin
+              network_name: site1-net
+              subnet_name: site1-subnet
     - router:
         name: site2-router
         external_gateway: external
         internal_subnets:
-          - site2-subnet
+          - subnet:
+              project_name: admin
+              network_name: site2-net
+              subnet_name: site2-subnet
     - router:
         name: site-to-site-router
         interfaces:
index ac5e214..b5f00b1 100644 (file)
@@ -52,7 +52,10 @@ openstack:
         name: ext-net-router
         external_gateway: ext-net
         internal_subnets:
-          - internal-subnet
+          - subnet:
+              project_name: admin
+              network_name: internal-net
+              subnet_name: internal-subnet
   keypairs:
     - keypair:
         name: ext-net-kp
index 30dbcc0..b15f655 100644 (file)
@@ -95,7 +95,10 @@ openstack:
         name: {{ router_name }}
         external_gateway: {{ ext_net }}
         internal_subnets:
-          - {{ subnet_name }}
+          - subnet:
+              project_name: {{ admin_proj }}
+              network_name: {{ net_name }}
+              subnet_name: {{ subnet_name }}
   keypairs:
     - keypair:
         os_user:
index 3124210..fa4c8b2 100644 (file)
@@ -41,7 +41,10 @@ openstack:
         name: simple-router
         external_gateway: external
         internal_subnets:
-          - simple-subnet
+          - subnet:
+              project_name: admin
+              network_name: simple-net
+              subnet_name: simple-subnet
   keypairs:
     - keypair:
         name: simple-kp
index 4b5ba89..d23fff9 100644 (file)
@@ -48,7 +48,10 @@ openstack:
         name: router-1
         external_gateway: external
         internal_subnets:
-          - subnet-1
+          - subnet:
+              project_name: admin
+              network_name: net-1
+              subnet_name: subnet-1
   keypairs:
     - keypair:
         name: two-net
index 0ad471c..0381bff 100644 (file)
@@ -48,7 +48,10 @@ openstack:
         name: router-1
         external_gateway: external
         internal_subnets:
-          - subnet-1
+          - subnet:
+              project_name: admin
+              network_name: net-1
+              subnet_name: subnet-1
   keypairs:
     - keypair:
         name: simple
index 137159f..1b4481f 100644 (file)
@@ -1,14 +1,15 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-python-novaclient>=9.0.0 # Apache-2.0
-python-neutronclient>=6.3.0 # Apache-2.0
+python-novaclient>=9.1.0 # Apache-2.0
+python-neutronclient>=6.7.0 # Apache-2.0
 python-keystoneclient>=3.8.0 # Apache-2.0
 python-glanceclient>=2.8.0 # Apache-2.0
-python-heatclient>=1.6.1 # Apache-2.0
-python-cinderclient>=3.1.0 # Apache-2.0
-python-magnumclient>=2.0.0 # Apache-2.0
-ansible<2.4,>=2.1.0
+python-heatclient>=1.10.0 # Apache-2.0
+python-cinderclient>=3.3.0 # Apache-2.0
+python-magnumclient>=2.1.0,<2.3 # Apache-2.0
+ansible>=2.4
 wrapt>=1.7.0 # BSD License
 scp
-cryptography!=2.0,>=1.6 # BSD/Apache-2.0
+cryptography>=2.1 # BSD/Apache-2.0
+concurrencytest
index 39a4254..b142480 100644 (file)
@@ -46,6 +46,7 @@ class NetworkConfig(object):
         :param segmentation_id: the id of the segmentation
                                  (this is required when network_type is 'vlan')
         :param subnets or subnet_settings: List of SubnetConfig objects.
+        :param mtu: MTU setting (optional)
         :return:
         """
 
@@ -88,6 +89,8 @@ class NetworkConfig(object):
         if not self.name or len(self.name) < 1:
             raise NetworkConfigError('Name required for networks')
 
+        self.mtu = kwargs.get('mtu')
+
     def get_project_id(self, os_creds):
         """
         Returns the project ID for a given project_name or None
@@ -98,11 +101,15 @@ class NetworkConfig(object):
             return self.project_id
         else:
             if self.project_name:
-                keystone = keystone_utils.keystone_client(os_creds)
-                project = keystone_utils.get_project(
-                    keystone=keystone, project_name=self.project_name)
-                if project:
-                    return project.id
+                session = keystone_utils.keystone_session(os_creds)
+                keystone = keystone_utils.keystone_client(os_creds, session)
+                try:
+                    project = keystone_utils.get_project(
+                        keystone=keystone, project_name=self.project_name)
+                    if project:
+                        return project.id
+                finally:
+                    keystone_utils.close_session(session)
 
         return None
 
@@ -140,6 +147,8 @@ class NetworkConfig(object):
             out['provider:segmentation_id'] = self.segmentation_id
         if self.external:
             out['router:external'] = self.external
+        if self.mtu:
+            out['mtu'] = self.mtu
         return {'network': out}
 
 
@@ -175,14 +184,17 @@ class SubnetConfig(object):
                              through authorization policies (optional)
         :param start: The start address for the allocation pools (optional)
         :param end: The end address for the allocation pools (optional)
-        :param gateway_ip: The gateway IP address (optional)
+        :param gateway_ip: The gateway IP address (optional). When not
+                           configured, the IP address will be automatically
+                           assigned; when 'none', no gateway address will be
+                           assigned, else the value must be valid
         :param enable_dhcp: Set to true if DHCP is enabled and false if DHCP is
                             disabled (optional)
         :param dns_nameservers: A list of DNS name servers for the subnet.
                                 Specify each name server as an IP address
                                 and separate multiple entries with a space.
                                 For example [8.8.8.7 8.8.8.8]
-                                (default '8.8.8.8')
+                                (default [])
         :param host_routes: A list of host route dictionaries for the subnet.
                             For example:
                                 "host_routes":[
@@ -221,10 +233,7 @@ class SubnetConfig(object):
         if 'dns_nameservers' in kwargs:
             self.dns_nameservers = kwargs.get('dns_nameservers')
         else:
-            if self.ip_version == 4:
-                self.dns_nameservers = ['8.8.8.8']
-            else:
-                self.dns_nameservers = list()
+            self.dns_nameservers = list()
 
         self.host_routes = kwargs.get('host_routes')
         self.destination = kwargs.get('destination')
@@ -255,9 +264,13 @@ class SubnetConfig(object):
         if self.name:
             out['name'] = self.name
         if self.project_name:
-            keystone = keystone_utils.keystone_client(os_creds)
-            project = keystone_utils.get_project(
-                keystone=keystone, project_name=self.project_name)
+            session = keystone_utils.keystone_session(os_creds)
+            keystone = keystone_utils.keystone_client(os_creds, session)
+            try:
+                project = keystone_utils.get_project(
+                    keystone=keystone, project_name=self.project_name)
+            finally:
+                keystone_utils.close_session(session)
             project_id = None
             if project:
                 project_id = project.id
@@ -270,7 +283,10 @@ class SubnetConfig(object):
         if self.start and self.end:
             out['allocation_pools'] = [{'start': self.start, 'end': self.end}]
         if self.gateway_ip:
-            out['gateway_ip'] = self.gateway_ip
+            if self.gateway_ip == 'none':
+                out['gateway_ip'] = None
+            else:
+                out['gateway_ip'] = self.gateway_ip
         if self.enable_dhcp is not None:
             out['enable_dhcp'] = self.enable_dhcp
         if self.dns_nameservers and len(self.dns_nameservers) > 0:
@@ -401,22 +417,23 @@ class PortConfig(object):
             raise PortConfigError(
                 'The attribute network_name is required')
 
-    def __get_fixed_ips(self, neutron):
+    def __get_fixed_ips(self, neutron, network):
         """
         Sets the self.fixed_ips value
         :param neutron: the Neutron client
+        :param network: the SNAPS-OO network domain object
         :return: None
         """
-
         fixed_ips = list()
         if self.ip_addrs:
 
             for ip_addr_dict in self.ip_addrs:
                 subnet = neutron_utils.get_subnet(
-                    neutron, subnet_name=ip_addr_dict['subnet_name'])
-                if subnet and 'ip' in ip_addr_dict:
-                    fixed_ips.append({'ip_address': ip_addr_dict['ip'],
-                                      'subnet_id': subnet.id})
+                    neutron, network, subnet_name=ip_addr_dict['subnet_name'])
+                if subnet:
+                    if 'ip' in ip_addr_dict:
+                        fixed_ips.append({'ip_address': ip_addr_dict['ip'],
+                                          'subnet_id': subnet.id})
                 else:
                     raise PortConfigError(
                         'Invalid port configuration, subnet does not exist '
@@ -435,22 +452,28 @@ class PortConfig(object):
         :param os_creds: the OpenStack credentials
         :return: the dictionary object
         """
-
         out = dict()
+        session = keystone_utils.keystone_session(os_creds)
+        keystone = keystone_utils.keystone_client(os_creds, session)
 
-        project_id = None
+        project_name = os_creds.project_name
         if self.project_name:
-            keystone = keystone_utils.keystone_client(os_creds)
-            project = keystone_utils.get_project(
-                keystone=keystone, project_name=self.project_name)
-            if project:
-                project_id = project.id
+            project_name = project_name
+        try:
+            network = neutron_utils.get_network(
+                neutron, keystone, network_name=self.network_name)
+            if network and not (network.shared or network.external):
+                network = neutron_utils.get_network(
+                    neutron, keystone, network_name=self.network_name,
+                    project_name=project_name)
+        finally:
+            if session:
+                keystone_utils.close_session(session)
 
-        network = neutron_utils.get_network(
-            neutron, network_name=self.network_name, project_id=project_id)
         if not network:
             raise PortConfigError(
-                'Cannot locate network with name - ' + self.network_name)
+                'Cannot locate network with name - ' + self.network_name
+                + ' in project - ' + str(project_name))
 
         out['network_id'] = network.id
 
@@ -459,6 +482,11 @@ class PortConfig(object):
         if self.name:
             out['name'] = self.name
         if self.project_name:
+            project = keystone_utils.get_project(
+                keystone=keystone, project_name=self.project_name)
+            project_id = None
+            if project:
+                project_id = project.id
             if project_id:
                 out['tenant_id'] = project_id
             else:
@@ -468,7 +496,7 @@ class PortConfig(object):
         if self.mac_address:
             out['mac_address'] = self.mac_address
 
-        fixed_ips = self.__get_fixed_ips(neutron)
+        fixed_ips = self.__get_fixed_ips(neutron, network)
         if fixed_ips and len(fixed_ips) > 0:
             out['fixed_ips'] = fixed_ips
 
@@ -476,7 +504,8 @@ class PortConfig(object):
             sec_grp_ids = list()
             for sec_grp_name in self.security_groups:
                 sec_grp = neutron_utils.get_security_group(
-                    neutron, sec_grp_name=sec_grp_name)
+                    neutron, keystone, sec_grp_name=sec_grp_name,
+                    project_name=self.project_name)
                 if sec_grp:
                     sec_grp_ids.append(sec_grp.id)
             out['security_groups'] = sec_grp_ids
index 6790609..d6d175f 100644 (file)
@@ -32,11 +32,12 @@ class ProjectConfig(object):
         :param users: list of users to associate project to (optional)
         :param enabled: denotes whether or not the project is enabled
                         (default True)
+        :param quotas: quota values to override (optional)
         """
 
         self.name = kwargs.get('name')
         self.domain_name = kwargs.get(
-            'domain', kwargs.get('domain', 'Default'))
+            'domain_name', kwargs.get('domain', 'Default'))
 
         self.description = kwargs.get('description')
         if kwargs.get('enabled') is not None:
@@ -46,6 +47,8 @@ class ProjectConfig(object):
 
         self.users = kwargs.get('users', list())
 
+        self.quotas = kwargs.get('quotas')
+
         if not self.name:
             raise ProjectConfigError(
                 "The attribute name is required for ProjectConfig")
index 72164f2..2a0b6a4 100644 (file)
@@ -33,7 +33,11 @@ class RouterConfig(object):
         :param admin_state_up: The administrative status of the router.
                                True = up / False = down (default True)
         :param internal_subnets: List of subnet names to which to connect this
-                                 router for Floating IP purposes
+                                 router (this way is deprecated).
+                                 *** NEW WAY ***
+                                 List of dict where the key is 'subnet' that
+                                 contains members with the following keys:
+                                 project_name, network_name, and subnet_name
         :param port_settings: List of PortConfig objects
         :return:
         """
@@ -45,6 +49,19 @@ class RouterConfig(object):
         self.enable_snat = kwargs.get('enable_snat')
         if kwargs.get('internal_subnets'):
             self.internal_subnets = kwargs['internal_subnets']
+            if isinstance(self.internal_subnets, dict):
+                if 'subnet' not in self.internal_subnets:
+                    raise RouterConfigError(
+                        'subnet is a required key to internal_subnets')
+                if 'project_name' not in self.internal_subnets['subnet']:
+                    raise RouterConfigError(
+                        'subnet.project is a required key to subnet')
+                if 'network_name' not in self.internal_subnets['subnet']:
+                    raise RouterConfigError(
+                        'network_name is a required key to subnet')
+                if 'subnet_name' not in self.internal_subnets['subnet']:
+                    raise RouterConfigError(
+                        'subnet_name is a required key to subnet')
         else:
             self.internal_subnets = list()
 
@@ -70,39 +87,42 @@ class RouterConfig(object):
         TODO - expand automated testing to exercise all parameters
         :param neutron: The neutron client to retrieve external network
                         information if necessary
-        :param os_creds: The OpenStack credentials
+        :param os_creds: The OpenStack credentials for retrieving the keystone
+                         client for looking up the project ID when the
+                         self.project_name is not None
         :return: the dictionary object
         """
         out = dict()
         ext_gw = dict()
 
-        if self.name:
-            out['name'] = self.name
-        if self.project_name:
-            keystone = keystone_utils.keystone_client(os_creds)
-            project = keystone_utils.get_project(
-                keystone=keystone, project_name=self.project_name)
-            project_id = None
-            if project:
-                project_id = project.id
-            if project_id:
-                out['tenant_id'] = project_id
-            else:
-                raise RouterConfigError(
-                    'Could not find project ID for project named - ' +
-                    self.project_name)
-        if self.admin_state_up is not None:
-            out['admin_state_up'] = self.admin_state_up
-        if self.external_gateway:
-            ext_net = neutron_utils.get_network(
-                neutron, network_name=self.external_gateway)
-            if ext_net:
-                ext_gw['network_id'] = ext_net.id
-                out['external_gateway_info'] = ext_gw
-            else:
-                raise RouterConfigError(
-                    'Could not find the external network named - ' +
-                    self.external_gateway)
+        session = keystone_utils.keystone_session(os_creds)
+        keystone = keystone_utils.keystone_client(os_creds, session)
+        try:
+            if self.name:
+                out['name'] = self.name
+            if self.project_name:
+                project = keystone_utils.get_project(
+                    keystone=keystone, project_name=self.project_name)
+                if project:
+                        out['tenant_id'] = project.id
+                else:
+                    raise RouterConfigError(
+                        'Could not find project ID for project named - ' +
+                        self.project_name)
+            if self.admin_state_up is not None:
+                out['admin_state_up'] = self.admin_state_up
+            if self.external_gateway:
+                ext_net = neutron_utils.get_network(
+                    neutron, keystone, network_name=self.external_gateway)
+                if ext_net:
+                    ext_gw['network_id'] = ext_net.id
+                    out['external_gateway_info'] = ext_gw
+                else:
+                    raise RouterConfigError(
+                        'Could not find the external network named - ' +
+                        self.external_gateway)
+        finally:
+            keystone_utils.close_session(session)
 
         return {'router': out}
 
index 32a1e95..9e485c3 100644 (file)
@@ -54,7 +54,7 @@ class SecurityGroupConfig(object):
             raise SecurityGroupConfigError('The attribute name is required')
 
         for rule_setting in self.rule_settings:
-            if rule_setting.sec_grp_name is not self.name:
+            if rule_setting.sec_grp_name != self.name:
                 raise SecurityGroupConfigError(
                     'Rule settings must correspond with the name of this '
                     'security group')
@@ -204,13 +204,14 @@ class SecurityGroupRuleConfig(object):
             raise SecurityGroupRuleConfigError(
                 'direction and sec_grp_name are required')
 
-    def dict_for_neutron(self, neutron):
+    def dict_for_neutron(self, neutron, keystone, project_name):
         """
         Returns a dictionary object representing this object.
         This is meant to be converted into JSON designed for use by the Neutron
         API
-
         :param neutron: the neutron client for performing lookups
+        :param keystone: the keystone client for performing lookups
+        :param project_name: the name of the project associated with the group
         :return: the dictionary object
         """
         out = dict()
@@ -229,7 +230,8 @@ class SecurityGroupRuleConfig(object):
             out['protocol'] = self.protocol.value
         if self.sec_grp_name:
             sec_grp = neutron_utils.get_security_group(
-                neutron, sec_grp_name=self.sec_grp_name)
+                neutron, keystone, sec_grp_name=self.sec_grp_name,
+                project_name=project_name)
             if sec_grp:
                 out['security_group_id'] = sec_grp.id
             else:
@@ -312,12 +314,15 @@ def map_direction(direction):
     :return: the Direction enum object
     :raise: Exception if value is invalid
     """
-    if not direction:
+    if not direction or 'None' == str(direction):
         return None
-    if isinstance(direction, Direction):
-        return direction
-    elif (isinstance(direction, str) or isinstance(direction, unicode)
-            or isinstance(direction, unicode)):
+    if isinstance(direction, enum.Enum):
+        if direction.__class__.__name__ == 'Direction':
+            return direction
+        else:
+            raise SecurityGroupRuleConfigError(
+                'Invalid class - ' + direction.__class__.__name__)
+    elif isinstance(direction, str):
         dir_str = str(direction)
         if dir_str == 'egress':
             return Direction.egress
@@ -327,7 +332,7 @@ def map_direction(direction):
             raise SecurityGroupRuleConfigError(
                 'Invalid Direction - ' + dir_str)
     else:
-        return map_direction(direction.value)
+        return map_direction(str(direction))
 
 
 def map_protocol(protocol):
@@ -340,19 +345,22 @@ def map_protocol(protocol):
     """
     if not protocol:
         return None
-    elif isinstance(protocol, Protocol):
-        return protocol
-    elif (isinstance(protocol, str) or isinstance(protocol, unicode)
-            or isinstance(protocol, int)):
+    elif isinstance(protocol, enum.Enum):
+        if protocol.__class__.__name__ == 'Protocol':
+            return protocol
+        else:
+            raise SecurityGroupRuleConfigError(
+                'Invalid class - ' + protocol.__class__.__name__)
+    elif isinstance(protocol, str) or isinstance(protocol, int):
         for proto_enum in Protocol:
             if proto_enum.name == protocol or proto_enum.value == protocol:
                 if proto_enum == Protocol.any:
                     return Protocol.null
                 return proto_enum
         raise SecurityGroupRuleConfigError(
-            'Invalid Protocol - ' + protocol)
+            'Invalid Protocol - ' + str(protocol))
     else:
-        return map_protocol(protocol.value)
+        return map_protocol(str(protocol))
 
 
 def map_ethertype(ethertype):
@@ -363,12 +371,15 @@ def map_ethertype(ethertype):
     :return: the Ethertype enum object
     :raise: Exception if value is invalid
     """
-    if not ethertype:
+    if not ethertype or 'None' == str(ethertype):
         return None
-    elif isinstance(ethertype, Ethertype):
-        return ethertype
-    elif (isinstance(ethertype, str) or isinstance(ethertype, unicode)
-            or isinstance(ethertype, int)):
+    elif isinstance(ethertype, enum.Enum):
+        if ethertype.__class__.__name__ == 'Ethertype':
+            return ethertype
+        else:
+            raise SecurityGroupRuleConfigError(
+                'Invalid class - ' + ethertype.__class__.__name__)
+    elif isinstance(ethertype, str) or isinstance(ethertype, int):
         eth_str = str(ethertype)
         if eth_str == 'IPv6' or eth_str == '6':
             return Ethertype.IPv6
@@ -378,7 +389,7 @@ def map_ethertype(ethertype):
             raise SecurityGroupRuleConfigError(
                 'Invalid Ethertype - ' + eth_str)
     else:
-        return map_ethertype(ethertype.value)
+        return map_ethertype(str(ethertype))
 
 
 class SecurityGroupRuleConfigError(Exception):
index 4d5db29..3fc820e 100644 (file)
 
 STACK_DELETE_TIMEOUT = 1200
 STACK_COMPLETE_TIMEOUT = 1200
+STACK_UPDATE_TIMEOUT = 1200
 POLL_INTERVAL = 3
 STATUS_CREATE_FAILED = 'CREATE_FAILED'
 STATUS_CREATE_COMPLETE = 'CREATE_COMPLETE'
+STATUS_UPDATE_FAILED = 'UPDATE_FAILED'
+STATUS_UPDATE_COMPLETE = 'UPDATE_COMPLETE'
 STATUS_DELETE_COMPLETE = 'DELETE_COMPLETE'
 STATUS_DELETE_FAILED = 'DELETE_FAILED'
 
index 43b69c7..cbc71af 100644 (file)
@@ -15,7 +15,7 @@
 import unittest
 
 from snaps.config.network import (
-    NetworkConfigError, NetworkConfig,  SubnetConfig, SubnetConfigError,
+    NetworkConfigError, NetworkConfig, SubnetConfig, SubnetConfigError,
     IPv6Mode, PortConfig, PortConfigError)
 
 
@@ -42,6 +42,7 @@ class NetworkConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.network_type)
         self.assertIsNone(settings.segmentation_id)
         self.assertEqual(0, len(settings.subnet_settings))
+        self.assertIsNone(settings.mtu)
 
     def test_config_with_name_only(self):
         settings = NetworkConfig(**{'name': 'foo'})
@@ -53,13 +54,14 @@ class NetworkConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.network_type)
         self.assertIsNone(settings.segmentation_id)
         self.assertEqual(0, len(settings.subnet_settings))
+        self.assertIsNone(settings.mtu)
 
     def test_all(self):
         sub_settings = SubnetConfig(name='foo-subnet', cidr='10.0.0.0/24')
         settings = NetworkConfig(
             name='foo', admin_state_up=False, shared=True, project_name='bar',
             external=True, network_type='vlan', physical_network='phy',
-            segmentation_id=2366, subnet_settings=[sub_settings])
+            segmentation_id=2366, subnet_settings=[sub_settings], mtu=999)
         self.assertEqual('foo', settings.name)
         self.assertFalse(settings.admin_state_up)
         self.assertTrue(settings.shared)
@@ -70,6 +72,7 @@ class NetworkConfigUnitTests(unittest.TestCase):
         self.assertEqual(2366, settings.segmentation_id)
         self.assertEqual(1, len(settings.subnet_settings))
         self.assertEqual('foo-subnet', settings.subnet_settings[0].name)
+        self.assertEqual(999, settings.mtu)
 
     def test_config_all(self):
         settings = NetworkConfig(
@@ -79,7 +82,8 @@ class NetworkConfigUnitTests(unittest.TestCase):
                'segmentation_id': 2366,
                'subnets':
                    [{'subnet': {'name': 'foo-subnet',
-                                'cidr': '10.0.0.0/24'}}]})
+                                'cidr': '10.0.0.0/24'}}],
+               'mtu': 999})
         self.assertEqual('foo', settings.name)
         self.assertFalse(settings.admin_state_up)
         self.assertTrue(settings.shared)
@@ -90,6 +94,7 @@ class NetworkConfigUnitTests(unittest.TestCase):
         self.assertEqual(2366, settings.segmentation_id)
         self.assertEqual(1, len(settings.subnet_settings))
         self.assertEqual('foo-subnet', settings.subnet_settings[0].name)
+        self.assertEqual(999, settings.mtu)
 
 
 class SubnetConfigUnitTests(unittest.TestCase):
@@ -122,8 +127,7 @@ class SubnetConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.start)
         self.assertIsNone(settings.end)
         self.assertIsNone(settings.enable_dhcp)
-        self.assertEqual(1, len(settings.dns_nameservers))
-        self.assertEqual('8.8.8.8', settings.dns_nameservers[0])
+        self.assertEqual(0, len(settings.dns_nameservers))
         self.assertIsNone(settings.host_routes)
         self.assertIsNone(settings.destination)
         self.assertIsNone(settings.nexthop)
@@ -140,8 +144,7 @@ class SubnetConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.end)
         self.assertIsNone(settings.gateway_ip)
         self.assertIsNone(settings.enable_dhcp)
-        self.assertEqual(1, len(settings.dns_nameservers))
-        self.assertEqual('8.8.8.8', settings.dns_nameservers[0])
+        self.assertEqual(0, len(settings.dns_nameservers))
         self.assertIsNone(settings.host_routes)
         self.assertIsNone(settings.destination)
         self.assertIsNone(settings.nexthop)
index 0470d83..99de4a9 100644 (file)
@@ -37,6 +37,7 @@ class ProjectConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.description)
         self.assertTrue(settings.enabled)
         self.assertEqual(list(), settings.users)
+        self.assertIsNone(settings.quotas)
 
     def test_config_with_name_only(self):
         settings = ProjectConfig(**{'name': 'foo'})
@@ -45,25 +46,52 @@ class ProjectConfigUnitTests(unittest.TestCase):
         self.assertIsNone(settings.description)
         self.assertTrue(settings.enabled)
         self.assertEqual(list(), settings.users)
+        self.assertIsNone(settings.quotas)
 
     def test_all(self):
         users = ['test1', 'test2']
+        quotas = {
+            'cores': 4, 'instances': 5, 'injected_files': 6,
+            'injected_file_content_bytes': 60000, 'ram': 70000, 'fixed_ips': 7,
+            'key_pairs': 8}
         settings = ProjectConfig(
             name='foo', domain='bar', description='foobar', enabled=False,
-            users=users)
+            users=users, quotas=quotas)
         self.assertEqual('foo', settings.name)
         self.assertEqual('bar', settings.domain_name)
         self.assertEqual('foobar', settings.description)
         self.assertFalse(settings.enabled)
         self.assertEqual(users, settings.users)
+        self.assertIsNotNone(settings.quotas)
+        self.assertEquals(4, settings.quotas.get('cores'))
+        self.assertEquals(5, settings.quotas.get('instances'))
+        self.assertEquals(6, settings.quotas.get('injected_files'))
+        self.assertEquals(
+            60000, settings.quotas.get('injected_file_content_bytes'))
+        self.assertEquals(70000, settings.quotas.get('ram'))
+        self.assertEquals(7, settings.quotas.get('fixed_ips'))
+        self.assertEquals(8, settings.quotas.get('key_pairs'))
 
     def test_config_all(self):
         users = ['test1', 'test2']
         settings = ProjectConfig(
             **{'name': 'foo', 'domain': 'bar', 'description': 'foobar',
-               'enabled': False, 'users': users})
+               'enabled': False, 'users': users,
+               'quotas': {
+                   'cores': 4, 'instances': 5, 'injected_files': 6,
+                   'injected_file_content_bytes': 60000, 'ram': 70000,
+                   'fixed_ips': 7, 'key_pairs': 8}})
         self.assertEqual('foo', settings.name)
         self.assertEqual('bar', settings.domain_name)
         self.assertEqual('foobar', settings.description)
         self.assertFalse(settings.enabled)
         self.assertEqual(users, settings.users)
+        self.assertIsNotNone(settings.quotas)
+        self.assertEquals(4, settings.quotas.get('cores'))
+        self.assertEquals(5, settings.quotas.get('instances'))
+        self.assertEquals(6, settings.quotas.get('injected_files'))
+        self.assertEquals(
+            60000, settings.quotas.get('injected_file_content_bytes'))
+        self.assertEquals(70000, settings.quotas.get('ram'))
+        self.assertEquals(7, settings.quotas.get('fixed_ips'))
+        self.assertEquals(8, settings.quotas.get('key_pairs'))
index 2c8f91f..1397f23 100644 (file)
@@ -31,6 +31,25 @@ class RouterConfigUnitTests(unittest.TestCase):
         with self.assertRaises(RouterConfigError):
             RouterConfig(**dict())
 
+    def test_bad_internal_subnets_bad_key(self):
+        with self.assertRaises(RouterConfigError):
+            RouterConfig(name='foo', internal_subnets={'foo': 'bar'})
+
+    def test_bad_internal_subnets_no_project(self):
+        with self.assertRaises(RouterConfigError):
+            RouterConfig(name='foo', internal_subnets={
+                'subnet': {'subnet_name': 'bar', 'network_name': 'foo'}})
+
+    def test_bad_internal_subnets_no_network(self):
+        with self.assertRaises(RouterConfigError):
+            RouterConfig(name='foo', internal_subnets={
+                'subnet': {'subnet_name': 'bar', 'project_name': 'foo'}})
+
+    def test_bad_internal_subnets_no_subnet(self):
+        with self.assertRaises(RouterConfigError):
+            RouterConfig(name='foo', internal_subnets={
+                'subnet': {'project_name': 'bar', 'network_name': 'foo'}})
+
     def test_name_only(self):
         settings = RouterConfig(name='foo')
         self.assertEqual('foo', settings.name)
@@ -59,7 +78,7 @@ class RouterConfigUnitTests(unittest.TestCase):
         self.assertTrue(isinstance(settings.port_settings, list))
         self.assertEqual(0, len(settings.port_settings))
 
-    def test_all(self):
+    def test_all_internal_subnets_str(self):
         port_settings = PortConfig(name='foo', network_name='bar')
         settings = RouterConfig(
             name='foo', project_name='bar', external_gateway='foo_gateway',
@@ -76,11 +95,36 @@ class RouterConfigUnitTests(unittest.TestCase):
         self.assertEqual(['10.0.0.1/24'], settings.internal_subnets)
         self.assertEqual([port_settings], settings.port_settings)
 
-    def test_config_all(self):
+    def test_all_internal_subnets_dict(self):
+        port_settings = PortConfig(name='foo', network_name='bar')
+        int_subs = {'subnet': {
+            'project_name': 'proj_a', 'network_name': 'net_name',
+            'subnet_name': 'sub_name'}}
+        settings = RouterConfig(
+            name='foo', project_name='bar', external_gateway='foo_gateway',
+            admin_state_up=True, enable_snat=False,
+            internal_subnets=int_subs,
+            interfaces=[port_settings])
+        self.assertEqual('foo', settings.name)
+        self.assertEqual('bar', settings.project_name)
+        self.assertEqual('foo_gateway', settings.external_gateway)
+        self.assertTrue(settings.admin_state_up)
+        self.assertFalse(settings.enable_snat)
+        self.assertIsNotNone(settings.internal_subnets)
+        self.assertTrue(isinstance(settings.internal_subnets, dict))
+        self.assertEqual(1, len(settings.internal_subnets))
+        self.assertEqual(int_subs, settings.internal_subnets)
+        self.assertEqual([port_settings], settings.port_settings)
+
+    def test_config_all_internal_subnets_str(self):
+        int_subs = {'subnet': {
+            'project_name': 'proj_a', 'network_name': 'net_name',
+            'subnet_name': 'sub_name'}}
         settings = RouterConfig(
             **{'name': 'foo', 'project_name': 'bar',
                'external_gateway': 'foo_gateway', 'admin_state_up': True,
-               'enable_snat': False, 'internal_subnets': ['10.0.0.1/24'],
+               'enable_snat': False,
+               'internal_subnets': int_subs,
                'interfaces':
                    [{'port': {'name': 'foo-port',
                               'network_name': 'bar-net'}}]})
@@ -90,9 +134,9 @@ class RouterConfigUnitTests(unittest.TestCase):
         self.assertTrue(settings.admin_state_up)
         self.assertFalse(settings.enable_snat)
         self.assertIsNotNone(settings.internal_subnets)
-        self.assertTrue(isinstance(settings.internal_subnets, list))
+        self.assertTrue(isinstance(settings.internal_subnets, dict))
         self.assertEqual(1, len(settings.internal_subnets))
-        self.assertEqual(['10.0.0.1/24'], settings.internal_subnets)
+        self.assertEqual(int_subs, settings.internal_subnets)
         self.assertEqual([PortConfig(**{'name': 'foo-port',
                                         'network_name': 'bar-net'})],
                          settings.port_settings)
index b4b54bd..21adffa 100644 (file)
@@ -33,6 +33,7 @@ class VolumeConfigUnitTests(unittest.TestCase):
     def test_name_only(self):
         settings = VolumeConfig(name='foo')
         self.assertEqual('foo', settings.name)
+        self.assertIsNone(settings.project_name)
         self.assertIsNone(settings.description)
         self.assertEquals(1, settings.size)
         self.assertIsNone(settings.image_name)
@@ -43,6 +44,7 @@ class VolumeConfigUnitTests(unittest.TestCase):
     def test_config_with_name_only(self):
         settings = VolumeConfig(**{'name': 'foo'})
         self.assertEqual('foo', settings.name)
+        self.assertIsNone(settings.project_name)
         self.assertIsNone(settings.description)
         self.assertEquals(1, settings.size)
         self.assertIsNone(settings.image_name)
@@ -52,10 +54,12 @@ class VolumeConfigUnitTests(unittest.TestCase):
 
     def test_all_strings(self):
         settings = VolumeConfig(
-            name='foo', description='desc', size='2', image_name='image',
-            type_name='type', availability_zone='zone1', multi_attach='true')
+            name='foo', project_name='proj-foo', description='desc', size='2',
+            image_name='image', type_name='type', availability_zone='zone1',
+            multi_attach='true')
 
         self.assertEqual('foo', settings.name)
+        self.assertEqual('proj-foo', settings.project_name)
         self.assertEqual('desc', settings.description)
         self.assertEqual(2, settings.size)
         self.assertEqual('image', settings.image_name)
@@ -65,10 +69,12 @@ class VolumeConfigUnitTests(unittest.TestCase):
 
     def test_all_correct_type(self):
         settings = VolumeConfig(
-            name='foo', description='desc', size=2, image_name='image',
-            type_name='bar', availability_zone='zone1', multi_attach=True)
+            name='foo', project_name='proj-foo', description='desc', size=2,
+            image_name='image', type_name='bar', availability_zone='zone1',
+            multi_attach=True)
 
         self.assertEqual('foo', settings.name)
+        self.assertEqual('proj-foo', settings.project_name)
         self.assertEqual('desc', settings.description)
         self.assertEqual(2, settings.size)
         self.assertEqual('image', settings.image_name)
@@ -78,11 +84,13 @@ class VolumeConfigUnitTests(unittest.TestCase):
 
     def test_config_all(self):
         settings = VolumeConfig(
-            **{'name': 'foo', 'description': 'desc', 'size': '2',
+            **{'name': 'foo', 'project_name': 'proj-foo',
+               'description': 'desc', 'size': '2',
                'image_name': 'foo', 'type_name': 'bar',
                'availability_zone': 'zone1', 'multi_attach': 'true'})
 
         self.assertEqual('foo', settings.name)
+        self.assertEqual('proj-foo', settings.project_name)
         self.assertEqual('desc', settings.description)
         self.assertEqual(2, settings.size)
         self.assertEqual('foo', settings.image_name)
index a31e8f5..0b4b73e 100644 (file)
@@ -20,6 +20,9 @@ class VolumeConfig(object):
         """
         Constructor
         :param name: the volume's name (required)
+        :param project_name: the name of the project to associate (optional)
+            note: due to a bug in the Cinder API, this functionality will not
+            work. see https://bugs.launchpad.net/cinder/+bug/1641982
         :param description: the volume's name (optional)
         :param size: the volume's size in GB (default 1)
         :param image_name: when a glance image is used for the image source
@@ -32,6 +35,7 @@ class VolumeConfig(object):
         """
 
         self.name = kwargs.get('name')
+        self.project_name = kwargs.get('project_name')
         self.description = kwargs.get('description')
         self.size = int(kwargs.get('size', 1))
         self.image_name = kwargs.get('image_name')
index 2d02966..3d5e4af 100644 (file)
@@ -24,6 +24,7 @@ class Network:
         Constructor
         :param name: the network's name
         :param id: the network's ID
+        :param project_id: the associated project ID
         :param admin_state_up: T/F - network is up when True
         :param shared: T/F - network can be shared amongst other project's
         :param external: T/F - network is deemed to be external
@@ -32,19 +33,22 @@ class Network:
         """
         self.name = kwargs.get('name')
         self.id = kwargs.get('id')
+        self.project_id = kwargs.get('project_id')
         self.admin_state_up = kwargs.get('admin_state_up')
         self.shared = kwargs.get('shared')
         self.external = kwargs.get('router:external', kwargs.get('external'))
         self.type = kwargs.get('provider:network_type', kwargs.get('type'))
         self.subnets = kwargs.get('subnets', list())
+        self.mtu = kwargs.get('mtu')
 
     def __eq__(self, other):
         return (self.name == other.name and self.id == other.id and
+                self.project_id == other.project_id and
                 self.admin_state_up == other.admin_state_up and
                 self.shared == other.shared and
                 self.external == other.external and
-                self.type == other.type and
-                self.subnets == other.subnets)
+                self.subnets == other.subnets and
+                self.mtu == other.mtu)
 
 
 class Subnet:
@@ -57,6 +61,7 @@ class Subnet:
         Constructor
         :param name: the network's name
         :param id: the subnet's ID
+        :param project_id: the associated project ID
         :param network_id: the network's ID
         :param cidr: the CIDR
         :param ip_version: the IP version
@@ -71,6 +76,7 @@ class Subnet:
         """
         self.name = kwargs.get('name')
         self.id = kwargs.get('id')
+        self.project_id = kwargs.get('project_id')
         self.network_id = kwargs.get('network_id')
         self.cidr = kwargs.get('cidr')
         self.ip_version = kwargs.get('ip_version')
@@ -95,6 +101,7 @@ class Subnet:
     def __eq__(self, other):
         return (self.name == other.name and
                 self.id == other.id and
+                self.project_id == other.project_id and
                 self.network_id == other.network_id and
                 self.cidr == other.cidr and
                 self.ip_version == other.ip_version and
@@ -181,8 +188,7 @@ class Router:
         self.port_subnets = kwargs.get('port_subnets')
 
         if (kwargs.get('external_gateway_info') and
-                isinstance(kwargs.get('external_gateway_info'), dict) and
-                kwargs.get('external_gateway_info').get('external_fixed_ips')):
+                isinstance(kwargs.get('external_gateway_info'), dict)):
             gateway_info = kwargs.get('external_gateway_info')
 
             self.external_network_id = gateway_info.get('network_id')
index 080ab17..2c593d3 100644 (file)
@@ -19,14 +19,22 @@ class Stack:
     SNAPS domain object for Heat Stacks. Should contain attributes that
     are shared amongst cloud providers
     """
-    def __init__(self, name, stack_id):
+    def __init__(self, name, stack_id, stack_project_id,
+                 status, status_reason):
         """
         Constructor
         :param name: the stack's name
         :param stack_id: the stack's stack_id
+        :param stack_project_id: the project ID that was spawned from this
+                                 deployment
+        :param status: the stack's last known status code
+        :param status_reason: the stack's last known explanation of the status
         """
         self.name = name
         self.id = stack_id
+        self.stack_project_id = stack_project_id
+        self.status = status
+        self.status_reason = status_reason
 
     def __eq__(self, other):
         return (self.name == other.name and
index 3003326..2c4c841 100644 (file)
@@ -26,28 +26,34 @@ class NetworkObjectTests(unittest.TestCase):
 
     def test_construction_kwargs_1(self):
         subnet = Subnet(
-            **{'name': 'foo', 'id': 'bar', 'network_id': 'foo-bar'})
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'network_id': 'foo-bar'})
         network = Network(
-            **{'name': 'foo', 'id': 'bar', 'provider:network_type': 'flat',
-               'admin_state_up': False, 'shared': True,
-               'router:external': False, 'subnets': [subnet]})
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'provider:network_type': 'flat', 'admin_state_up': False,
+               'shared': True, 'router:external': False, 'subnets': [subnet],
+               'mtu': 999})
         self.assertEqual('foo', network.name)
         self.assertEqual('bar', network.id)
+        self.assertEqual('proj1', network.project_id)
         self.assertEqual('flat', network.type)
         self.assertFalse(network.admin_state_up)
         self.assertFalse(network.external)
         self.assertTrue(network.shared)
         self.assertEqual([subnet], network.subnets)
+        self.assertEqual(999, network.mtu)
 
     def test_construction_kwargs_2(self):
         subnet = Subnet(
-            **{'name': 'foo', 'id': 'bar', 'network_id': 'foo-bar'})
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'network_id': 'foo-bar'})
         network = Network(
-            **{'name': 'foo', 'id': 'bar', 'type': 'flat',
-               'admin_state_up': False, 'shared': True, 'external': False,
-               'subnets': [subnet]})
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'type': 'flat', 'admin_state_up': False, 'shared': True,
+               'external': False, 'subnets': [subnet]})
         self.assertEqual('foo', network.name)
         self.assertEqual('bar', network.id)
+        self.assertEqual('proj1', network.project_id)
         self.assertEqual('flat', network.type)
         self.assertFalse(network.admin_state_up)
         self.assertFalse(network.external)
@@ -56,12 +62,15 @@ class NetworkObjectTests(unittest.TestCase):
 
     def test_construction_named(self):
         subnet = Subnet(
-            **{'name': 'foo', 'id': 'bar', 'network_id': 'foo-bar'})
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'network_id': 'foo-bar'})
         network = Network(
-            name='foo', id='bar', type='flat', admin_state_up=False,
-            shared=True, external=False, subnets=[subnet])
+            name='foo', id='bar', project_id='proj1', type='flat',
+            admin_state_up=False, shared=True, external=False,
+            subnets=[subnet])
         self.assertEqual('foo', network.name)
         self.assertEqual('bar', network.id)
+        self.assertEqual('proj1', network.project_id)
         self.assertEqual('flat', network.type)
         self.assertFalse(network.admin_state_up)
         self.assertFalse(network.external)
@@ -76,12 +85,14 @@ class SubnetObjectTests(unittest.TestCase):
 
     def test_construction_kwargs(self):
         subnet = Subnet(
-            **{'name': 'foo', 'id': 'bar', 'cidr': '10.0.0.0/24',
-               'ip_version': 4, 'gateway_ip': '10.0.0.1', 'enable_dhcp': True,
+            **{'name': 'foo', 'id': 'bar', 'project_id': 'proj1',
+               'cidr': '10.0.0.0/24', 'ip_version': 4,
+               'gateway_ip': '10.0.0.1', 'enable_dhcp': True,
                'dns_nameservers': ['8.8.8.8'], 'host_routes': list(),
                'ipv6_ra_mode': 'hello', 'ipv6_address_mode': 'world'})
         self.assertEqual('foo', subnet.name)
         self.assertEqual('bar', subnet.id)
+        self.assertEqual('proj1', subnet.project_id)
         self.assertEqual('10.0.0.0/24', subnet.cidr)
         self.assertEqual(4, subnet.ip_version)
         self.assertEqual('10.0.0.1', subnet.gateway_ip)
@@ -94,12 +105,13 @@ class SubnetObjectTests(unittest.TestCase):
 
     def test_construction_named(self):
         subnet = Subnet(
-            name='foo', id='bar', cidr='10.0.0.0/24',
+            name='foo', id='bar', project_id='proj1', cidr='10.0.0.0/24',
             ip_version=4, gateway_ip='10.0.0.1', enable_dhcp=True,
             dns_nameservers=['8.8.8.8'], host_routes=list(),
             ipv6_ra_mode='hello', ipv6_address_mode='world')
         self.assertEqual('foo', subnet.name)
         self.assertEqual('bar', subnet.id)
+        self.assertEqual('proj1', subnet.project_id)
         self.assertEqual('10.0.0.0/24', subnet.cidr)
         self.assertEqual(4, subnet.ip_version)
         self.assertEqual('10.0.0.1', subnet.gateway_ip)
index 21e31d2..2ad690a 100644 (file)
@@ -23,14 +23,23 @@ class StackDomainObjectTests(unittest.TestCase):
     """
 
     def test_construction_positional(self):
-        stack = Stack('name', 'id')
+        stack = Stack(
+            'name', 'id', 'stack_proj_id', 'fine', 'good')
         self.assertEqual('name', stack.name)
         self.assertEqual('id', stack.id)
+        self.assertEqual('stack_proj_id', stack.stack_project_id)
+        self.assertEqual('fine', stack.status)
+        self.assertEqual('good', stack.status_reason)
 
     def test_construction_named(self):
-        stack = Stack(stack_id='id', name='name')
+        stack = Stack(
+            stack_id='id', name='name', stack_project_id='stack_proj_id',
+            status='fine', status_reason='good')
         self.assertEqual('name', stack.name)
         self.assertEqual('id', stack.id)
+        self.assertEqual('stack_proj_id', stack.stack_project_id)
+        self.assertEqual('fine', stack.status)
+        self.assertEqual('good', stack.status_reason)
 
 
 class ResourceDomainObjectTests(unittest.TestCase):
index ad7a9ce..c90837d 100644 (file)
@@ -24,7 +24,7 @@ class VmInstDomainObjectTests(unittest.TestCase):
 
     def test_construction_positional(self):
         vm_inst = VmInst('name', 'id', '456', '123', list(), 'kp-name',
-                         ['foo', 'bar'], ['123', '456'])
+                         ['foo', 'bar'], ['123', '456'], 'host1', 'zone1')
         self.assertEqual('name', vm_inst.name)
         self.assertEqual('id', vm_inst.id)
         self.assertEqual('456', vm_inst.image_id)
@@ -33,9 +33,12 @@ class VmInstDomainObjectTests(unittest.TestCase):
         self.assertEqual('kp-name', vm_inst.keypair_name)
         self.assertEqual(['foo', 'bar'], vm_inst.sec_grp_names)
         self.assertEqual(['123', '456'], vm_inst.volume_ids)
+        self.assertEqual('host1', vm_inst.compute_host)
+        self.assertEqual('zone1', vm_inst.availability_zone)
 
     def test_construction_named(self):
         vm_inst = VmInst(
+            availability_zone='zone1', compute_host='host1',
             volume_ids=['123', '456'], sec_grp_names=['foo', 'bar'],
             ports=list(), inst_id='id', name='name', flavor_id='123',
             image_id='456', keypair_name='kp-name')
@@ -47,6 +50,8 @@ class VmInstDomainObjectTests(unittest.TestCase):
         self.assertEqual('kp-name', vm_inst.keypair_name)
         self.assertEqual(['foo', 'bar'], vm_inst.sec_grp_names)
         self.assertEqual(['123', '456'], vm_inst.volume_ids)
+        self.assertEqual('host1', vm_inst.compute_host)
+        self.assertEqual('zone1', vm_inst.availability_zone)
 
 
 class FloatingIpDomainObjectTests(unittest.TestCase):
index 6feadc9..09401d3 100644 (file)
@@ -24,10 +24,12 @@ class VolumeDomainObjectTests(unittest.TestCase):
     """
 
     def test_construction_positional(self):
-        volume = Volume('name1', 'id1', 'desc_val1', 2, 'type_val1',
-                        'avail_zone1', False, [{'attached_at': 'foo'}])
+        volume = Volume('name1', 'id1', 'proj_id1', 'desc_val1', 2,
+                        'type_val1', 'avail_zone1', False,
+                        [{'attached_at': 'foo'}])
         self.assertEqual('name1', volume.name)
         self.assertEqual('id1', volume.id)
+        self.assertEqual('proj_id1', volume.project_id)
         self.assertEqual('desc_val1', volume.description)
         self.assertEqual(2, volume.size)
         self.assertEqual('type_val1', volume.type)
@@ -41,9 +43,10 @@ class VolumeDomainObjectTests(unittest.TestCase):
         volume = Volume(attachments=[{'attached_at': 'foo'}],
                         multi_attach=True, availability_zone='avail_zone2',
                         vol_type='type_val2', size=3, description='desc_val2',
-                        volume_id='id2', name='name2')
+                        volume_id='id2', name='name2', project_id='proj_id1')
         self.assertEqual('name2', volume.name)
         self.assertEqual('id2', volume.id)
+        self.assertEqual('proj_id1', volume.project_id)
         self.assertEqual('desc_val2', volume.description)
         self.assertEqual(3, volume.size)
         self.assertEqual('type_val2', volume.type)
index c49b03e..f3b5381 100644 (file)
@@ -20,7 +20,8 @@ class VmInst:
     are shared amongst cloud providers
     """
     def __init__(self, name, inst_id, image_id, flavor_id, ports,
-                 keypair_name, sec_grp_names, volume_ids):
+                 keypair_name, sec_grp_names, volume_ids, compute_host,
+                 availability_zone):
         """
         Constructor
         :param name: the image's name
@@ -32,6 +33,11 @@ class VmInst:
         :param keypair_name: the name of the associated keypair
         :param sec_grp_names: list of security group names
         :param volume_ids: list of attached volume IDs
+        :param compute_host: the name of the host on which this VM is running
+                             When the user requesting this query is not part of
+                             the 'admin' role, this value will be None
+        :param availability_zone: the name of the availability zone to which
+                                  this VM has been assigned
         """
         self.name = name
         self.id = inst_id
@@ -41,6 +47,8 @@ class VmInst:
         self.keypair_name = keypair_name
         self.sec_grp_names = sec_grp_names
         self.volume_ids = volume_ids
+        self.compute_host = compute_host
+        self.availability_zone = availability_zone
 
     def __eq__(self, other):
         return (self.name == other.name and
@@ -49,7 +57,6 @@ class VmInst:
                 self.flavor_id == other.flavor_id and
                 self.ports == other.ports and
                 self.keypair_name == other.keypair_name and
-                self.sec_grp_names == other.sec_grp_names and
                 self.volume_ids == other.volume_ids)
 
 
index 0042d71..0ab2a7d 100644 (file)
@@ -19,12 +19,14 @@ class Volume:
     SNAPS domain object for Volumes. Should contain attributes that
     are shared amongst cloud providers
     """
-    def __init__(self, name, volume_id, description, size, vol_type,
-                 availability_zone, multi_attach, attachments=list()):
+    def __init__(self, name, volume_id, project_id, description, size,
+                 vol_type, availability_zone, multi_attach,
+                 attachments=list()):
         """
         Constructor
         :param name: the volume's name
         :param volume_id: the volume's id
+        :param project_id: the volume's associated project id
         :param description: the volume's description
         :param size: the volume's size in GB
         :param vol_type: the volume's type
@@ -35,6 +37,7 @@ class Volume:
         """
         self.name = name
         self.id = volume_id
+        self.project_id = project_id
         self.description = description
         self.size = size
         self.type = vol_type
@@ -43,7 +46,9 @@ class Volume:
         self.attachments = attachments
 
     def __eq__(self, other):
-        return (self.name == other.name and self.id == other.id
+        return (self.name == other.name
+                and self.id == other.id
+                and self.project_id == other.project_id
                 and self.description == other.description
                 and self.size == other.size
                 and self.type == other.type
index a421dd3..284ae15 100644 (file)
@@ -12,6 +12,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+import ssl
+
 import os
 import logging
 
@@ -168,7 +170,8 @@ def __get_url_response(url):
     proxy_handler = urllib.ProxyHandler({})
     opener = urllib.build_opener(proxy_handler)
     urllib.install_opener(opener)
-    return urllib.urlopen(url)
+    context = ssl._create_unverified_context()
+    return urllib.urlopen(url, context=context)
 
 
 def read_yaml(config_file_path):
@@ -180,7 +183,7 @@ def read_yaml(config_file_path):
     logger.debug('Attempting to load configuration file - ' + config_file_path)
     config_file = None
     try:
-        with open(config_file_path) as config_file:
+        with open(config_file_path, 'r') as config_file:
             config = yaml.safe_load(config_file)
             logger.info('Loaded configuration')
         return config
@@ -190,6 +193,20 @@ def read_yaml(config_file_path):
             config_file.close()
 
 
+def persist_dict_to_yaml(the_dict, file_name):
+    """
+    Creates a YAML file from a dict
+    :param the_dict: the dictionary to store
+    :param conf_dir: the directory used to store the config file
+    :return: the file object
+    """
+    logger.info('Persisting %s to [%s]', the_dict, file_name)
+    file_path = os.path.expanduser(file_name)
+    yaml_from_dict = yaml.dump(
+        the_dict, default_flow_style=False, default_style='')
+    return save_string_to_file(yaml_from_dict, file_path)
+
+
 def read_os_env_file(os_env_filename):
     """
     Reads the OS environment source file and returns a map of each key/value
index c4ba76d..f6c7aa2 100644 (file)
@@ -85,6 +85,8 @@ class OpenStackClusterTemplate(OpenStackMagnumObject):
 
         self.__cluster_template = None
 
+        super(self.__class__, self).clean()
+
     def get_cluster_template(self):
         """
         Returns the domain Volume object as it was populated when create() was
index 65b9059..48b3e7c 100644 (file)
@@ -87,6 +87,8 @@ class OpenStackFlavor(OpenStackComputeObject):
 
             self.__flavor = None
 
+        super(self.__class__, self).clean()
+
     def get_flavor(self):
         """
         Returns the OpenStack flavor object
index a5520e3..1a8aa12 100644 (file)
@@ -54,7 +54,10 @@ class OpenStackImage(OpenStackCloudObject):
         Loads the existing Image
         :return: The Image domain object or None
         """
-        self.__glance = glance_utils.glance_client(self._os_creds)
+        super(self.__class__, self).initialize()
+
+        self.__glance = glance_utils.glance_client(
+            self._os_creds, self._os_session)
         self.__image = glance_utils.get_image(
             self.__glance, image_settings=self.image_settings)
 
@@ -145,6 +148,11 @@ class OpenStackImage(OpenStackCloudObject):
         self.__kernel_image = None
         self.__ramdisk_image = None
 
+        if self.__glance:
+            self.__glance.http_client.session.session.close()
+
+        super(self.__class__, self).clean()
+
     def get_image(self):
         """
         Returns the domain Image object as it was populated when create() was
index cdc778f..16bd0ce 100644 (file)
@@ -19,7 +19,8 @@ from novaclient.exceptions import NotFound
 
 from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig
 from snaps.openstack.openstack_creator import OpenStackComputeObject
-from snaps.openstack.utils import glance_utils, cinder_utils, settings_utils
+from snaps.openstack.utils import (
+    glance_utils, cinder_utils, settings_utils, keystone_utils)
 from snaps.openstack.utils import neutron_utils
 from snaps.openstack.utils import nova_utils
 from snaps.openstack.utils.nova_utils import RebootType
@@ -72,7 +73,14 @@ class OpenStackVmInstance(OpenStackComputeObject):
         """
         super(self.__class__, self).initialize()
 
-        self.__neutron = neutron_utils.neutron_client(self._os_creds)
+        self.__neutron = neutron_utils.neutron_client(
+            self._os_creds, self._os_session)
+        self.__keystone = keystone_utils.keystone_client(
+            self._os_creds, self._os_session)
+        self.__cinder = cinder_utils.cinder_client(
+            self._os_creds, self._os_session)
+        self.__glance = glance_utils.glance_client(
+            self._os_creds, self._os_session)
 
         self.__ports = self.__query_ports(self.instance_settings.port_settings)
         self.__lookup_existing_vm_by_name()
@@ -88,7 +96,7 @@ class OpenStackVmInstance(OpenStackComputeObject):
         """
         self.initialize()
 
-        if len(self.__ports) == 0:
+        if len(self.__ports) != len(self.instance_settings.port_settings):
             self.__ports = self.__create_ports(
                 self.instance_settings.port_settings)
         if not self.__vm:
@@ -103,7 +111,7 @@ class OpenStackVmInstance(OpenStackComputeObject):
         within the project
         """
         server = nova_utils.get_server(
-            self._nova, self.__neutron,
+            self._nova, self.__neutron, self.__keystone,
             vm_inst_settings=self.instance_settings)
         if server:
             if server.name == self.instance_settings.name:
@@ -112,8 +120,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
                     'Found existing machine with name - %s',
                     self.instance_settings.name)
 
-                fips = neutron_utils.get_floating_ips(self.__neutron,
-                                                      self.__ports)
+                fips = neutron_utils.get_port_floating_ips(
+                    self.__neutron, self.__ports)
                 for port_id, fip in fips:
                     settings = self.instance_settings.floating_ip_settings
                     for fip_setting in settings:
@@ -132,10 +140,10 @@ class OpenStackVmInstance(OpenStackComputeObject):
                       active, error, or timeout waiting. Floating IPs will be
                       assigned after active when block=True
         """
-        glance = glance_utils.glance_client(self._os_creds)
         self.__vm = nova_utils.create_server(
-            self._nova, self.__neutron, glance, self.instance_settings,
-            self.image_settings, self.keypair_settings)
+            self._nova, self.__keystone, self.__neutron, self.__glance,
+            self.instance_settings, self.image_settings,
+            self._os_creds.project_name, self.keypair_settings)
         logger.info('Created instance with name - %s',
                     self.instance_settings.name)
 
@@ -159,20 +167,20 @@ class OpenStackVmInstance(OpenStackComputeObject):
 
         if self.instance_settings.volume_names:
             for volume_name in self.instance_settings.volume_names:
-                cinder = cinder_utils.cinder_client(self._os_creds)
                 volume = cinder_utils.get_volume(
-                    cinder, volume_name=volume_name)
+                    self.__cinder, self.__keystone, volume_name=volume_name,
+                    project_name=self._os_creds.project_name)
 
                 if volume and self.vm_active(block=True):
-                    timeout = 30
                     vm = nova_utils.attach_volume(
-                        self._nova, self.__neutron, self.__vm, volume, timeout)
+                        self._nova, self.__neutron, self.__keystone, self.__vm,
+                        volume, self._os_creds.project_name)
 
                     if vm:
                         self.__vm = vm
                     else:
-                        logger.warn('Volume [%s] not attached within timeout '
-                                    'of [%s]', volume.name, timeout)
+                        logger.warn(
+                            'Volume [%s] attachment timeout ', volume.name)
                 else:
                     logger.warn('Unable to attach volume named [%s]',
                                 volume_name)
@@ -215,7 +223,7 @@ class OpenStackVmInstance(OpenStackComputeObject):
             floating_ip_setting.router_name)
         if ext_gateway and self.vm_active(block=True):
             floating_ip = neutron_utils.create_floating_ip(
-                self.__neutron, ext_gateway, port.id)
+                self.__neutron, self.__keystone, ext_gateway, port.id)
             self.__floating_ip_dict[floating_ip_setting.name] = floating_ip
 
             logger.info(
@@ -236,7 +244,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
         :return: the external network name or None
         """
         router = neutron_utils.get_router(
-            self.__neutron, router_name=router_name)
+            self.__neutron, self.__keystone, router_name=router_name,
+            project_name=self._os_creds.project_name)
         if router and router.external_network_id:
             network = neutron_utils.get_network_by_id(
                 self.__neutron, router.external_network_id)
@@ -266,12 +275,12 @@ class OpenStackVmInstance(OpenStackComputeObject):
         if self.__vm:
             # Detach Volume
             for volume_rec in self.__vm.volume_ids:
-                cinder = cinder_utils.cinder_client(self._os_creds)
                 volume = cinder_utils.get_volume_by_id(
-                    cinder, volume_rec['id'])
+                    self.__cinder, volume_rec['id'])
                 if volume:
                     vm = nova_utils.detach_volume(
-                        self._nova, self.__neutron, self.__vm, volume, 30)
+                        self._nova, self.__neutron, self.__keystone, self.__vm,
+                        volume, self._os_creds.project_name)
                     if vm:
                         self.__vm = vm
                     else:
@@ -304,6 +313,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
                     'VM not deleted within the timeout period of %s '
                     'seconds', self.instance_settings.vm_delete_timeout)
 
+        super(self.__class__, self).clean()
+
     def __query_ports(self, port_settings):
         """
         Returns the previously configured ports or an empty list if none
@@ -316,7 +327,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
 
         for port_setting in port_settings:
             port = neutron_utils.get_port(
-                self.__neutron, port_settings=port_setting)
+                self.__neutron, self.__keystone, port_settings=port_setting,
+                project_name=self._os_creds.project_name)
             if port:
                 ports.append((port_setting.name, port))
 
@@ -334,12 +346,13 @@ class OpenStackVmInstance(OpenStackComputeObject):
 
         for port_setting in port_settings:
             port = neutron_utils.get_port(
-                self.__neutron, port_settings=port_setting)
+                self.__neutron, self.__keystone, port_settings=port_setting,
+                project_name=self._os_creds.project_name)
             if not port:
                 port = neutron_utils.create_port(
                     self.__neutron, self._os_creds, port_setting)
-                if port:
-                    ports.append((port_setting.name, port))
+            if port:
+                ports.append((port_setting.name, port))
 
         return ports
 
@@ -356,7 +369,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
         :return: Server object
         """
         return nova_utils.get_server_object_by_id(
-            self._nova, self.__neutron, self.__vm.id)
+            self._nova, self.__neutron, self.__keystone, self.__vm.id,
+            self._os_creds.project_name)
 
     def get_console_output(self):
         """
@@ -377,8 +391,10 @@ class OpenStackVmInstance(OpenStackComputeObject):
         port = self.get_port_by_name(port_name)
         if port:
             if subnet_name:
+                network = neutron_utils.get_network_by_id(
+                    self.__neutron, port.network_id)
                 subnet = neutron_utils.get_subnet(
-                    self.__neutron, subnet_name=subnet_name)
+                    self.__neutron, network, subnet_name=subnet_name)
                 if not subnet:
                     logger.warning('Cannot retrieve port IP as subnet could '
                                    'not be located with name - %s',
@@ -423,6 +439,10 @@ class OpenStackVmInstance(OpenStackComputeObject):
         Returns a dictionary of a VMs info as returned by OpenStack
         :return: a dict()
         """
+        from warnings import warn
+        warn('Do not use the returned dict() structure',
+             DeprecationWarning)
+
         return nova_utils.get_server_info(self._nova, self.__vm)
 
     def __get_first_provisioning_floating_ip(self):
@@ -504,7 +524,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
                 STATUS_ACTIVE, block, self.instance_settings.vm_boot_timeout,
                 poll_interval):
             self.__vm = nova_utils.get_server_object_by_id(
-                self._nova, self.__neutron, self.__vm.id)
+                self._nova, self.__neutron, self.__keystone, self.__vm.id,
+                self._os_creds.project_name)
             return True
         return False
 
@@ -771,24 +792,32 @@ class OpenStackVmInstance(OpenStackComputeObject):
             self._nova, self.__vm, reboot_type=reboot_type)
 
 
-def generate_creator(os_creds, vm_inst, image_config, keypair_config=None):
+def generate_creator(os_creds, vm_inst, image_config, project_name,
+                     keypair_config=None):
     """
     Initializes an OpenStackVmInstance object
     :param os_creds: the OpenStack credentials
     :param vm_inst: the SNAPS-OO VmInst domain object
     :param image_config: the associated ImageConfig object
+    :param project_name: the associated project ID
     :param keypair_config: the associated KeypairConfig object (optional)
     :return: an initialized OpenStackVmInstance object
     """
-    nova = nova_utils.nova_client(os_creds)
-    neutron = neutron_utils.neutron_client(os_creds)
-    derived_inst_config = settings_utils.create_vm_inst_config(
-        nova, neutron, vm_inst)
-
-    derived_inst_creator = OpenStackVmInstance(
-        os_creds, derived_inst_config, image_config, keypair_config)
-    derived_inst_creator.initialize()
-    return derived_inst_creator
+    session = keystone_utils.keystone_session(os_creds)
+    nova = nova_utils.nova_client(os_creds, session)
+    keystone = keystone_utils.keystone_client(os_creds, session)
+    neutron = neutron_utils.neutron_client(os_creds, session)
+
+    try:
+        derived_inst_config = settings_utils.create_vm_inst_config(
+            nova, keystone, neutron, vm_inst, project_name)
+
+        derived_inst_creator = OpenStackVmInstance(
+            os_creds, derived_inst_config, image_config, keypair_config)
+        derived_inst_creator.initialize()
+        return derived_inst_creator
+    finally:
+        keystone_utils.close_session(session)
 
 
 class VmInstanceSettings(VmInstanceConfig):
index a181a7b..b037c3f 100644 (file)
@@ -133,6 +133,8 @@ class OpenStackKeypair(OpenStackComputeObject):
                 os.remove(expanded_path)
                 logger.info('Deleted private key file [%s]', expanded_path)
 
+        super(self.__class__, self).clean()
+
     def get_keypair(self):
         """
         Returns the OpenStack keypair object
index 984eedd..13c9667 100644 (file)
@@ -53,9 +53,9 @@ class OpenStackNetwork(OpenStackNetworkObject):
 
         try:
             self.__network = neutron_utils.get_network(
-                self._neutron, network_settings=self.network_settings,
-                project_id=self.network_settings.get_project_id(
-                    self._os_creds))
+                self._neutron, self._keystone,
+                network_settings=self.network_settings,
+                project_name=self._os_creds.project_name)
         except Unauthorized as e:
             logger.warn('Unable to lookup network with name %s - %s',
                         self.network_settings.name, e)
@@ -82,12 +82,13 @@ class OpenStackNetwork(OpenStackNetworkObject):
         """
         Removes and deletes all items created in reverse order.
         """
-        if self.__network:
-            try:
-                neutron_utils.delete_network(self._neutron, self.__network)
-            except NetworkNotFoundClient:
-                pass
-            self.__network = None
+        try:
+            neutron_utils.delete_network(self._neutron, self.__network)
+        except NetworkNotFoundClient:
+            pass
+        self.__network = None
+
+        super(self.__class__, self).clean()
 
     def get_network(self):
         """
index 0349890..ed7e9cd 100644 (file)
@@ -74,6 +74,29 @@ class OpenStackProject(OpenStackIdentityObject):
                         logger.warn('Unable to associate user %s due to %s',
                                     user.name, e)
 
+            if self.project_settings.quotas:
+                quota_dict = self.project_settings.quotas
+                nova = nova_utils.nova_client(self._os_creds, self._os_session)
+                quotas = nova_utils.get_compute_quotas(nova, self.__project.id)
+                if quotas:
+                    if 'cores' in quota_dict:
+                        quotas.cores = quota_dict['cores']
+                    if 'instances' in quota_dict:
+                        quotas.instances = quota_dict['instances']
+                    if 'injected_files' in quota_dict:
+                        quotas.injected_files = quota_dict['injected_files']
+                    if 'injected_file_content_bytes' in quota_dict:
+                        quotas.injected_file_content_bytes = \
+                            quota_dict['injected_file_content_bytes']
+                    if 'ram' in quota_dict:
+                        quotas.ram = quota_dict['ram']
+                    if 'fixed_ips' in quota_dict:
+                        quotas.fixed_ips = quota_dict['fixed_ips']
+                    if 'key_pairs' in quota_dict:
+                        quotas.key_pairs = quota_dict['key_pairs']
+
+                    nova_utils.update_quotas(nova, self.__project.id, quotas)
+
         return self.__project
 
     def clean(self):
@@ -83,16 +106,20 @@ class OpenStackProject(OpenStackIdentityObject):
         """
         if self.__project:
             # Delete security group 'default' if exists
-            neutron = neutron_utils.neutron_client(self._os_creds)
-            default_sec_grp = neutron_utils.get_security_group(
-                neutron, sec_grp_name='default',
-                project_id=self.__project.id)
-            if default_sec_grp:
-                try:
-                    neutron_utils.delete_security_group(
-                        neutron, default_sec_grp)
-                except:
-                    pass
+            neutron = neutron_utils.neutron_client(
+                self._os_creds, self._os_session)
+            try:
+                default_sec_grp = neutron_utils.get_security_group(
+                    neutron, self._keystone, sec_grp_name='default',
+                    project_name=self.__project.name)
+                if default_sec_grp:
+                    try:
+                        neutron_utils.delete_security_group(
+                            neutron, default_sec_grp)
+                    except:
+                        pass
+            finally:
+                neutron.httpclient.session.session.close()
 
             # Delete Project
             try:
@@ -114,6 +141,8 @@ class OpenStackProject(OpenStackIdentityObject):
         if role:
             keystone_utils.delete_role(self._keystone, role)
 
+        super(self.__class__, self).clean()
+
     def get_project(self):
         """
         Returns the OpenStack project object populated on create()
@@ -142,32 +171,48 @@ class OpenStackProject(OpenStackIdentityObject):
         Returns the compute quotas as an instance of the ComputeQuotas class
         :return:
         """
-        nova = nova_utils.nova_client(self._os_creds)
-        return nova_utils.get_compute_quotas(nova, self.__project.id)
+        nova = nova_utils.nova_client(self._os_creds, self._os_session)
+
+        try:
+            return nova_utils.get_compute_quotas(nova, self.__project.id)
+        finally:
+            nova.client.session.session.close()
 
     def get_network_quotas(self):
         """
         Returns the network quotas as an instance of the NetworkQuotas class
         :return:
         """
-        neutron = neutron_utils.neutron_client(self._os_creds)
-        return neutron_utils.get_network_quotas(neutron, self.__project.id)
+        neutron = neutron_utils.neutron_client(
+            self._os_creds, self._os_session)
+        try:
+            return neutron_utils.get_network_quotas(neutron, self.__project.id)
+        finally:
+            neutron.httpclient.session.session.close()
 
     def update_compute_quotas(self, compute_quotas):
         """
         Updates the compute quotas for this project
         :param compute_quotas: a ComputeQuotas object.
         """
-        nova = nova_utils.nova_client(self._os_creds)
-        nova_utils.update_quotas(nova, self.__project.id, compute_quotas)
+        nova = nova_utils.nova_client(self._os_creds, self._os_session)
+        try:
+            nova_utils.update_quotas(nova, self.__project.id, compute_quotas)
+        finally:
+            nova.client.session.session.close()
 
     def update_network_quotas(self, network_quotas):
         """
         Updates the network quotas for this project
         :param network_quotas: a NetworkQuotas object.
         """
-        neutron = neutron_utils.neutron_client(self._os_creds)
-        neutron_utils.update_quotas(neutron, self.__project.id, network_quotas)
+        neutron = neutron_utils.neutron_client(
+            self._os_creds, self._os_session)
+        try:
+            neutron_utils.update_quotas(
+                neutron, self.__project.id, network_quotas)
+        finally:
+            neutron.httpclient.session.session.close()
 
 
 class ProjectSettings(ProjectConfig):
@@ -181,4 +226,4 @@ class ProjectSettings(ProjectConfig):
         from warnings import warn
         warn('Use snaps.config.project.ProjectConfig instead',
              DeprecationWarning)
-        super(self.__class__, self).__init__(**kwargs)
\ No newline at end of file
+        super(self.__class__, self).__init__(**kwargs)
index 44e35a3..7764a57 100644 (file)
@@ -90,6 +90,8 @@ class OpenStackQoS(OpenStackVolumeObject):
 
         self.__qos = None
 
+        super(self.__class__, self).clean()
+
     def get_qos(self):
         """
         Returns the domain QoS object as it was populated when create() was
index c9ccdd6..3269bbd 100644 (file)
@@ -63,24 +63,26 @@ class OpenStackRouter(OpenStackNetworkObject):
 
         try:
             self.__router = neutron_utils.get_router(
-                self._neutron, router_settings=self.router_settings)
+                self._neutron, self._keystone,
+                router_settings=self.router_settings,
+                project_name=self._os_creds.project_name)
         except Unauthorized as e:
             logger.warn('Unable to lookup router with name %s - %s',
                         self.router_settings.name, e)
 
         if self.__router:
-            for internal_subnet_name in self.router_settings.internal_subnets:
-                internal_subnet = neutron_utils.get_subnet(
-                    self._neutron, subnet_name=internal_subnet_name)
+            for sub_config in self.router_settings.internal_subnets:
+                internal_subnet = self.__get_internal_subnet(sub_config)
                 if internal_subnet:
                     self.__internal_subnets.append(internal_subnet)
                 else:
                     raise RouterCreationError(
-                        'Subnet not found with name ' + internal_subnet_name)
+                        'Subnet not found with name ' + internal_subnet.name)
 
             for port_setting in self.router_settings.port_settings:
                 port = neutron_utils.get_port(
-                    self._neutron, port_settings=port_setting)
+                    self._neutron, self._keystone, port_settings=port_setting,
+                    project_name=self._os_creds.project_name)
                 if port:
                     self.__ports.append(port)
 
@@ -97,9 +99,8 @@ class OpenStackRouter(OpenStackNetworkObject):
             self.__router = neutron_utils.create_router(
                 self._neutron, self._os_creds, self.router_settings)
 
-            for internal_subnet_name in self.router_settings.internal_subnets:
-                internal_subnet = neutron_utils.get_subnet(
-                    self._neutron, subnet_name=internal_subnet_name)
+            for sub_config in self.router_settings.internal_subnets:
+                internal_subnet = self.__get_internal_subnet(sub_config)
                 if internal_subnet:
                     self.__internal_subnets.append(internal_subnet)
                     if internal_subnet:
@@ -110,11 +111,12 @@ class OpenStackRouter(OpenStackNetworkObject):
                         self.__internal_router_interface = router_intf
                 else:
                     raise RouterCreationError(
-                        'Subnet not found with name ' + internal_subnet_name)
+                        'Subnet not found with name {}'.format(sub_config))
 
             for port_setting in self.router_settings.port_settings:
                 port = neutron_utils.get_port(
-                    self._neutron, port_settings=port_setting)
+                    self._neutron, self._keystone, port_settings=port_setting,
+                    project_name=self._os_creds.project_name)
                 logger.info(
                     'Retrieved port %s for router - %s', port_setting.name,
                     self.router_settings.name)
@@ -130,9 +132,8 @@ class OpenStackRouter(OpenStackNetworkObject):
                             port_setting.name,
                             self.router_settings.name)
                         self.__ports.append(port)
-                        neutron_utils.add_interface_router(self._neutron,
-                                                           self.__router,
-                                                           port=port)
+                        neutron_utils.add_interface_router(
+                            self._neutron, self.__router, port=port)
                     else:
                         raise RouterCreationError(
                             'Error creating port with name - '
@@ -142,6 +143,28 @@ class OpenStackRouter(OpenStackNetworkObject):
             self._neutron, self.__router.id)
         return self.__router
 
+    def __get_internal_subnet(self, sub_config):
+        """
+        returns the Subnet domain object from the subnet configurator
+        :param sub_config:
+        :return:
+        """
+        if isinstance(sub_config, dict):
+            sub_dict = sub_config['subnet']
+            network = neutron_utils.get_network(
+                self._neutron, self._keystone,
+                network_name=sub_dict['network_name'],
+                project_name=sub_dict['project_name'])
+            if network:
+                return neutron_utils.get_subnet(
+                    self._neutron, network,
+                    subnet_name=sub_dict['subnet_name'])
+        else:
+            return neutron_utils.get_subnet_by_name(
+                self._neutron, self._keystone,
+                subnet_name=sub_config,
+                project_name=self._os_creds.project_name)
+
     def clean(self):
         """
         Removes and deletes all items created in reverse order.
@@ -177,6 +200,8 @@ class OpenStackRouter(OpenStackNetworkObject):
                 pass
             self.__router = None
 
+        super(self.__class__, self).clean()
+
     def get_router(self):
         """
         Returns the OpenStack router object
index 7a20fe1..490f419 100644 (file)
@@ -20,7 +20,6 @@ from neutronclient.common.exceptions import NotFound, Conflict
 from snaps.config.security_group import (
     SecurityGroupConfig, SecurityGroupRuleConfig)
 from snaps.openstack.openstack_creator import OpenStackNetworkObject
-from snaps.openstack.utils import keystone_utils
 from snaps.openstack.utils import neutron_utils
 
 __author__ = 'spisarski'
@@ -57,7 +56,9 @@ class OpenStackSecurityGroup(OpenStackNetworkObject):
         super(self.__class__, self).initialize()
 
         self.__security_group = neutron_utils.get_security_group(
-            self._neutron, sec_grp_settings=self.sec_grp_settings)
+            self._neutron, self._keystone,
+            sec_grp_settings=self.sec_grp_settings,
+            project_name=self._os_creds.project_name)
         if self.__security_group:
             # Populate rules
             existing_rules = neutron_utils.get_rules_by_security_group(
@@ -84,10 +85,8 @@ class OpenStackSecurityGroup(OpenStackNetworkObject):
             logger.info(
                 'Creating security group %s...' % self.sec_grp_settings.name)
 
-            keystone = keystone_utils.keystone_client(self._os_creds)
             self.__security_group = neutron_utils.create_security_group(
-                self._neutron, keystone,
-                self.sec_grp_settings)
+                self._neutron, self._keystone, self.sec_grp_settings)
 
             # Get the rules added for free
             auto_rules = neutron_utils.get_rules_by_security_group(
@@ -103,15 +102,16 @@ class OpenStackSecurityGroup(OpenStackNetworkObject):
             for sec_grp_rule_setting in self.sec_grp_settings.rule_settings:
                 try:
                     custom_rule = neutron_utils.create_security_group_rule(
-                        self._neutron, sec_grp_rule_setting)
+                        self._neutron, self._keystone, sec_grp_rule_setting,
+                        self._os_creds.project_name)
                     self.__rules[sec_grp_rule_setting] = custom_rule
                 except Conflict as e:
                     logger.warn('Unable to create rule due to conflict - %s',
                                 e)
 
             # Refresh security group object to reflect the new rules added
-            self.__security_group = neutron_utils.get_security_group(
-                self._neutron, sec_grp_settings=self.sec_grp_settings)
+            self.__security_group = neutron_utils.get_security_group_by_id(
+                self._neutron, self.__security_group.id)
 
         return self.__security_group
 
@@ -159,6 +159,8 @@ class OpenStackSecurityGroup(OpenStackNetworkObject):
 
             self.__security_group = None
 
+        super(self.__class__, self).clean()
+
     def get_security_group(self):
         """
         Returns the OpenStack security group object
@@ -179,8 +181,9 @@ class OpenStackSecurityGroup(OpenStackNetworkObject):
         :param rule_setting: the rule configuration
         """
         rule_setting.sec_grp_name = self.sec_grp_settings.name
-        new_rule = neutron_utils.create_security_group_rule(self._neutron,
-                                                            rule_setting)
+        new_rule = neutron_utils.create_security_group_rule(
+            self._neutron, self._keystone, rule_setting,
+            self._os_creds.project_name)
         self.__rules[rule_setting] = new_rule
         self.sec_grp_settings.rule_settings.append(rule_setting)
 
index d4a6b10..71e5d0a 100644 (file)
@@ -23,16 +23,17 @@ from snaps.config.stack import StackConfig
 from snaps.openstack.create_flavor import OpenStackFlavor
 from snaps.openstack.create_instance import OpenStackVmInstance
 from snaps.openstack.create_keypairs import OpenStackKeypair
-from snaps.openstack.create_security_group import OpenStackSecurityGroup
+from snaps.openstack.create_network import OpenStackNetwork
 from snaps.openstack.create_router import OpenStackRouter
+from snaps.openstack.create_security_group import OpenStackSecurityGroup
 from snaps.openstack.create_volume import OpenStackVolume
 from snaps.openstack.create_volume_type import OpenStackVolumeType
 from snaps.openstack.openstack_creator import OpenStackCloudObject
 from snaps.openstack.utils import (
     nova_utils, settings_utils, glance_utils, cinder_utils)
-
-from snaps.openstack.create_network import OpenStackNetwork
 from snaps.openstack.utils import heat_utils, neutron_utils
+from snaps.thread_utils import worker_pool
+
 
 __author__ = 'spisarski'
 
@@ -73,19 +74,35 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         self.__stack = None
         self.__heat_cli = None
 
+        self.__neutron = None
+        self.__nova = None
+        self.__glance = None
+        self.__cinder = None
+
     def initialize(self):
         """
         Loads the existing heat stack
         :return: The Stack domain object or None
         """
-        self.__heat_cli = heat_utils.heat_client(self._os_creds)
+        super(self.__class__, self).initialize()
+
+        self.__neutron = neutron_utils.neutron_client(
+            self._os_creds, self._os_session)
+        self.__nova = nova_utils.nova_client(self._os_creds, self._os_session)
+        self.__glance = glance_utils.glance_client(
+            self._os_creds, self._os_session)
+        self.__cinder = cinder_utils.cinder_client(
+            self._os_creds, self._os_session)
+
+        self.__heat_cli = heat_utils.heat_client(
+            self._os_creds, self._os_session)
         self.__stack = heat_utils.get_stack(
             self.__heat_cli, stack_settings=self.stack_settings)
         if self.__stack:
             logger.info('Found stack with name - ' + self.stack_settings.name)
             return self.__stack
 
-    def create(self):
+    def create(self, block=False):
         """
         Creates the heat stack in OpenStack if it does not already exist and
         returns the domain Stack object
@@ -101,7 +118,7 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
                                                    self.stack_settings)
             logger.info(
                 'Created stack with name - %s', self.stack_settings.name)
-            if self.__stack and self.stack_complete(block=True):
+            if self.__stack and self.stack_complete(block=block):
                 logger.info('Stack is now active with name - %s',
                             self.stack_settings.name)
                 return self.__stack
@@ -111,6 +128,28 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
                 logger.error('ERROR: STACK CREATION FAILED: %s', status)
                 raise StackCreationError('Failure while creating stack')
 
+    def update(self, env_vals, block=False):
+        """
+        Updates the heat stack in OpenStack
+        :param: env_vals - the values to update
+        :return: The Stack domain object or None
+        """
+        if self.__stack:
+            logger.info('Updating stack - %s', self.__stack.name)
+            heat_utils.update_stack(self.__heat_cli, self.__stack, env_vals)
+            if self.stack_updated(block=block):
+                logger.info('Stack %s is now updated with params: %s',
+                            self.__stack.name, env_vals)
+                self.stack_settings.env_values = env_vals
+                self.__stack = heat_utils.get_stack_by_id(
+                    self.__heat_cli, self.__stack.id)
+                return self.__stack
+            else:
+                status = heat_utils.get_stack_status_reason(self.__heat_cli,
+                                                            self.__stack.id)
+                logger.error('ERROR: STACK UPDATE FAILED: %s', status)
+                raise StackUpdateError('Failure while updating stack')
+
     def clean(self):
         """
         Cleanse environment of all artifacts
@@ -152,13 +191,21 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
 
             self.__stack = None
 
+        self.__neutron.httpclient.session.session.close()
+        self.__nova.client.session.session.close()
+        self.__glance.http_client.session.session.close()
+        self.__cinder.client.session.session.close()
+
+        super(self.__class__, self).clean()
+
     def get_stack(self):
         """
         Returns the domain Stack object as it was populated when create() was
         called
         :return: the object
         """
-        return self.__stack
+        if self.__stack:
+            return heat_utils.get_stack_by_id(self.__heat_cli, self.__stack.id)
 
     def get_outputs(self):
         """
@@ -174,7 +221,9 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         object
         :return:
         """
-        return heat_utils.get_stack_status(self.__heat_cli, self.__stack.id)
+        stack = self.get_stack()
+        if stack:
+            return stack.status
 
     def stack_complete(self, block=False, timeout=None,
                        poll_interval=snaps.config.stack.POLL_INTERVAL):
@@ -193,6 +242,22 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
             snaps.config.stack.STATUS_CREATE_COMPLETE, block, timeout,
             poll_interval, snaps.config.stack.STATUS_CREATE_FAILED)
 
+    def stack_updated(self, block=False,
+                      timeout=snaps.config.stack.STACK_UPDATE_TIMEOUT,
+                      poll_interval=snaps.config.stack.POLL_INTERVAL):
+        """
+        Returns true when the stack status returns the value of
+        expected_status_code
+        :param block: When true, thread will block until active or timeout
+                      value in seconds has been exceeded (False)
+        :param timeout: The timeout value
+        :param poll_interval: The polling interval in seconds
+        :return: T/F
+        """
+        return self._stack_status_check(
+            snaps.config.stack.STATUS_UPDATE_COMPLETE, block, timeout,
+            poll_interval, snaps.config.stack.STATUS_UPDATE_FAILED)
+
     def stack_deleted(self, block=False,
                       timeout=snaps.config.stack.STACK_DELETE_TIMEOUT,
                       poll_interval=snaps.config.stack.POLL_INTERVAL):
@@ -216,15 +281,13 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         :return: list() of OpenStackNetwork objects
         """
 
-        neutron = neutron_utils.neutron_client(self._os_creds)
-
         out = list()
         stack_networks = heat_utils.get_stack_networks(
-            self.__heat_cli, neutron, self.__stack)
+            self.__heat_cli, self.__neutron, self.__stack)
 
         for stack_network in stack_networks:
             net_settings = settings_utils.create_network_config(
-                neutron, stack_network)
+                self.__neutron, stack_network)
             net_creator = OpenStackNetwork(self._os_creds, net_settings)
             out.append(net_creator)
             net_creator.initialize()
@@ -238,15 +301,13 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         :return: list() of OpenStackNetwork objects
         """
 
-        neutron = neutron_utils.neutron_client(self._os_creds)
-
         out = list()
         stack_security_groups = heat_utils.get_stack_security_groups(
-            self.__heat_cli, neutron, self.__stack)
+            self.__heat_cli, self.__neutron, self.__stack)
 
         for stack_security_group in stack_security_groups:
             settings = settings_utils.create_security_group_config(
-                neutron, stack_security_group)
+                self.__neutron, stack_security_group)
             creator = OpenStackSecurityGroup(self._os_creds, settings)
             out.append(creator)
             creator.initialize()
@@ -260,21 +321,36 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         :return: list() of OpenStackRouter objects
         """
 
-        neutron = neutron_utils.neutron_client(self._os_creds)
-
         out = list()
         stack_routers = heat_utils.get_stack_routers(
-            self.__heat_cli, neutron, self.__stack)
+            self.__heat_cli, self.__neutron, self.__stack)
 
         for routers in stack_routers:
             settings = settings_utils.create_router_config(
-                neutron, routers)
+                self.__neutron, routers)
             creator = OpenStackRouter(self._os_creds, settings)
             out.append(creator)
             creator.initialize()
 
         return out
 
+    def __create_vm_inst(self, heat_keypair_option, stack_server):
+
+        vm_inst_settings = settings_utils.create_vm_inst_config(
+            self.__nova, self._keystone, self.__neutron, stack_server,
+            self._os_creds.project_name)
+        image_settings = settings_utils.determine_image_config(
+            self.__glance, stack_server, self.image_settings)
+        keypair_settings = settings_utils.determine_keypair_config(
+            self.__heat_cli, self.__stack, stack_server,
+            keypair_settings=self.keypair_settings,
+            priv_key_key=heat_keypair_option)
+        vm_inst_creator = OpenStackVmInstance(
+            self._os_creds, vm_inst_settings, image_settings,
+            keypair_settings)
+        vm_inst_creator.initialize()
+        return vm_inst_creator
+
     def get_vm_inst_creators(self, heat_keypair_option=None):
         """
         Returns a list of VM Instance creator objects as configured by the heat
@@ -283,28 +359,21 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         """
 
         out = list()
-        nova = nova_utils.nova_client(self._os_creds)
-        neutron = neutron_utils.neutron_client(self._os_creds)
 
         stack_servers = heat_utils.get_stack_servers(
-            self.__heat_cli, nova, neutron, self.__stack)
-
-        glance = glance_utils.glance_client(self._os_creds)
+            self.__heat_cli, self.__nova, self.__neutron, self._keystone,
+            self.__stack, self._os_creds.project_name)
 
+        workers = []
         for stack_server in stack_servers:
-            vm_inst_settings = settings_utils.create_vm_inst_config(
-                nova, neutron, stack_server)
-            image_settings = settings_utils.determine_image_config(
-                glance, stack_server, self.image_settings)
-            keypair_settings = settings_utils.determine_keypair_config(
-                self.__heat_cli, self.__stack, stack_server,
-                keypair_settings=self.keypair_settings,
-                priv_key_key=heat_keypair_option)
-            vm_inst_creator = OpenStackVmInstance(
-                self._os_creds, vm_inst_settings, image_settings,
-                keypair_settings)
-            out.append(vm_inst_creator)
-            vm_inst_creator.initialize()
+            worker = worker_pool().apply_async(
+                self.__create_vm_inst,
+                (heat_keypair_option,
+                    stack_server))
+            workers.append(worker)
+
+        for worker in workers:
+            out.append(worker.get())
 
         return out
 
@@ -316,10 +385,8 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         """
 
         out = list()
-        cinder = cinder_utils.cinder_client(self._os_creds)
-
         volumes = heat_utils.get_stack_volumes(
-            self.__heat_cli, cinder, self.__stack)
+            self.__heat_cli, self.__cinder, self.__stack)
 
         for volume in volumes:
             settings = settings_utils.create_volume_config(volume)
@@ -342,10 +409,8 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         """
 
         out = list()
-        cinder = cinder_utils.cinder_client(self._os_creds)
-
         vol_types = heat_utils.get_stack_volume_types(
-            self.__heat_cli, cinder, self.__stack)
+            self.__heat_cli, self.__cinder, self.__stack)
 
         for volume in vol_types:
             settings = settings_utils.create_volume_type_config(volume)
@@ -369,10 +434,9 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         """
 
         out = list()
-        nova = nova_utils.nova_client(self._os_creds)
 
         keypairs = heat_utils.get_stack_keypairs(
-            self.__heat_cli, nova, self.__stack)
+            self.__heat_cli, self.__nova, self.__stack)
 
         for keypair in keypairs:
             settings = settings_utils.create_keypair_config(
@@ -397,10 +461,9 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         """
 
         out = list()
-        nova = nova_utils.nova_client(self._os_creds)
 
         flavors = heat_utils.get_stack_flavors(
-            self.__heat_cli, nova, self.__stack)
+            self.__heat_cli, self.__nova, self.__stack)
 
         for flavor in flavors:
             settings = settings_utils.create_flavor_config(flavor)
@@ -486,6 +549,22 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
         return status == expected_status_code
 
 
+def generate_creator(os_creds, stack_inst, image_settings):
+    """
+    Initializes an OpenStackHeatStack object
+    :param os_creds: the OpenStack credentials
+    :param stack_inst: the SNAPS-OO VmInst domain object
+    :param image_settings: list of SNAPS-OO ImageConfig objects
+    :return: an initialized OpenStackHeatStack object
+    """
+
+    heat_config = StackConfig(
+        name=stack_inst.name, template={'place': 'holder'})
+    heat_creator = OpenStackHeatStack(os_creds, heat_config, image_settings)
+    heat_creator.initialize()
+    return heat_creator
+
+
 class StackSettings(StackConfig):
     """
     Class to hold the configuration settings required for creating OpenStack
@@ -505,6 +584,11 @@ class StackCreationError(Exception):
     Exception to be thrown when an stack cannot be created
     """
 
+class StackUpdateError(Exception):
+    """
+    Exception to be thrown when an stack update failed
+    """
+
 
 class StackError(Exception):
     """
index 5da3a5e..b187f4e 100644 (file)
@@ -77,6 +77,8 @@ class OpenStackUser(OpenStackIdentityObject):
                 pass
             self.__user = None
 
+        super(self.__class__, self).clean()
+
     def get_user(self):
         """
         Returns the OpenStack user object populated in create()
@@ -91,6 +93,9 @@ class OpenStackUser(OpenStackIdentityObject):
                              credentials
         :return:
         """
+        if not project_name:
+            project_name = self._os_creds.project_name
+
         return OSCreds(
             username=self.user_settings.name,
             password=self.user_settings.password,
@@ -102,6 +107,7 @@ class OpenStackUser(OpenStackIdentityObject):
             compute_api_version=self._os_creds.compute_api_version,
             heat_api_version=self._os_creds.heat_api_version,
             volume_api_version=self._os_creds.volume_api_version,
+            region_name=self._os_creds.region_name,
             user_domain_name=self._os_creds.user_domain_name,
             user_domain_id=self._os_creds.user_domain_id,
             project_domain_name=self._os_creds.project_domain_name,
index c134ca1..b35cd89 100644 (file)
@@ -60,7 +60,9 @@ class OpenStackVolume(OpenStackVolumeObject):
         super(self.__class__, self).initialize()
 
         self.__volume = cinder_utils.get_volume(
-            self._cinder, volume_settings=self.volume_settings)
+            self._cinder, self._keystone,
+            volume_settings=self.volume_settings,
+            project_name=self._os_creds.project_name)
         return self.__volume
 
     def create(self, block=False):
@@ -73,7 +75,7 @@ class OpenStackVolume(OpenStackVolumeObject):
 
         if not self.__volume:
             self.__volume = cinder_utils.create_volume(
-                self._cinder, self.volume_settings)
+                self._cinder, self._keystone, self.volume_settings)
 
             logger.info(
                 'Created volume with name - %s', self.volume_settings.name)
@@ -124,6 +126,8 @@ class OpenStackVolume(OpenStackVolumeObject):
 
         self.__volume = None
 
+        super(self.__class__, self).clean()
+
     def get_volume(self):
         """
         Returns the domain Volume object as it was populated when create() was
index a7198d8..9a45561 100644 (file)
@@ -87,6 +87,8 @@ class OpenStackVolumeType(OpenStackVolumeObject):
 
         self.__volume_type = None
 
+        super(self.__class__, self).clean()
+
     def get_volume_type(self):
         """
         Returns the domain Volume object as it was populated when create() was
index 0caee9a..6eeac37 100644 (file)
@@ -29,17 +29,24 @@ class OpenStackCloudObject(CloudObject):
         Constructor
         :param os_creds: the OpenStack credentials object
         """
-        # super(self.__class__, self, os_creds)
         self._os_creds = os_creds
+        self._os_session = None
+        self._keystone = None
 
     def initialize(self):
-        raise NotImplementedError('Do not override abstract method')
+        self._os_session = keystone_utils.keystone_session(self._os_creds)
+        self._keystone = keystone_utils.keystone_client(
+            self._os_creds, session=self._os_session)
+
+    def get_os_creds(self):
+        return self._os_creds
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
 
     def clean(self):
-        raise NotImplementedError('Do not override abstract method')
+        if self._os_session:
+            keystone_utils.close_session(self._os_session)
 
 
 class OpenStackComputeObject(OpenStackCloudObject):
@@ -56,14 +63,12 @@ class OpenStackComputeObject(OpenStackCloudObject):
         self._nova = None
 
     def initialize(self):
-        self._nova = nova_utils.nova_client(self._os_creds)
+        super(OpenStackComputeObject, self).initialize()
+        self._nova = nova_utils.nova_client(self._os_creds, self._os_session)
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
 
-    def clean(self):
-        raise NotImplementedError('Do not override abstract method')
-
 
 class OpenStackNetworkObject(OpenStackCloudObject):
     """
@@ -79,14 +84,13 @@ class OpenStackNetworkObject(OpenStackCloudObject):
         self._neutron = None
 
     def initialize(self):
-        self._neutron = neutron_utils.neutron_client(self._os_creds)
+        super(OpenStackNetworkObject, self).initialize()
+        self._neutron = neutron_utils.neutron_client(
+            self._os_creds, self._os_session)
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
 
-    def clean(self):
-        raise NotImplementedError('Do not override abstract method')
-
 
 class OpenStackIdentityObject(OpenStackCloudObject):
     """
@@ -99,17 +103,13 @@ class OpenStackIdentityObject(OpenStackCloudObject):
         :param os_creds: the OpenStack credentials object
         """
         super(OpenStackIdentityObject, self).__init__(os_creds)
-        self._keystone = None
 
     def initialize(self):
-        self._keystone = keystone_utils.keystone_client(self._os_creds)
+        super(OpenStackIdentityObject, self).initialize()
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
 
-    def clean(self):
-        raise NotImplementedError('Do not override abstract method')
-
 
 class OpenStackVolumeObject(OpenStackCloudObject):
     """
@@ -125,14 +125,13 @@ class OpenStackVolumeObject(OpenStackCloudObject):
         self._cinder = None
 
     def initialize(self):
-        self._cinder = cinder_utils.cinder_client(self._os_creds)
+        super(OpenStackVolumeObject, self).initialize()
+        self._cinder = cinder_utils.cinder_client(
+            self._os_creds, self._os_session)
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
 
-    def clean(self):
-        raise NotImplementedError('Do not override abstract method')
-
 
 class OpenStackMagnumObject(OpenStackCloudObject):
     """
@@ -148,10 +147,9 @@ class OpenStackMagnumObject(OpenStackCloudObject):
         self._magnum = None
 
     def initialize(self):
-        self._magnum = magnum_utils.magnum_client(self._os_creds)
+        super(OpenStackMagnumObject, self).initialize()
+        self._magnum = magnum_utils.magnum_client(
+            self._os_creds, self._os_session)
 
     def create(self):
         raise NotImplementedError('Do not override abstract method')
-
-    def clean(self):
-        raise NotImplementedError('Do not override abstract method')
index 72223e3..11ef8ff 100644 (file)
@@ -63,7 +63,7 @@ class OSCreds:
         self.project_name = kwargs.get('project_name')
 
         if kwargs.get('identity_api_version') is None:
-            self.identity_api_version = keystone_utils.V2_VERSION_NUM
+            self.identity_api_version = keystone_utils.V3_VERSION_NUM
         else:
             self.identity_api_version = float(kwargs['identity_api_version'])
 
@@ -85,7 +85,9 @@ class OSCreds:
         if kwargs.get('heat_api_version') is None:
             self.heat_api_version = 1
         else:
-            self.heat_api_version = float(kwargs['heat_api_version'])
+            val = kwargs['heat_api_version']
+            ver = float(val)
+            self.heat_api_version = int(ver)
 
         if kwargs.get('volume_api_version') is None:
             self.volume_api_version = cinder_utils.VERSION_2
@@ -169,6 +171,45 @@ class OSCreds:
 
         return new_url
 
+    def to_dict(self):
+        """Converts object to a dict that can be used to construct another"""
+        return {'username': self.username,
+                'password': self.password,
+                'auth_url': self.auth_url,
+                'project_name': self.project_name,
+                'identity_api_version': self.identity_api_version,
+                'image_api_version': self.image_api_version,
+                'network_api_version': self.network_api_version,
+                'compute_api_version': self.compute_api_version,
+                'heat_api_version': self.heat_api_version,
+                'user_domain_id': self.user_domain_id,
+                'user_domain_name': self.user_domain_name,
+                'project_domain_id': self.project_domain_id,
+                'project_domain_name': self.project_domain_name,
+                'interface': self.interface,
+                'region_name': self.region_name,
+                'proxy_settings': self.proxy_settings,
+                'cacert': self.cacert}
+
+    def __eq__(self, other):
+        return (self.username == other.username and
+                self.password == other.password and
+                self.auth_url == other.auth_url and
+                self.project_name == other.project_name and
+                float(self.identity_api_version) == float(other.identity_api_version) and
+                float(self.image_api_version) == float(other.image_api_version) and
+                float(self.network_api_version) == float(other.network_api_version) and
+                float(self.compute_api_version) == float(other.compute_api_version) and
+                float(self.heat_api_version) == float(other.heat_api_version) and
+                self.user_domain_id == other.user_domain_id and
+                self.user_domain_name == other.user_domain_name and
+                self.project_domain_id == other.project_domain_id and
+                self.project_domain_name == other.project_domain_name and
+                self.interface == other.interface and
+                self.region_name == other.region_name and
+                self.proxy_settings == other.proxy_settings and
+                self.cacert == other.cacert)
+
     def __str__(self):
         """Converts object to a string"""
         return ('OSCreds - username=' + str(self.username) +
index 355467d..eda790d 100644 (file)
@@ -54,7 +54,8 @@ class CreateClusterTemplateTests(OSIntegrationTestCase):
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.cluster_type_name = self.guid + '-cluster-type'
-        self.magnum = magnum_utils.magnum_client(self.os_creds)
+        self.magnum = magnum_utils.magnum_client(
+            self.os_creds, self.os_session)
 
         metadata = self.image_metadata
         if not metadata:
@@ -68,9 +69,10 @@ class CreateClusterTemplateTests(OSIntegrationTestCase):
 
         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
 
-        self.flavor_creator = OpenStackFlavor(
-            self.os_creds, FlavorConfig(
-                name=self.guid + '-flavor', ram=512, disk=10, vcpus=1))
+        flavor_config = openstack_tests.get_flavor_config(
+            name=self.guid + '-flavor', ram=512, disk=10,
+            vcpus=1, metadata=self.flavor_metadata)
+        self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_config)
 
         keypair_priv_filepath = 'tmp/' + self.guid
         keypair_pub_filepath = keypair_priv_filepath + '.pub'
index 192be86..696ca2d 100644 (file)
@@ -142,9 +142,9 @@ class OSCredsUnitTests(unittest.TestCase):
             project_name='hello')
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
@@ -165,9 +165,9 @@ class OSCredsUnitTests(unittest.TestCase):
                               'project_name': 'hello'})
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
@@ -243,9 +243,9 @@ class OSCredsUnitTests(unittest.TestCase):
             project_name='hello', proxy_settings=proxy_settings)
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
@@ -262,6 +262,11 @@ class OSCredsUnitTests(unittest.TestCase):
         self.assertIsNone(os_creds.proxy_settings.ssh_proxy_cmd)
         self.assertIsNone(os_creds.region_name)
 
+        creds_dict = os_creds.to_dict()
+        creds_from_dict = OSCreds(**creds_dict)
+
+        self.assertEqual(os_creds, creds_from_dict)
+
     def test_proxy_settings_obj_kwargs(self):
         proxy_settings = ProxySettings(host='foo', port=1234)
         os_creds = OSCreds(
@@ -273,9 +278,9 @@ class OSCredsUnitTests(unittest.TestCase):
                'project_domain_name': 'domain4'})
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
@@ -300,9 +305,9 @@ class OSCredsUnitTests(unittest.TestCase):
             project_domain_id='domain3', project_domain_name='domain4')
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
@@ -326,9 +331,9 @@ class OSCredsUnitTests(unittest.TestCase):
                'region_name': 'test_region'})
         self.assertEqual('foo', os_creds.username)
         self.assertEqual('bar', os_creds.password)
-        self.assertEqual('http://foo.bar:5000/v2.0', os_creds.auth_url)
+        self.assertEqual('http://foo.bar:5000/v3', os_creds.auth_url)
         self.assertEqual('hello', os_creds.project_name)
-        self.assertEqual(2, os_creds.identity_api_version)
+        self.assertEqual(3, os_creds.identity_api_version)
         self.assertEqual(2, os_creds.image_api_version)
         self.assertEqual(2, os_creds.compute_api_version)
         self.assertEqual(1, os_creds.heat_api_version)
index 36e3cfd..53d500f 100644 (file)
@@ -14,4 +14,7 @@
 #os_auth_url: http://<host>:<port>/
 #project_name: admin
 #identity_api_version: 3
-#ext_net: <external network name>
\ No newline at end of file
+#ext_net: <external network name>
+
+flavor_metadata:
+    hw:mem_page_size: large
index f84355d..a69de40 100644 (file)
@@ -20,6 +20,7 @@ from snaps.openstack import create_flavor
 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
 from snaps.openstack.utils import nova_utils
+from snaps.openstack.tests import openstack_tests
 
 __author__ = 'spisarski'
 
@@ -274,7 +275,7 @@ class CreateFlavorTests(OSComponentTestCase):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.flavor_name = guid + 'name'
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.flavor_creator = None
@@ -286,6 +287,8 @@ class CreateFlavorTests(OSComponentTestCase):
         if self.flavor_creator:
             self.flavor_creator.clean()
 
+        super(self.__class__, self).__clean__()
+
     def test_create_flavor(self):
         """
         Tests the creation of an OpenStack flavor.
@@ -362,10 +365,12 @@ class CreateFlavorTests(OSComponentTestCase):
         raise any exceptions.
         """
         # Create Flavor
-        flavor_settings = FlavorConfig(
+        if self.flavor_metadata:
+            self.flavor_metadata.update(create_flavor.MEM_PAGE_SIZE_ANY)
+        flavor_settings = openstack_tests.get_flavor_config(
             name=self.flavor_name, ram=1, disk=1, vcpus=1, ephemeral=2, swap=3,
             rxtx_factor=2.2, is_public=False,
-            metadata=create_flavor.MEM_PAGE_SIZE_ANY)
+            metadata=self.flavor_metadata)
         self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings)
         flavor = self.flavor_creator.create()
         self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor))
index 9965f87..ae59a67 100644 (file)
@@ -265,7 +265,8 @@ class CreateImageSuccessTests(OSIntegrationTestCase):
 
         guid = uuid.uuid4()
         self.image_name = self.__class__.__name__ + '-' + str(guid)
-        self.glance = glance_utils.glance_client(self.os_creds)
+        self.glance = glance_utils.glance_client(
+            self.os_creds, self.os_session)
         self.image_creator = None
 
         if self.image_metadata and 'glance_tests' in self.image_metadata:
@@ -379,8 +380,8 @@ class CreateImageSuccessTests(OSIntegrationTestCase):
         clean() does not raise an Exception.
         """
         # Create Image
-        self.image_creator = create_image.OpenStackImage(self.os_creds,
-                                                         self.image_settings)
+        self.image_creator = create_image.OpenStackImage(
+            self.os_creds, self.image_settings)
         created_image = self.image_creator.create()
         self.assertIsNotNone(created_image)
 
@@ -562,7 +563,8 @@ class CreateMultiPartImageTests(OSIntegrationTestCase):
         guid = uuid.uuid4()
         self.image_creators = list()
         self.image_name = self.__class__.__name__ + '-' + str(guid)
-        self.glance = glance_utils.glance_client(self.os_creds)
+        self.glance = glance_utils.glance_client(
+            self.os_creds, self.os_session)
 
         self.tmp_dir = 'tmp/' + str(guid)
         if not os.path.exists(self.tmp_dir):
index c713794..17831b3 100644 (file)
@@ -24,7 +24,6 @@ from neutronclient.common.exceptions import (
     InvalidIpForSubnetClient, BadRequest)
 
 from snaps import file_utils
-from snaps.config.flavor import FlavorConfig
 from snaps.config.image import ImageConfig
 from snaps.config.keypair import KeypairConfig
 from snaps.config.network import PortConfig, NetworkConfig, SubnetConfig
@@ -45,10 +44,11 @@ from snaps.openstack.create_network import OpenStackNetwork
 from snaps.openstack.create_router import OpenStackRouter
 from snaps.openstack.create_security_group import OpenStackSecurityGroup
 from snaps.openstack.create_volume import OpenStackVolume
+from snaps.openstack.os_credentials import OSCreds
 from snaps.openstack.tests import openstack_tests, validation_utils
 from snaps.openstack.tests.os_source_file_test import (
     OSIntegrationTestCase, OSComponentTestCase)
-from snaps.openstack.utils import nova_utils
+from snaps.openstack.utils import nova_utils, keystone_utils, neutron_utils
 from snaps.openstack.utils.nova_utils import RebootType
 from snaps.openstack.utils import nova_utils, settings_utils, neutron_utils
 
@@ -294,7 +294,7 @@ class SimpleHealthCheck(OSIntegrationTestCase):
         """
         super(self.__class__, self).__start__()
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.vm_inst_name = guid + '-inst'
         self.port_1_name = guid + 'port-1'
@@ -306,6 +306,7 @@ class SimpleHealthCheck(OSIntegrationTestCase):
         self.inst_creator = None
 
         self.priv_net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-priv-net',
             subnet_name=guid + '-priv-subnet',
             netconf_override=self.netconf_override)
@@ -334,10 +335,11 @@ class SimpleHealthCheck(OSIntegrationTestCase):
             if (self.flavor_metadata and
                self.flavor_metadata.get('hw:mem_page_size') == 'large'):
                 self.flavor_ram = 1024
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=self.flavor_ram, disk=10,
+                vcpus=1, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=self.flavor_ram,
-                             disk=10, vcpus=1, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
         except Exception as e:
             self.tearDown()
@@ -411,23 +413,16 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase):
 
     def setUp(self):
         """
-        Instantiates the CreateImage object that is responsible for downloading
-        and creating an OS image file
-        within OpenStack
+        Setup the objects required for the test
         """
         super(self.__class__, self).__start__()
 
-        guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.vm_inst_name = guid + '-inst'
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.vm_inst_name = self.guid + '-inst'
         self.nova = nova_utils.nova_client(self.os_creds)
         self.neutron = neutron_utils.neutron_client(self.os_creds)
         os_image_settings = openstack_tests.cirros_image_settings(
-            name=guid + '-image', image_metadata=self.image_metadata)
-
-        net_config = openstack_tests.get_priv_net_config(
-            net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
-            router_name=guid + '-pub-router', external_net=self.ext_net_name,
-            netconf_override=self.netconf_override)
+            name=self.guid + '-image', image_metadata=self.image_metadata)
 
         # Initialize for tearDown()
         self.image_creator = None
@@ -443,21 +438,13 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase):
             self.image_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
-                             vcpus=2, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
-
-            # Create Network
-            self.network_creator = OpenStackNetwork(
-                self.os_creds, net_config.network_settings)
-            self.network_creator.create()
-
-            self.port_settings = PortConfig(
-                name=guid + '-port',
-                network_name=net_config.network_settings.name)
-
+            self.network_creator = None
         except Exception as e:
             self.tearDown()
             raise e
@@ -504,6 +491,22 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack instance with a single port with a
         static IP without a Floating IP.
         """
+        # Create Network
+        net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
+            net_name=self.guid + '-pub-net',
+            subnet_name=self.guid + '-pub-subnet',
+            router_name=self.guid + '-pub-router',
+            external_net=self.ext_net_name,
+            netconf_override=self.netconf_override)
+        self.network_creator = OpenStackNetwork(
+            self.os_creds, net_config.network_settings)
+        self.network_creator.create()
+
+        self.port_settings = PortConfig(
+            name=self.guid + '-port',
+            network_name=net_config.network_settings.name)
+
         instance_settings = VmInstanceConfig(
             name=self.vm_inst_name,
             flavor=self.flavor_creator.flavor_settings.name,
@@ -513,20 +516,174 @@ class CreateInstanceSimpleTests(OSIntegrationTestCase):
             self.os_creds, instance_settings,
             self.image_creator.image_settings)
 
-        vm_inst = self.inst_creator.create()
-        self.assertIsNotNone(nova_utils.get_server(
-            self.nova, self.neutron, vm_inst_settings=instance_settings))
+        vm_inst = self.inst_creator.create(block=True)
+        vm_inst_get = nova_utils.get_server(
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings)
+        self.assertEqual(vm_inst, vm_inst_get)
+
+        self.assertIsNotNone(self.inst_creator.get_vm_inst().availability_zone)
+        self.assertIsNone(self.inst_creator.get_vm_inst().compute_host)
 
         # Delete instance
         nova_utils.delete_vm_instance(self.nova, vm_inst)
 
         self.assertTrue(self.inst_creator.vm_deleted(block=True))
         self.assertIsNone(nova_utils.get_server(
-            self.nova, self.neutron, vm_inst_settings=instance_settings))
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings))
 
         # Exception should not be thrown
         self.inst_creator.clean()
 
+    def test_create_admin_instance(self):
+        """
+        Tests the creation of an OpenStack instance with a single port with a
+        static IP without a Floating IP.
+        """
+        # Create Network
+        net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
+            net_name=self.guid + '-pub-net',
+            subnet_name=self.guid + '-pub-subnet',
+            router_name=self.guid + '-pub-router',
+            external_net=self.ext_net_name,
+            netconf_override=self.netconf_override)
+        self.network_creator = OpenStackNetwork(
+            self.admin_os_creds, net_config.network_settings)
+        self.network_creator.create()
+
+        self.port_settings = PortConfig(
+            name=self.guid + '-port',
+            network_name=net_config.network_settings.name)
+
+        instance_settings = VmInstanceConfig(
+            name=self.vm_inst_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            port_settings=[self.port_settings])
+
+        self.inst_creator = OpenStackVmInstance(
+            self.admin_os_creds, instance_settings,
+            self.image_creator.image_settings)
+
+        admin_nova = nova_utils.nova_client(self.admin_os_creds)
+        admin_neutron = neutron_utils.neutron_client(self.admin_os_creds)
+        admin_key = keystone_utils.keystone_client(self.admin_os_creds)
+        vm_inst = self.inst_creator.create(block=True)
+
+        self.assertIsNotNone(vm_inst)
+        vm_inst_get = nova_utils.get_server(
+            admin_nova, admin_neutron, admin_key,
+            vm_inst_settings=instance_settings)
+        self.assertEqual(vm_inst, vm_inst_get)
+
+        self.assertIsNone(nova_utils.get_server(
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings))
+
+        self.assertIsNotNone(self.inst_creator.get_vm_inst().availability_zone)
+        self.assertIsNotNone(self.inst_creator.get_vm_inst().compute_host)
+
+
+class CreateInstanceExternalNetTests(OSIntegrationTestCase):
+    """
+    Simple instance creation tests where the network is external
+    """
+
+    def setUp(self):
+        """
+        Instantiates the CreateImage object that is responsible for downloading
+        and creating an OS image file
+        within OpenStack
+        """
+        super(self.__class__, self).__start__()
+
+        guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.vm_inst_name = guid + '-inst'
+        self.nova = nova_utils.nova_client(self.admin_os_creds)
+        self.neutron = neutron_utils.neutron_client(self.admin_os_creds)
+        os_image_settings = openstack_tests.cirros_image_settings(
+            name=guid + '-image', image_metadata=self.image_metadata)
+
+        # Initialize for tearDown()
+        self.image_creator = None
+        self.flavor_creator = None
+        self.inst_creator = None
+
+        try:
+            # Create Image
+            self.image_creator = OpenStackImage(self.os_creds,
+                                                os_image_settings)
+            self.image_creator.create()
+
+            # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
+            self.flavor_creator = OpenStackFlavor(
+                self.admin_os_creds, flavor_config)
+            self.flavor_creator.create()
+
+            self.port_settings = PortConfig(
+                name=guid + '-port',
+                network_name=self.ext_net_name)
+
+        except Exception as e:
+            self.tearDown()
+            raise e
+
+    def tearDown(self):
+        """
+        Cleans the created object
+        """
+        if self.inst_creator:
+            try:
+                self.inst_creator.clean()
+            except Exception as e:
+                logger.error(
+                    'Unexpected exception cleaning VM instance with message '
+                    '- %s', e)
+
+        if self.flavor_creator:
+            try:
+                self.flavor_creator.clean()
+            except Exception as e:
+                logger.error(
+                    'Unexpected exception cleaning flavor with message - %s',
+                    e)
+
+        if self.image_creator and not self.image_creator.image_settings.exists:
+            try:
+                self.image_creator.clean()
+            except Exception as e:
+                logger.error(
+                    'Unexpected exception cleaning image with message - %s', e)
+
+        super(self.__class__, self).__clean__()
+
+    def test_create_instance_public_net(self):
+        """
+        Tests the creation of an OpenStack instance with a single port to
+        the external network.
+        """
+        instance_settings = VmInstanceConfig(
+            name=self.vm_inst_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            port_settings=[self.port_settings])
+
+        self.inst_creator = OpenStackVmInstance(
+            self.admin_os_creds, instance_settings,
+            self.image_creator.image_settings)
+
+        vm_inst = self.inst_creator.create(block=True)
+        vm_inst_get = nova_utils.get_server(
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings)
+        self.assertEqual(vm_inst, vm_inst_get)
+        ip = self.inst_creator.get_port_ip(self.port_settings.name)
+
+        check_dhcp_lease(self.inst_creator, ip)
+
 
 class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
     """
@@ -538,9 +695,10 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
         Instantiates the CreateImage object that is responsible for downloading
         and creating an OS image file within OpenStack
         """
+        self.proj_users = ['admin']
         super(self.__class__, self).__start__()
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.keypair_priv_filepath = 'tmp/' + guid
         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
@@ -560,6 +718,7 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
         self.inst_creators = list()
 
         self.pub_net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
             router_name=guid + '-pub-router', external_net=self.ext_net_name,
             netconf_override=self.netconf_override)
@@ -582,10 +741,11 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
             self.router_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
-                             vcpus=2, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             self.keypair_creator = OpenStackKeypair(
@@ -816,19 +976,19 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
         # Test default reboot which should be 'SOFT'
         inst_creator.reboot()
         # Lag time to allow for shutdown routine to take effect
-        time.sleep(10)
+        time.sleep(15)
         self.assertTrue(check_dhcp_lease(inst_creator, ip))
         self.assertTrue(validate_ssh_client(inst_creator))
 
         # Test 'SOFT' reboot
         inst_creator.reboot(reboot_type=RebootType.soft)
-        time.sleep(10)
+        time.sleep(15)
         self.assertTrue(check_dhcp_lease(inst_creator, ip))
         self.assertTrue(validate_ssh_client(inst_creator))
 
         # Test 'HARD' reboot
         inst_creator.reboot(reboot_type=RebootType.hard)
-        time.sleep(10)
+        time.sleep(15)
         self.assertTrue(check_dhcp_lease(inst_creator, ip))
         self.assertTrue(validate_ssh_client(inst_creator))
 
@@ -897,9 +1057,35 @@ class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
 
         self.assertTrue(inst_creator.vm_active(block=True))
 
+        vm_os_creds = OSCreds(
+            auth_url=self.admin_os_creds.auth_url,
+            username=self.admin_os_creds.username,
+            password=self.admin_os_creds.password,
+            project_name=self.os_creds.project_name,
+            identity_api_version=self.os_creds.identity_api_version)
         derived_inst_creator = create_instance.generate_creator(
-            self.os_creds, vm_inst, self.image_creator.image_settings,
-            self.keypair_creator.keypair_settings)
+            vm_os_creds, vm_inst, self.image_creator.image_settings,
+            self.os_creds.project_name, self.keypair_creator.keypair_settings)
+
+        # Tests to ensure that a instance can be returned with an invalid
+        # image config object and admin credentials (when the 'admin' user has
+        # been added to the project) as this should not matter unless one
+        # needs to access the machine via ssh and its floating IP
+
+        # Invalid ImageConfig
+        derived_foo_image_creator = create_instance.generate_creator(
+            vm_os_creds, vm_inst, ImageConfig(
+                name='foo', image_user='bar', format='qcow2',
+                image_file='foo/bar'),
+            vm_os_creds.project_name)
+        self.assertIsNotNone(derived_foo_image_creator)
+        self.assertTrue(derived_foo_image_creator.vm_active())
+
+        # None ImageConfig
+        derived_none_image_creator = create_instance.generate_creator(
+            vm_os_creds, vm_inst, None, vm_os_creds.project_name)
+        self.assertIsNotNone(derived_none_image_creator)
+        self.assertTrue(derived_none_image_creator.vm_active())
 
         derived_inst_creator.add_floating_ip(FloatingIpConfig(
             name=self.floating_ip_name, port_name=self.port_1_name,
@@ -966,7 +1152,7 @@ class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
         """
         super(self.__class__, self).__start__()
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.keypair_priv_filepath = 'tmp/' + self.guid
         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
@@ -991,11 +1177,11 @@ class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
                 self.os_creds, os_image_settings)
             self.image_creator.create()
 
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(
-                    name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=2,
-                    metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             self.keypair_creator = OpenStackKeypair(
@@ -1094,7 +1280,10 @@ class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
             name=self.guid + '-net', subnet_settings=[subnet_settings])
         router_settings = RouterConfig(
             name=self.guid + '-router', external_gateway=self.ext_net_name,
-            internal_subnets=[subnet_settings.name])
+            internal_subnets=[{'subnet': {
+                'project_name': self.os_creds.project_name,
+                'network_name': network_settings.name,
+                'subnet_name': subnet_settings.name}}])
 
         # Create Network
         self.network_creator = OpenStackNetwork(
@@ -1142,7 +1331,10 @@ class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
             subnet_settings=[subnet4_settings, subnet6_settings])
         router_settings = RouterConfig(
             name=self.guid + '-router', external_gateway=self.ext_net_name,
-            internal_subnets=[subnet4_settings.name])
+            internal_subnets=[{'subnet': {
+                'project_name': self.os_creds.project_name,
+                'network_name': network_settings.name,
+                'subnet_name': subnet4_settings.name}}])
 
         # Create Network
         self.network_creator = OpenStackNetwork(
@@ -1172,6 +1364,7 @@ class CreateInstanceIPv6NetworkTests(OSIntegrationTestCase):
             keypair_settings=self.keypair_creator.keypair_settings)
 
         self.inst_creator.create(block=True)
+        self.inst_creator.cloud_init_complete(block=True)
         ssh_client = self.inst_creator.ssh_client()
         self.assertIsNotNone(ssh_client)
 
@@ -1189,24 +1382,28 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase):
         """
         super(self.__class__, self).__start__()
 
-        guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.vm_inst_name = guid + '-inst'
-        self.port_1_name = guid + 'port-1'
-        self.port_2_name = guid + 'port-2'
-        self.floating_ip_name = guid + 'fip1'
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.vm_inst_name = self.guid + '-inst'
+        self.port_1_name = self.guid + 'port-1'
+        self.port_2_name = self.guid + 'port-2'
+        self.floating_ip_name = self.guid + 'fip1'
 
         # Initialize for tearDown()
         self.image_creator = None
         self.network_creator = None
+        self.network_creator2 = None
         self.flavor_creator = None
         self.inst_creator = None
 
         self.net_config = openstack_tests.get_priv_net_config(
-            net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
-            router_name=guid + '-pub-router', external_net=self.ext_net_name,
+            project_name=self.os_creds.project_name,
+            net_name=self.guid + '-pub-net',
+            subnet_name=self.guid + '-pub-subnet',
+            router_name=self.guid + '-pub-router',
+            external_net=self.ext_net_name,
             netconf_override=self.netconf_override)
         os_image_settings = openstack_tests.cirros_image_settings(
-            name=guid + '-image', image_metadata=self.image_metadata)
+            name=self.guid + '-image', image_metadata=self.image_metadata)
 
         try:
             # Create Image
@@ -1220,10 +1417,11 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase):
             self.network_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
-                             vcpus=2, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
         except Exception as e:
             self.tearDown()
@@ -1257,6 +1455,14 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase):
                     'Unexpected exception cleaning network with message - %s',
                     e)
 
+        if self.network_creator2:
+            try:
+                self.network_creator2.clean()
+            except Exception as e:
+                logger.error(
+                    'Unexpected exception cleaning network with message - %s',
+                    e)
+
         if self.image_creator and not self.image_creator.image_settings.exists:
             try:
                 self.image_creator.clean()
@@ -1293,6 +1499,86 @@ class CreateInstancePortManipulationTests(OSIntegrationTestCase):
             subnet_name=self.net_config.network_settings.subnet_settings[
                 0].name))
 
+    def test_set_one_port_two_ip_one_subnet(self):
+        """
+        Tests the creation of an OpenStack instance with a single port with a
+        two static IPs on a network with one subnet.
+        """
+        ip1 = '10.55.0.101'
+        ip2 = '10.55.0.102'
+        sub_settings = self.net_config.network_settings.subnet_settings
+        port_settings = PortConfig(
+            name=self.port_1_name,
+            network_name=self.net_config.network_settings.name,
+            ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip1},
+                      {'subnet_name': sub_settings[0].name, 'ip': ip2}])
+
+        instance_settings = VmInstanceConfig(
+            name=self.vm_inst_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            port_settings=[port_settings])
+
+        self.inst_creator = OpenStackVmInstance(
+            self.os_creds, instance_settings,
+            self.image_creator.image_settings)
+        vm_inst = self.inst_creator.create(block=True)
+
+        self.assertEqual(ip1, vm_inst.ports[0].ips[0]['ip_address'])
+        self.assertEqual(self.network_creator.get_network().subnets[0].id,
+                         vm_inst.ports[0].ips[0]['subnet_id'])
+        self.assertEqual(ip2, vm_inst.ports[0].ips[1]['ip_address'])
+        self.assertEqual(self.network_creator.get_network().subnets[0].id,
+                         vm_inst.ports[0].ips[1]['subnet_id'])
+
+    def test_set_one_port_two_ip_two_subnets(self):
+        """
+        Tests the creation of an OpenStack instance with a single port with a
+        two static IPs on a network with one subnet.
+        """
+        net2_config = NetworkConfig(
+            name=self.guid + 'net2', subnets=[
+                SubnetConfig(name=self.guid + '-subnet1', cidr='10.55.0.0/24'),
+                SubnetConfig(name=self.guid + '-subnet2', cidr='10.65.0.0/24'),
+            ])
+
+        # Create Network
+        self.network_creator2 = OpenStackNetwork(self.os_creds, net2_config)
+        net2 = self.network_creator2.create()
+
+        ip1 = '10.55.0.101'
+        ip2 = '10.65.0.101'
+
+        port_settings = PortConfig(
+            name=self.port_1_name,
+            network_name=net2_config.name,
+            ip_addrs=[
+                {'subnet_name': net2_config.subnet_settings[0].name,
+                 'ip': ip1},
+                {'subnet_name': net2_config.subnet_settings[1].name,
+                 'ip': ip2}])
+
+        instance_settings = VmInstanceConfig(
+            name=self.vm_inst_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            port_settings=[port_settings])
+
+        self.inst_creator = OpenStackVmInstance(
+            self.os_creds, instance_settings,
+            self.image_creator.image_settings)
+        vm_inst = self.inst_creator.create(block=True)
+
+        subnet1_id = None
+        subnet2_id = None
+        for subnet in net2.subnets:
+            if subnet.name == net2_config.subnet_settings[0].name:
+                subnet1_id = subnet.id
+            if subnet.name == net2_config.subnet_settings[1].name:
+                subnet2_id = subnet.id
+        self.assertEqual(ip1, vm_inst.ports[0].ips[0]['ip_address'])
+        self.assertEqual(subnet1_id, vm_inst.ports[0].ips[0]['subnet_id'])
+        self.assertEqual(ip2, vm_inst.ports[0].ips[1]['ip_address'])
+        self.assertEqual(subnet2_id, vm_inst.ports[0].ips[1]['subnet_id'])
+
     def test_set_custom_invalid_ip_one_subnet(self):
         """
         Tests the creation of an OpenStack instance with a single port with a
@@ -1501,6 +1787,7 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase):
         self.inst_creators = list()
 
         self.priv_net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet',
             netconf_override=self.netconf_override)
 
@@ -1514,10 +1801,11 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase):
             self.network_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=512, disk=1,
+                vcpus=1, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=512, disk=1,
-                             vcpus=1, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             # Create Image
@@ -1571,7 +1859,8 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase):
         Tests the creation of OpenStack VM instances to each compute node.
         """
         from snaps.openstack.utils import nova_utils
-        nova = nova_utils.nova_client(self.admin_os_creds)
+        nova = nova_utils.nova_client(
+            self.admin_os_creds, self.admin_os_session)
         zone_hosts = nova_utils.get_availability_zone_hosts(nova)
 
         # Create Instance on each server/zone
@@ -1592,7 +1881,11 @@ class CreateInstanceOnComputeHost(OSIntegrationTestCase):
                 self.admin_os_creds, instance_settings,
                 self.image_creator.image_settings)
             self.inst_creators.append(inst_creator)
-            inst_creator.create()
+            inst_creator.create(block=True)
+            avail_zone = inst_creator.get_vm_inst().availability_zone
+            self.assertTrue(avail_zone in zone)
+            compute_host = inst_creator.get_vm_inst().compute_host
+            self.assertTrue(compute_host in zone)
 
         # Validate instances to ensure they've been deployed to the correct
         # server
@@ -1621,7 +1914,7 @@ class InstanceSecurityGroupTests(OSIntegrationTestCase):
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.vm_inst_name = self.guid + '-inst'
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         os_image_settings = openstack_tests.cirros_image_settings(
             name=self.guid + '-image', image_metadata=self.image_metadata)
 
@@ -1631,6 +1924,7 @@ class InstanceSecurityGroupTests(OSIntegrationTestCase):
         self.floating_ip_name = self.guid + 'fip1'
 
         net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=self.guid + '-pub-net',
             subnet_name=self.guid + '-pub-subnet',
             router_name=self.guid + '-pub-router',
@@ -1657,11 +1951,11 @@ class InstanceSecurityGroupTests(OSIntegrationTestCase):
             self.network_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=self.guid + '-flavor-name', ram=256,
-                             disk=10, vcpus=2,
-                             metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             self.port_settings = PortConfig(
@@ -1952,9 +2246,10 @@ class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.image_name = guid
         self.vm_inst_name = guid + '-inst'
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
             router_name=guid + '-pub-router', external_net=self.ext_net_name,
             netconf_override=self.netconf_override)
@@ -1993,10 +2288,11 @@ class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
             self.image_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=256, disk=10,
-                             vcpus=2, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             # Create Network
@@ -2097,6 +2393,7 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase):
         self.inst_creator = None
 
         self.priv_net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=self.guid + '-priv-net',
             subnet_name=self.guid + '-priv-subnet')
         self.port_settings = PortConfig(
@@ -2114,11 +2411,11 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase):
             self.network_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=256, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.os_creds,
-                FlavorConfig(
-                    name=self.guid + '-flavor-name', ram=256, disk=10,
-                    vcpus=1))
+                self.os_creds, flavor_config)
             self.flavor_creator.create()
         except Exception as e:
             self.tearDown()
@@ -2162,6 +2459,8 @@ class CreateInstanceMockOfflineTests(OSComponentTestCase):
         if os.path.exists(self.tmpDir) and os.path.isdir(self.tmpDir):
             shutil.rmtree(self.tmpDir)
 
+        super(self.__class__, self).__clean__()
+
     def test_inst_from_file_image_simple_flat(self):
         """
         Creates a VM instance from a locally sourced file image using simply
@@ -2582,7 +2881,7 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
         self.ip1 = '10.200.201.5'
         self.ip2 = '10.200.202.5'
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         # Initialize for tearDown()
         self.image_creator = None
@@ -2616,13 +2915,14 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
 
         try:
             # Create Image
-            self.image_creator = OpenStackImage(self.os_creds,
-                                                os_image_settings)
+            self.image_creator = OpenStackImage(
+                self.os_creds, os_image_settings)
             self.image_creator.create()
 
             # First network is public
             self.network_creators.append(OpenStackNetwork(
                 self.os_creds, self.net_config_1))
+
             # Second network is private
             self.network_creators.append(OpenStackNetwork(
                 self.os_creds, self.net_config_2))
@@ -2630,47 +2930,47 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
                 network_creator.create()
 
             port_settings = [
-                create_network.PortConfig(
+                PortConfig(
                     name=self.guid + '-router-port1',
                     ip_addrs=[{
                         'subnet_name':
                             self.net_config_1.subnet_settings[0].name,
                         'ip': static_gateway_ip1
                     }],
-                    network_name=self.net_config_1.name,
-                    project_name=self.os_creds.project_name),
-                create_network.PortConfig(
+                    network_name=self.net_config_1.name),
+                PortConfig(
                     name=self.guid + '-router-port2',
                     ip_addrs=[{
                         'subnet_name':
                             self.net_config_2.subnet_settings[0].name,
                         'ip': static_gateway_ip2
                     }],
-                    network_name=self.net_config_2.name,
-                    project_name=self.os_creds.project_name)]
+                    network_name=self.net_config_2.name)]
 
             router_settings = RouterConfig(
                 name=self.guid + '-pub-router', port_settings=port_settings)
-            self.router_creator = create_router.OpenStackRouter(
+            self.router_creator = OpenStackRouter(
                 self.os_creds, router_settings)
             self.router_creator.create()
 
-            # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=self.guid + '-flavor-name', ram=512, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=self.guid + '-flavor-name', ram=512,
-                             disk=10, vcpus=2,
-                             metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
-            sec_grp_name = self.guid + '-sec-grp'
+            self.sec_grp_name = self.guid + '-sec-grp'
             rule1 = SecurityGroupRuleConfig(
-                sec_grp_name=sec_grp_name, direction=Direction.ingress,
+                sec_grp_name=self.sec_grp_name, direction=Direction.ingress,
+                protocol=Protocol.icmp)
+            rule2 = SecurityGroupRuleConfig(
+                sec_grp_name=self.sec_grp_name, direction=Direction.egress,
                 protocol=Protocol.icmp)
             self.sec_grp_creator = OpenStackSecurityGroup(
                 self.os_creds,
                 SecurityGroupConfig(
-                    name=sec_grp_name, rule_settings=[rule1]))
+                    name=self.sec_grp_name, rule_settings=[rule1, rule2]))
             self.sec_grp_creator.create()
         except:
             self.tearDown()
@@ -2750,6 +3050,7 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
             name=self.vm_inst1_name,
             flavor=self.flavor_creator.flavor_settings.name,
             userdata=_get_ping_userdata(self.ip2),
+            security_group_names=self.sec_grp_name,
             port_settings=[PortConfig(
                 name=self.port_1_name,
                 ip_addrs=[{
@@ -2762,6 +3063,7 @@ class CreateInstanceTwoNetTests(OSIntegrationTestCase):
             name=self.vm_inst2_name,
             flavor=self.flavor_creator.flavor_settings.name,
             userdata=_get_ping_userdata(self.ip1),
+            security_group_names=self.sec_grp_name,
             port_settings=[PortConfig(
                 name=self.port_2_name,
                 ip_addrs=[{
@@ -2806,12 +3108,15 @@ class CreateInstanceVolumeTests(OSIntegrationTestCase):
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.vm_inst_name = guid + '-inst'
-        self.nova = nova_utils.nova_client(self.os_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.nova = nova_utils.nova_client(
+            self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
         os_image_settings = openstack_tests.cirros_image_settings(
             name=guid + '-image', image_metadata=self.image_metadata)
 
         net_config = openstack_tests.get_priv_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
             router_name=guid + '-pub-router', external_net=self.ext_net_name,
             netconf_override=self.netconf_override)
@@ -2837,10 +3142,11 @@ class CreateInstanceVolumeTests(OSIntegrationTestCase):
             self.image_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=256, disk=1,
+                vcpus=2, metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(name=guid + '-flavor-name', ram=256, disk=1,
-                             vcpus=2, metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             # Create Network
@@ -2933,7 +3239,8 @@ class CreateInstanceVolumeTests(OSIntegrationTestCase):
 
         vm_inst = self.inst_creator.create(block=True)
         self.assertIsNotNone(nova_utils.get_server(
-            self.nova, self.neutron, vm_inst_settings=instance_settings))
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings))
 
         self.assertIsNotNone(vm_inst)
         self.assertEqual(1, len(vm_inst.volume_ids))
@@ -2957,7 +3264,8 @@ class CreateInstanceVolumeTests(OSIntegrationTestCase):
 
         vm_inst = self.inst_creator.create(block=True)
         self.assertIsNotNone(nova_utils.get_server(
-            self.nova, self.neutron, vm_inst_settings=instance_settings))
+            self.nova, self.neutron, self.keystone,
+            vm_inst_settings=instance_settings))
 
         self.assertIsNotNone(vm_inst)
         self.assertEqual(2, len(vm_inst.volume_ids))
index 63e0bcc..44214d0 100644 (file)
@@ -200,7 +200,7 @@ class CreateKeypairsTests(OSIntegrationTestCase):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.priv_file_path = 'tmp/' + guid
         self.pub_file_path = self.priv_file_path + '.pub'
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.keypair_name = guid
 
         self.keypair_creator = None
@@ -370,7 +370,7 @@ class CreateKeypairsCleanupTests(OSIntegrationTestCase):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.priv_file_path = 'tmp/' + guid
         self.pub_file_path = self.priv_file_path + '.pub'
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.keypair_name = guid
 
         self.keypair_creator = None
index 966cbd0..26c57bd 100644 (file)
@@ -15,6 +15,8 @@
 import unittest
 import uuid
 
+from neutronclient.common.exceptions import BadRequest
+
 from snaps.config.network import (
     NetworkConfig, SubnetConfig, SubnetConfigError, NetworkConfigError,
     PortConfigError, IPv6Mode)
@@ -24,7 +26,7 @@ from snaps.openstack.create_network import (
 from snaps.openstack.tests import openstack_tests
 from snaps.openstack.tests.os_source_file_test import (
     OSIntegrationTestCase, OSComponentTestCase)
-from snaps.openstack.utils import neutron_utils
+from snaps.openstack.utils import neutron_utils, keystone_utils
 from snaps.openstack.utils.tests import neutron_utils_tests
 from snaps.openstack.create_network import IPv6Mode as IPv6Mode_old
 
@@ -136,8 +138,7 @@ class SubnetSettingsUnitTests(unittest.TestCase):
         self.assertIsNone(settings.start)
         self.assertIsNone(settings.end)
         self.assertIsNone(settings.enable_dhcp)
-        self.assertEqual(1, len(settings.dns_nameservers))
-        self.assertEqual('8.8.8.8', settings.dns_nameservers[0])
+        self.assertEqual(0, len(settings.dns_nameservers))
         self.assertIsNone(settings.host_routes)
         self.assertIsNone(settings.destination)
         self.assertIsNone(settings.nexthop)
@@ -154,8 +155,7 @@ class SubnetSettingsUnitTests(unittest.TestCase):
         self.assertIsNone(settings.end)
         self.assertIsNone(settings.gateway_ip)
         self.assertIsNone(settings.enable_dhcp)
-        self.assertEqual(1, len(settings.dns_nameservers))
-        self.assertEqual('8.8.8.8', settings.dns_nameservers[0])
+        self.assertEqual(0, len(settings.dns_nameservers))
         self.assertIsNone(settings.host_routes)
         self.assertIsNone(settings.destination)
         self.assertIsNone(settings.nexthop)
@@ -365,11 +365,15 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.net_config = openstack_tests.get_pub_net_config(
-            net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
-            router_name=guid + '-pub-router', external_net=self.ext_net_name,
+            project_name=self.os_creds.project_name,
+            net_name="{}-{}".format(guid, 'pub-net'), mtu=999,
+            subnet_name="{}-{}".format(guid, 'pub-subnet'),
+            router_name="{}-{}".format(guid, 'pub-router'),
+            external_net=self.ext_net_name,
             netconf_override=self.netconf_override)
 
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.net_creator = None
@@ -392,17 +396,19 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack network without a router.
         """
         # Create Network
-        self.net_creator = OpenStackNetwork(self.os_creds,
-                                            self.net_config.network_settings)
-        self.net_creator.create()
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
+        network = self.net_creator.create()
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, self.net_creator.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name, mtu=999))
 
         # Validate subnets
         self.assertTrue(neutron_utils_tests.validate_subnet(
-            self.neutron,
+            self.neutron, network,
             self.net_creator.network_settings.subnet_settings[0].name,
             self.net_creator.network_settings.subnet_settings[0].cidr, True))
 
@@ -411,18 +417,22 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack network, it's deletion, then cleanup
         """
         # Create Network
-        self.net_creator = OpenStackNetwork(self.os_creds,
-                                            self.net_config.network_settings)
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
         self.net_creator.create()
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, self.net_creator.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name, mtu=999))
 
-        neutron_utils.delete_network(self.neutron,
-                                     self.net_creator.get_network())
+        neutron_utils.delete_network(
+            self.neutron, self.net_creator.get_network())
         self.assertIsNone(neutron_utils.get_network(
-            self.neutron, network_settings=self.net_creator.network_settings))
+            self.neutron, self.keystone,
+            network_settings=self.net_creator.network_settings,
+            project_name=self.os_creds.project_name))
 
         # This shall not throw an exception here
         self.net_creator.clean()
@@ -432,9 +442,9 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack network with a router.
         """
         # Create Network
-        self.net_creator = OpenStackNetwork(self.os_creds,
-                                            self.net_config.network_settings)
-        self.net_creator.create()
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
+        network = self.net_creator.create()
 
         # Create Router
         self.router_creator = create_router.OpenStackRouter(
@@ -443,17 +453,21 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, self.net_creator.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name, mtu=999))
 
         # Validate subnets
         self.assertTrue(neutron_utils_tests.validate_subnet(
-            self.neutron,
+            self.neutron, network,
             self.net_creator.network_settings.subnet_settings[0].name,
             self.net_creator.network_settings.subnet_settings[0].cidr, True))
 
         # Validate routers
         neutron_utils_tests.validate_router(
-            self.neutron, self.router_creator.router_settings.name, True)
+            self.neutron, self.keystone,
+            self.router_creator.router_settings.name,
+            self.os_creds.project_name, True)
 
         neutron_utils_tests.validate_interface_router(
             self.router_creator.get_internal_router_interface(),
@@ -466,12 +480,12 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         OpenStackNetwork object will not create a second.
         """
         # Create Network
-        self.net_creator = OpenStackNetwork(self.os_creds,
-                                            self.net_config.network_settings)
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
         self.net_creator.create()
 
-        self.net_creator2 = OpenStackNetwork(self.os_creds,
-                                             self.net_config.network_settings)
+        self.net_creator2 = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
         self.net_creator2.create()
 
         self.assertEqual(self.net_creator.get_network().id,
@@ -479,31 +493,42 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
 
     def test_create_network_router_admin_user_to_new_project(self):
         """
-        Tests the creation of an OpenStack network and router with the current
-        user to the admin project.
+        Tests the creation of an OpenStack network to the the current using
+        the credentials to the admin project.
         """
         # Create Network/Subnet where the project names have been changed
-        admin_project_name = self.admin_os_creds.project_name
-        self.net_config.network_settings.project_name = admin_project_name
-        self.net_config.network_settings.subnet_settings[0].project_name = \
-            admin_project_name
-        self.net_creator = OpenStackNetwork(self.os_creds,
-                                            self.net_config.network_settings)
+        project_name = self.os_creds.project_name
+        config = self.net_config.network_settings
+        config.project_name = project_name
+        config.subnet_settings[0].project_name = project_name
+
+        self.net_creator = OpenStackNetwork(self.admin_os_creds, config)
         self.net_creator.create()
 
         retrieved_net = neutron_utils.get_network(
-            self.neutron, network_settings=self.net_config.network_settings)
+            self.neutron, self.keystone,
+            network_name=self.net_config.network_settings.name,
+            project_name=self.os_creds.project_name)
 
         self.assertEqual(self.net_creator.get_network().id, retrieved_net.id)
 
+        # Initialize with actual credentials
+        config.project_name = None
+        config.subnet_settings[0].project_name = None
+        proj_net_creator = OpenStackNetwork(self.os_creds, config)
+        proj_net = proj_net_creator.create()
+        self.assertEqual(retrieved_net, proj_net)
+
         # Create Router
-        self.net_config.router_settings.project_name = admin_project_name
+        self.net_config.router_settings.project_name = project_name
         self.router_creator = create_router.OpenStackRouter(
-            self.os_creds, self.net_config.router_settings)
+            self.admin_os_creds, self.net_config.router_settings)
         self.router_creator.create()
 
         retrieved_router = neutron_utils.get_router(
-            self.neutron, router_settings=self.router_creator.router_settings)
+            self.neutron, self.keystone,
+            router_settings=self.router_creator.router_settings,
+            project_name=self.os_creds.project_name)
         self.assertEqual(
             self.router_creator.get_router().id, retrieved_router.id)
 
@@ -517,12 +542,14 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         self.net_config.network_settings.project_name = new_project_name
         self.net_config.network_settings.subnet_settings[0].project_name = \
             new_project_name
-        self.net_creator = OpenStackNetwork(self.admin_os_creds,
-                                            self.net_config.network_settings)
+        self.net_creator = OpenStackNetwork(
+            self.admin_os_creds, self.net_config.network_settings)
         self.net_creator.create()
 
         retrieved_net = neutron_utils.get_network(
-            self.neutron, network_settings=self.net_config.network_settings)
+            self.neutron, self.keystone,
+            network_settings=self.net_config.network_settings,
+            project_name=self.os_creds.project_name)
 
         self.assertEqual(self.net_creator.get_network().id, retrieved_net.id)
 
@@ -533,14 +560,149 @@ class CreateNetworkSuccessTests(OSIntegrationTestCase):
         self.router_creator.create()
 
         retrieved_router = neutron_utils.get_router(
-            self.neutron, router_settings=self.router_creator.router_settings)
+            self.neutron, self.keystone,
+            router_settings=self.router_creator.router_settings,
+            project_name=self.os_creds.project_name)
         self.assertEqual(
             self.router_creator.get_router().id, retrieved_router.id)
 
 
+class CreateNetworkGatewayTests(OSIntegrationTestCase):
+    """
+    Test for the CreateNetwork class defined in create_nework.py
+    """
+
+    def setUp(self):
+        """
+        Sets up object for test
+        """
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+        self.ip_prfx = '10.1.0.'
+
+        # Initialize for cleanup
+        self.net_creator = None
+
+    def tearDown(self):
+        """
+        Cleans the network
+        """
+        if self.net_creator:
+            self.net_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_create_subnet_default_gateway_ip(self):
+        """
+        Tests the creation of an OpenStack network with a subnet that has a
+        default value assigned to the gateway IP.
+        """
+        # Create Network
+        subnet_config = SubnetConfig(
+            name=self.guid + '-subnet', cidr=self.ip_prfx + '0/24')
+        net_config = NetworkConfig(
+            name=self.guid + '-net', subnets=[subnet_config])
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, net_config)
+        out_net = self.net_creator.create()
+
+        # Validate network was created
+        self.assertTrue(neutron_utils_tests.validate_network(
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name))
+
+        # Validate subnets
+        self.assertTrue(neutron_utils_tests.validate_subnet(
+            self.neutron, out_net,
+            self.net_creator.network_settings.subnet_settings[0].name,
+            self.net_creator.network_settings.subnet_settings[0].cidr, True))
+
+        self.assertEqual(self.ip_prfx + '1', out_net.subnets[0].gateway_ip)
+
+    def test_create_subnet_valid_gateway_ip(self):
+        """
+        Tests the creation of an OpenStack network with a subnet that has a
+        valid value assigned to the gateway IP.
+        """
+        # Create Network
+        subnet_config = SubnetConfig(
+            name=self.guid + '-subnet', cidr=self.ip_prfx + '0/24',
+            gateway_ip=self.ip_prfx + '2')
+        net_config = NetworkConfig(
+            name=self.guid + '-net', subnets=[subnet_config])
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, net_config)
+        out_net = self.net_creator.create()
+
+        self.assertIsNotNone(out_net)
+
+        get_net = neutron_utils.get_network_by_id(self.neutron, out_net.id)
+        self.assertIsNotNone(get_net)
+
+        # Validate subnets
+        self.assertTrue(neutron_utils_tests.validate_subnet(
+            self.neutron, out_net,
+            self.net_creator.network_settings.subnet_settings[0].name,
+            self.net_creator.network_settings.subnet_settings[0].cidr, True))
+
+        self.assertEqual(self.ip_prfx + '2', out_net.subnets[0].gateway_ip)
+
+    def test_create_subnet_no_gateway(self):
+        """
+        Tests the creation of an OpenStack network with a subnet that has a
+        valid value assigned to the gateway IP.
+        """
+        # Create Network
+        subnet_config = SubnetConfig(
+            name=self.guid + '-subnet', cidr=self.ip_prfx + '0/24',
+            gateway_ip='none')
+        net_config = NetworkConfig(
+            name=self.guid + '-net', subnets=[subnet_config])
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, net_config)
+        out_net = self.net_creator.create()
+
+        # Validate network was created
+        self.assertTrue(neutron_utils_tests.validate_network(
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name))
+
+        # Validate subnets
+        self.assertTrue(neutron_utils_tests.validate_subnet(
+            self.neutron, out_net,
+            self.net_creator.network_settings.subnet_settings[0].name,
+            self.net_creator.network_settings.subnet_settings[0].cidr, True))
+
+        self.assertIsNone(out_net.subnets[0].gateway_ip)
+
+    def test_create_subnet_invalid_gateway_ip(self):
+        """
+        Tests the creation of an OpenStack network with a subnet that has an
+        invalid value assigned to the gateway IP.
+        """
+        # Create Network
+        subnet_config = SubnetConfig(
+            name=self.guid + '-subnet', cidr=self.ip_prfx + '0/24',
+            gateway_ip='foo')
+        net_config = NetworkConfig(
+            name=self.guid + '-net', subnets=[subnet_config])
+        self.net_creator = OpenStackNetwork(
+            self.os_creds, net_config)
+
+        with self.assertRaises(BadRequest):
+            self.net_creator.create()
+
+
 class CreateNetworkIPv6Tests(OSIntegrationTestCase):
     """
-    Test for the CreateNetwork class defined in create_nework.py when 
+    Test for the CreateNetwork class defined in create_nework.py when
     """
 
     def setUp(self):
@@ -550,7 +712,8 @@ class CreateNetworkIPv6Tests(OSIntegrationTestCase):
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.net_creator = None
@@ -580,7 +743,9 @@ class CreateNetworkIPv6Tests(OSIntegrationTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, self.net_creator.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_creator.network_settings.name, True,
+            self.os_creds.project_name))
 
         network = self.net_creator.get_network()
         self.assertEqual(1, len(network.subnets))
@@ -627,7 +792,7 @@ class CreateNetworkIPv6Tests(OSIntegrationTestCase):
         self.assertEqual(subnet4_settings.name, subnet4.name)
         self.assertEqual(subnet4_settings.cidr, subnet4.cidr)
         self.assertEqual(4, subnet4.ip_version)
-        self.assertEqual(1, len(subnet4.dns_nameservers))
+        self.assertEqual(0, len(subnet4.dns_nameservers))
 
         # Validate IPv6 subnet
         self.assertEqual(network.id, subnet6.network_id)
@@ -649,9 +814,13 @@ class CreateNetworkTypeTests(OSComponentTestCase):
         """
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet')
 
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.net_creator = None
@@ -663,6 +832,8 @@ class CreateNetworkTypeTests(OSComponentTestCase):
         if self.net_creator:
             self.net_creator.clean()
 
+        super(self.__class__, self).__clean__()
+
     def test_create_network_type_vlan(self):
         """
         Tests the creation of an OpenStack network of type vlan.
@@ -680,7 +851,8 @@ class CreateNetworkTypeTests(OSComponentTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, net_settings.name, True))
+            self.neutron, self.keystone, net_settings.name, True,
+            self.os_creds.project_name))
 
         self.assertEquals(network_type, network.type)
 
@@ -709,7 +881,8 @@ class CreateNetworkTypeTests(OSComponentTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, net_settings.name, True))
+            self.neutron, self.keystone, net_settings.name, True,
+            self.os_creds.project_name))
 
         self.assertEquals(network_type, network.type)
 
@@ -730,7 +903,8 @@ class CreateNetworkTypeTests(OSComponentTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, net_settings.name, True))
+            self.neutron, self.keystone, net_settings.name, True,
+            self.os_creds.project_name))
 
         self.assertEqual(network_type, network.type)
 
@@ -753,7 +927,8 @@ class CreateNetworkTypeTests(OSComponentTestCase):
 
         # Validate network was created
         self.assertTrue(neutron_utils_tests.validate_network(
-            self.neutron, net_settings.name, True))
+            self.neutron, self.keystone, net_settings.name, True,
+            self.os_creds.project_name))
 
         self.assertEquals(network_type, network.type)
 
@@ -771,3 +946,94 @@ class CreateNetworkTypeTests(OSComponentTestCase):
         self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
         with self.assertRaises(Exception):
             self.net_creator.create()
+
+
+class CreateMultipleNetworkTests(OSIntegrationTestCase):
+    """
+    Test for the CreateNetwork class and how it interacts with networks
+    groups within other projects with the same name
+    """
+
+    def setUp(self):
+        """
+        Sets up object for test
+        """
+        super(self.__class__, self).__start__()
+
+        guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
+            net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet')
+
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+        # Initialize for cleanup
+        self.admin_net_creator = None
+        self.proj_net_creator = None
+
+    def tearDown(self):
+        """
+        Cleans the network
+        """
+        if self.admin_net_creator:
+            self.admin_net_creator.clean()
+        if self.proj_net_creator:
+            self.proj_net_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_network_same_name_diff_proj(self):
+        """
+        Tests the creation of an OpenStackNetwork with the same name
+        within a different project/tenant when not configured but implied by
+        the OSCreds.
+        """
+        # Create Network
+
+        self.admin_net_creator = OpenStackNetwork(
+            self.admin_os_creds, self.net_config.network_settings)
+        self.admin_net_creator.create()
+
+        self.proj_net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
+        self.proj_net_creator.create()
+
+        self.assertNotEqual(
+            self.admin_net_creator.get_network().id,
+            self.proj_net_creator.get_network().id)
+
+        admin_creator2 = OpenStackNetwork(
+            self.admin_os_creds, self.net_config.network_settings)
+        admin_creator2.create()
+        self.assertEqual(
+            self.admin_net_creator.get_network(), admin_creator2.get_network())
+
+        proj_creator2 = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
+        proj_creator2.create()
+        self.assertEqual(self.proj_net_creator.get_network(),
+                         proj_creator2.get_network())
+
+    def test_network_create_by_admin_to_different_project(self):
+        """
+        Tests the creation of an OpenStackNetwork by the admin user and
+        initialize again with tenant credentials.
+        """
+        # Create Network
+
+        net_settings = self.net_config.network_settings
+
+        net_settings.project_name = self.os_creds.project_name
+
+        self.admin_net_creator = OpenStackNetwork(
+            self.admin_os_creds, net_settings)
+        self.admin_net_creator.create()
+
+        self.proj_net_creator = OpenStackNetwork(
+            self.os_creds, self.net_config.network_settings)
+        self.proj_net_creator.create()
+
+        self.assertEqual(
+            self.admin_net_creator.get_network().id,
+            self.proj_net_creator.get_network().id)
index 2c10311..1e3a972 100644 (file)
@@ -99,7 +99,8 @@ class CreateProjectSuccessTests(OSComponentTestCase):
             name=guid + '-name',
             domain=self.os_creds.project_domain_name)
 
-        self.keystone = keystone_utils.keystone_client(self.os_creds)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.project_creator = None
@@ -111,6 +112,8 @@ class CreateProjectSuccessTests(OSComponentTestCase):
         if self.project_creator:
             self.project_creator.clean()
 
+        super(self.__class__, self).__clean__()
+
     def test_create_project_bad_domain(self):
         """
         Tests the creation of an OpenStack project with an invalid domain
@@ -140,6 +143,38 @@ class CreateProjectSuccessTests(OSComponentTestCase):
         self.assertTrue(validate_project(self.keystone, self.project_settings,
                                          created_project))
 
+    def test_create_project_quota_override(self):
+        """
+        Tests the creation of an OpenStack project with new quotas.
+        """
+        quotas = {
+            'cores': 4, 'instances': 5, 'injected_files': 6,
+            'injected_file_content_bytes': 60000, 'ram': 70000, 'fixed_ips': 7,
+            'key_pairs': 8}
+        self.project_settings.quotas = quotas
+        self.project_creator = OpenStackProject(self.os_creds,
+                                                self.project_settings)
+        created_project = self.project_creator.create()
+        self.assertIsNotNone(created_project)
+
+        retrieved_project = keystone_utils.get_project(
+            keystone=self.keystone, project_settings=self.project_settings)
+        self.assertIsNotNone(retrieved_project)
+        self.assertEqual(created_project, retrieved_project)
+        self.assertTrue(validate_project(self.keystone, self.project_settings,
+                                         created_project))
+
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
+        new_quotas = nova_utils.get_compute_quotas(nova, created_project.id)
+
+        self.assertEqual(4, new_quotas.cores)
+        self.assertEqual(5, new_quotas.instances)
+        self.assertEqual(6, new_quotas.injected_files)
+        self.assertEqual(60000, new_quotas.injected_file_content_bytes)
+        self.assertEqual(70000, new_quotas.ram)
+        self.assertEqual(7, new_quotas.fixed_ips)
+        self.assertEqual(8, new_quotas.key_pairs)
+
     def test_create_project_2x(self):
         """
         Tests the creation of an OpenStack project twice to ensure it only
@@ -214,12 +249,12 @@ class CreateProjectSuccessTests(OSComponentTestCase):
         self.assertEqual(update_network_quotas,
                          self.project_creator.get_network_quotas())
 
-        nova = nova_utils.nova_client(self.os_creds)
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
         new_compute_quotas = nova_utils.get_compute_quotas(
             nova, self.project_creator.get_project().id)
         self.assertEqual(update_compute_quotas, new_compute_quotas)
 
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
         new_network_quotas = neutron_utils.get_network_quotas(
             neutron, self.project_creator.get_project().id)
         self.assertEqual(update_network_quotas, new_network_quotas)
@@ -241,7 +276,8 @@ class CreateProjectUserTests(OSComponentTestCase):
             name=self.guid + '-name',
             domain=self.os_creds.project_domain_name)
 
-        self.keystone = keystone_utils.keystone_client(self.os_creds)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.project_creator = None
@@ -262,6 +298,8 @@ class CreateProjectUserTests(OSComponentTestCase):
         if self.project_creator:
             self.project_creator.clean()
 
+        super(self.__class__, self).__clean__()
+
     def test_create_project_sec_grp_one_user(self):
         """
         Tests the creation of an OpenStack object to a project with a new users
index 68737f8..b3d7979 100644 (file)
@@ -122,12 +122,14 @@ class CreateQoSTests(OSIntegrationTestCase):
         super(self.__class__, self).__start__()
 
         guid = uuid.uuid4()
-        self.qos_settings = QoSConfig(
+        qos_settings = QoSConfig(
             name=self.__class__.__name__ + '-' + str(guid),
             consumer=Consumer.both)
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
-        self.qos_creator = None
+        self.cinder = cinder_utils.cinder_client(
+            self.admin_os_creds, self.admin_os_session)
+        self.qos_creator = create_qos.OpenStackQoS(
+            self.admin_os_creds, qos_settings)
 
     def tearDown(self):
         """
@@ -143,13 +145,11 @@ class CreateQoSTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack qos.
         """
         # Create QoS
-        self.qos_creator = create_qos.OpenStackQoS(
-            self.os_creds, self.qos_settings)
         created_qos = self.qos_creator.create()
         self.assertIsNotNone(created_qos)
 
         retrieved_qos = cinder_utils.get_qos(
-            self.cinder, qos_settings=self.qos_settings)
+            self.cinder, qos_settings=self.qos_creator.qos_settings)
 
         self.assertIsNotNone(retrieved_qos)
         self.assertEqual(created_qos, retrieved_qos)
@@ -160,13 +160,11 @@ class CreateQoSTests(OSIntegrationTestCase):
         clean() does not raise an Exception.
         """
         # Create QoS
-        self.qos_creator = create_qos.OpenStackQoS(
-            self.os_creds, self.qos_settings)
         created_qos = self.qos_creator.create()
         self.assertIsNotNone(created_qos)
 
         retrieved_qos = cinder_utils.get_qos(
-            self.cinder, qos_settings=self.qos_settings)
+            self.cinder, qos_settings=self.qos_creator.qos_settings)
         self.assertIsNotNone(retrieved_qos)
         self.assertEqual(created_qos, retrieved_qos)
 
@@ -174,7 +172,7 @@ class CreateQoSTests(OSIntegrationTestCase):
         cinder_utils.delete_qos(self.cinder, created_qos)
 
         self.assertIsNone(cinder_utils.get_qos(
-            self.cinder, qos_settings=self.qos_settings))
+            self.cinder, qos_settings=self.qos_creator.qos_settings))
 
         # Must not raise an exception when attempting to cleanup non-existent
         # qos
@@ -186,16 +184,14 @@ class CreateQoSTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack qos when one already exists.
         """
         # Create QoS
-        self.qos_creator = create_qos.OpenStackQoS(
-            self.os_creds, self.qos_settings)
         qos1 = self.qos_creator.create()
 
         retrieved_qos = cinder_utils.get_qos(
-            self.cinder, qos_settings=self.qos_settings)
+            self.cinder, qos_settings=self.qos_creator.qos_settings)
         self.assertEqual(qos1, retrieved_qos)
 
         # Should be retrieving the instance data
         os_qos_2 = create_qos.OpenStackQoS(
-            self.os_creds, self.qos_settings)
+            self.admin_os_creds, self.qos_creator.qos_settings)
         qos2 = os_qos_2.create()
         self.assertEqual(qos1, qos2)
index 09471a3..a305cf8 100644 (file)
 import unittest
 import uuid
 
-from snaps.config.network import PortConfig, NetworkConfig
+from snaps.config.network import PortConfig, NetworkConfig, PortConfigError
 from snaps.config.router import RouterConfigError, RouterConfig
+from snaps.config.security_group import SecurityGroupConfig
 from snaps.openstack import create_network
 from snaps.openstack import create_router
 from snaps.openstack.create_network import OpenStackNetwork
-from snaps.openstack.create_router import RouterSettings
+from snaps.openstack.create_router import (
+    RouterSettings, OpenStackRouter, RouterCreationError)
+from snaps.openstack.create_security_group import OpenStackSecurityGroup
 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
-from snaps.openstack.utils import neutron_utils, settings_utils
+from snaps.openstack.utils import neutron_utils, settings_utils, keystone_utils
 
 __author__ = 'mmakati'
 
 cidr1 = '10.200.201.0/24'
 cidr2 = '10.200.202.0/24'
+cidr3 = '10.200.203.0/24'
 static_gateway_ip1 = '10.200.201.1'
 static_gateway_ip2 = '10.200.202.1'
 
@@ -128,7 +132,8 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
         self.router_creator = None
         self.network_creator1 = None
         self.network_creator2 = None
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -152,12 +157,13 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
         router_settings = RouterConfig(
             name=self.guid + '-pub-router', external_gateway=self.ext_net_name)
 
-        self.router_creator = create_router.OpenStackRouter(self.os_creds,
-                                                            router_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
         self.router_creator.create()
 
-        router = neutron_utils.get_router(self.neutron,
-                                          router_settings=router_settings)
+        router = neutron_utils.get_router(
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(router)
 
         self.assertEqual(self.router_creator.get_router(), router)
@@ -177,32 +183,34 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
             self.admin_os_creds, router_settings)
         self.router_creator.create()
 
-        router = neutron_utils.get_router(self.neutron,
-                                          router_settings=router_settings)
+        router = neutron_utils.get_router(
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(router)
 
-        self.assertEqual(self.router_creator.get_router(), router)
+        self.assertEqual(self.router_creator.get_router().id, router.id)
 
         self.check_router_recreation(router, router_settings)
 
-    def test_create_router_new_user_to_admin_project(self):
+    def test_create_router_new_user_as_admin_project(self):
         """
         Test creation of a most basic router with the new user pointing
         to the admin project.
         """
         router_settings = RouterConfig(
             name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
-            project_name=self.admin_os_creds.project_name)
+            project_name=self.os_creds.project_name)
 
         self.router_creator = create_router.OpenStackRouter(
-            self.os_creds, router_settings)
+            self.admin_os_creds, router_settings)
         self.router_creator.create()
 
-        router = neutron_utils.get_router(self.neutron,
-                                          router_settings=router_settings)
+        router = neutron_utils.get_router(
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(router)
 
-        self.assertEqual(self.router_creator.get_router(), router)
+        self.assertEqual(self.router_creator.get_router().id, router.id)
 
         self.check_router_recreation(router, router_settings)
 
@@ -219,18 +227,67 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
         created_router = self.router_creator.create()
         self.assertIsNotNone(created_router)
         retrieved_router = neutron_utils.get_router(
-            self.neutron, router_settings=self.router_settings)
+            self.neutron, self.keystone, router_settings=self.router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(retrieved_router)
 
         neutron_utils.delete_router(self.neutron, created_router)
 
         retrieved_router = neutron_utils.get_router(
-            self.neutron, router_settings=self.router_settings)
+            self.neutron, self.keystone, router_settings=self.router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNone(retrieved_router)
 
         # Should not raise an exception
         self.router_creator.clean()
 
+    def test_create_with_internal_sub(self):
+        """
+        Test internal_subnets works.
+        """
+        network_settings1 = NetworkConfig(
+            name=self.guid + '-pub-net1',
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-pub-subnet1',
+                    gateway_ip=static_gateway_ip1)])
+        self.network_creator1 = OpenStackNetwork(self.os_creds,
+                                                 network_settings1)
+
+        self.network_creator1.create()
+        self.router_settings = RouterConfig(
+            name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
+            internal_subnets=[network_settings1.subnet_settings[0].name])
+
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, self.router_settings)
+        created_router = self.router_creator.create()
+        self.assertIsNotNone(created_router)
+
+    def test_create_with_invalid_internal_sub(self):
+        """
+        Test adding an internal subnet owned by admin which should fail.
+        """
+        network_settings1 = NetworkConfig(
+            name=self.guid + '-pub-net1',
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-pub-subnet1',
+                    gateway_ip=static_gateway_ip1)])
+        self.network_creator1 = OpenStackNetwork(self.admin_os_creds,
+                                                 network_settings1)
+
+        self.network_creator1.create()
+        self.router_settings = RouterConfig(
+            name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
+            internal_subnets=[network_settings1.subnet_settings[0].name])
+
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, self.router_settings)
+
+        with self.assertRaises(RouterCreationError):
+            self.router_creator.create()
+
     def test_create_router_admin_state_false(self):
         """
         Test creation of a basic router with admin state down.
@@ -242,8 +299,9 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
                                                             router_settings)
         self.router_creator.create()
 
-        router = neutron_utils.get_router(self.neutron,
-                                          router_settings=router_settings)
+        router = neutron_utils.get_router(
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(router)
 
         self.assertEqual(self.router_creator.get_router(), router)
@@ -262,7 +320,8 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
         self.router_creator.create()
 
         router = neutron_utils.get_router(
-            self.neutron, router_settings=router_settings)
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(router)
 
         self.assertEqual(self.router_creator.get_router(), router)
@@ -303,25 +362,24 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
                         network_settings1.subnet_settings[0].name,
                     'ip': static_gateway_ip1
                 }],
-                network_name=network_settings1.name,
-                project_name=self.os_creds.project_name),
+                network_name=network_settings1.name),
             create_network.PortConfig(
                 name=self.guid + '-port2',
                 ip_addrs=[{
                     'subnet_name': network_settings2.subnet_settings[0].name,
                     'ip': static_gateway_ip2
                 }],
-                network_name=network_settings2.name,
-                project_name=self.os_creds.project_name)]
+                network_name=network_settings2.name)]
 
         router_settings = RouterConfig(
             name=self.guid + '-pub-router', port_settings=port_settings)
-        self.router_creator = create_router.OpenStackRouter(self.os_creds,
-                                                            router_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
         self.router_creator.create()
 
         router = neutron_utils.get_router(
-            self.neutron, router_settings=router_settings)
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
 
         self.assertEqual(router, self.router_creator.get_router())
 
@@ -355,8 +413,7 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
                 ip_addrs=[{
                     'subnet_name': network_settings.subnet_settings[0].name,
                     'ip': static_gateway_ip1}],
-                network_name=network_settings.name,
-                project_name=self.os_creds.project_name)]
+                network_name=network_settings.name)]
 
         router_settings = RouterConfig(
             name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
@@ -366,12 +423,58 @@ class CreateRouterSuccessTests(OSIntegrationTestCase):
         self.router_creator.create()
 
         router = neutron_utils.get_router(
-            self.neutron, router_settings=router_settings)
+            self.neutron, self.keystone, router_settings=router_settings,
+            project_name=self.os_creds.project_name)
 
         self.assertEquals(router, self.router_creator.get_router())
 
         self.check_router_recreation(router, router_settings)
 
+    def test_create_router_with_ext_port(self):
+        """
+        Test creation of a router with a port to an external network as an
+        'admin' user.
+        """
+        port_settings = [
+            create_network.PortConfig(
+                name=self.guid + '-port1',
+                network_name=self.ext_net_name)]
+
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router', port_settings=port_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.admin_os_creds, router_settings)
+        self.router_creator.create()
+
+        admin_neutron = neutron_utils.neutron_client(
+            self.admin_os_creds, self.admin_os_session)
+        admin_keystone = keystone_utils.keystone_client(
+            self.admin_os_creds, self.admin_os_session)
+        router = neutron_utils.get_router(
+            admin_neutron, admin_keystone, router_settings=router_settings,
+            project_name=self.admin_os_creds.project_name)
+
+        self.assertIsNotNone(router)
+        self.assertEquals(router, self.router_creator.get_router())
+
+        ext_net = neutron_utils.get_network(
+            admin_neutron, admin_keystone, network_name=self.ext_net_name)
+
+        self.assertIsNotNone(ext_net)
+        self.assertIsNotNone(router.port_subnets)
+
+        id_found = False
+        for port, subnets in router.port_subnets:
+            self.assertIsNotNone(subnets)
+            self.assertIsNotNone(port)
+
+            if ext_net.id == port.network_id:
+                id_found = True
+                for subnet in subnets:
+                    self.assertIsNotNone(subnet)
+                    self.assertEqual(ext_net.id, subnet.network_id)
+        self.assertTrue(id_found)
+
     def check_router_recreation(self, router, orig_settings):
         """
         Validates the derived RouterConfig with the original
@@ -421,6 +524,7 @@ class CreateRouterNegativeTests(OSIntegrationTestCase):
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.network_creator = None
         self.router_creator = None
 
     def tearDown(self):
@@ -430,6 +534,9 @@ class CreateRouterNegativeTests(OSIntegrationTestCase):
         if self.router_creator:
             self.router_creator.clean()
 
+        if self.network_creator:
+            self.network_creator.clean()
+
         super(self.__class__, self).__clean__()
 
     def test_create_router_noname(self):
@@ -454,3 +561,313 @@ class CreateRouterNegativeTests(OSIntegrationTestCase):
             self.router_creator = create_router.OpenStackRouter(
                 self.os_creds, router_settings)
             self.router_creator.create()
+
+    def test_create_router_admin_ports(self):
+        """
+        Test creation of a router with ports to subnets owned by the admin
+        project
+        """
+        network_settings = NetworkConfig(
+            name=self.guid + '-pub-net1',
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-pub-subnet1',
+                    gateway_ip=static_gateway_ip1)])
+        self.network_creator = OpenStackNetwork(
+            self.admin_os_creds, network_settings)
+        self.network_creator.create()
+
+        port_settings = [
+            create_network.PortConfig(
+                name=self.guid + '-port1',
+                ip_addrs=[{
+                    'subnet_name': network_settings.subnet_settings[0].name,
+                    'ip': static_gateway_ip1}],
+                network_name=network_settings.name)]
+
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
+            port_settings=port_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
+
+        with self.assertRaises(PortConfigError):
+            self.router_creator.create()
+
+
+class CreateMultipleRouterTests(OSIntegrationTestCase):
+    """
+    Test for the OpenStackRouter class and how it interacts with routers
+    groups within other projects with the same name
+    """
+
+    def setUp(self):
+        """
+        Initializes objects used for router testing
+        """
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.admin_router_creator = None
+        self.proj_router_creator = None
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+        network_settings = NetworkConfig(
+            name=self.guid + '-pub-net', shared=True,
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-pub-subnet',
+                    gateway_ip=static_gateway_ip1)])
+
+        self.network_creator = OpenStackNetwork(
+            self.admin_os_creds, network_settings)
+        self.network_creator.create()
+
+    def tearDown(self):
+        """
+        Cleans the remote OpenStack objects used for router testing
+        """
+        if self.admin_router_creator:
+            self.admin_router_creator.clean()
+
+        if self.proj_router_creator:
+            self.proj_router_creator.clean()
+
+        if self.network_creator:
+            self.network_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_router_same_name_diff_proj(self):
+        """
+        Tests the creation of an OpenStackNetwork with the same name
+        within a different project/tenant when not configured but implied by
+        the OSCreds.
+        """
+        # Create Router
+
+        router_config = RouterConfig(name=self.guid + '-router')
+        self.admin_router_creator = OpenStackRouter(
+            self.admin_os_creds, router_config)
+        self.admin_router_creator.create()
+
+        self.proj_router_creator = OpenStackRouter(
+            self.os_creds, router_config)
+        self.proj_router_creator.create()
+
+        self.assertNotEqual(
+            self.admin_router_creator.get_router().id,
+            self.proj_router_creator.get_router().id)
+
+        admin_creator2 = OpenStackRouter(
+            self.admin_os_creds, router_config)
+        admin_creator2.create()
+        self.assertEqual(
+            self.admin_router_creator.get_router(),
+            admin_creator2.get_router())
+
+        proj_creator2 = OpenStackRouter(self.os_creds, router_config)
+        proj_creator2.create()
+        self.assertEqual(self.proj_router_creator.get_router(),
+                         proj_creator2.get_router())
+
+    def test_router_create_by_admin_to_different_project(self):
+        """
+        Tests the creation of an OpenStackRouter by the admin user and
+        initialize again with tenant credentials.
+        """
+        # Create Network
+
+        admin_router_config = RouterConfig(
+            name=self.guid + '-router',
+            project_name=self.os_creds.project_name)
+
+        self.admin_router_creator = OpenStackRouter(
+            self.admin_os_creds, admin_router_config)
+        self.admin_router_creator.create()
+
+        proj_router_config = RouterConfig(
+            name=self.guid + '-router',
+            project_name=self.os_creds.project_name)
+
+        self.proj_router_creator = OpenStackRouter(
+            self.os_creds, proj_router_config)
+        self.proj_router_creator.create()
+
+        self.assertEqual(
+            self.admin_router_creator.get_router().id,
+            self.proj_router_creator.get_router().id)
+
+
+class CreateRouterSecurityGroupTests(OSIntegrationTestCase):
+    """
+    Class for testing routers with ports containing security groups
+    """
+
+    def setUp(self):
+        """
+        Initializes objects used for router testing
+        """
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.router_creator = None
+        self.network_creator = None
+
+        self.sec_grp_creator = OpenStackSecurityGroup(
+            self.os_creds, SecurityGroupConfig(name=self.guid + '-sec_grp'))
+        self.sec_grp_creator.create()
+
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+    def tearDown(self):
+        """
+        Cleans the remote OpenStack objects used for router testing
+        """
+        if self.router_creator:
+            self.router_creator.clean()
+
+        if self.network_creator:
+            self.network_creator.clean()
+
+        if self.sec_grp_creator:
+            self.sec_grp_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_create_router_secure_port(self):
+        """
+        Test creation of a router with a port that has a security group.
+        """
+        network_settings = NetworkConfig(
+            name=self.guid + '-pub-net1',
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-pub-subnet1')])
+        self.network_creator = OpenStackNetwork(
+            self.os_creds, network_settings)
+        self.network_creator.create()
+
+        port_settings = [
+            create_network.PortConfig(
+                name=self.guid + '-port1',
+                ip_addrs=[{
+                    'subnet_name': network_settings.subnet_settings[0].name,
+                    'ip': static_gateway_ip1}],
+                network_name=network_settings.name,
+                security_groups=[self.sec_grp_creator.sec_grp_settings.name])]
+
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router', external_gateway=self.ext_net_name,
+            port_settings=port_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
+        self.router_creator.create()
+
+
+class CreateRouterSharedNetworksTests(OSIntegrationTestCase):
+    """
+    Class for testing routers external and/or shared networks
+    """
+
+    def setUp(self):
+        """
+        Initializes objects used for router testing
+        """
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.router_creator = None
+
+        ext_network_settings = NetworkConfig(
+            name=self.guid + '-ext-net',
+            external=True,
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr1, name=self.guid + '-ext-subnet1')])
+        self.ext_network_creator = OpenStackNetwork(
+            self.admin_os_creds, ext_network_settings)
+        self.ext_network_creator.create()
+
+        shared_network_settings = NetworkConfig(
+            name=self.guid + '-shared-net',
+            shared=True,
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr2, name=self.guid + '-shared-subnet1')])
+        self.shared_network_creator = OpenStackNetwork(
+            self.admin_os_creds, shared_network_settings)
+        self.shared_network_creator.create()
+
+        overlay_network_settings = NetworkConfig(
+            name=self.guid + '-overlay-net',
+            subnet_settings=[
+                create_network.SubnetConfig(
+                    cidr=cidr3, name=self.guid + '-overlay-subnet1')])
+        self.overlay_network_creator = OpenStackNetwork(
+            self.os_creds, overlay_network_settings)
+        self.overlay_network_creator.create()
+
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+    def tearDown(self):
+        """
+        Cleans the remote OpenStack objects used for router testing
+        """
+        if self.router_creator:
+            self.router_creator.clean()
+
+        if self.overlay_network_creator:
+            self.overlay_network_creator.clean()
+
+        if self.shared_network_creator:
+            self.shared_network_creator.clean()
+
+        if self.ext_network_creator:
+            self.ext_network_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_create_router_external(self):
+        """
+        Test creation of a router with a custom external network created by
+        admin.
+        """
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router',
+            external_gateway=self.ext_network_creator.get_network().name)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
+        self.router_creator.create()
+
+    def test_create_router_port_external(self):
+        """
+        Test creation of a router with a port to an custom external network
+        created by admin.
+        """
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router',
+            network_name=self.ext_network_creator.get_network().name)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
+        self.router_creator.create()
+
+    def test_create_router_port_shared(self):
+        """
+        Test creation of a router with a port to an custom shared network
+        created by admin.
+        """
+        port_settings = [
+            create_network.PortConfig(
+                name=self.guid + '-port1',
+                network_name=self.shared_network_creator.get_network().name)]
+
+        router_settings = RouterConfig(
+            name=self.guid + '-pub-router',
+            port_settings=port_settings)
+        self.router_creator = create_router.OpenStackRouter(
+            self.os_creds, router_settings)
+        self.router_creator.create()
index 090d736..dc632b7 100644 (file)
@@ -21,7 +21,7 @@ from snaps.config.security_group import (
 from snaps.openstack import create_security_group
 from snaps.openstack.create_security_group import (
     SecurityGroupSettings, SecurityGroupRuleSettings, Direction, Ethertype,
-    Protocol)
+    Protocol, OpenStackSecurityGroup)
 from snaps.openstack.tests import validation_utils
 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
 from snaps.openstack.utils import neutron_utils
@@ -210,7 +210,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.sec_grp_name = guid + 'name'
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.sec_grp_creator = None
@@ -228,7 +229,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         """
         Tests the creation of an OpenStack Security Group without custom rules.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_settings = SecurityGroupConfig(name=self.sec_grp_name,
                                                description='hello group')
         self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(
@@ -236,7 +237,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp)
 
         validation_utils.objects_equivalent(
@@ -249,23 +250,24 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group()))
 
     def test_create_group_admin_user_to_new_project(self):
         """
         Tests the creation of an OpenStack Security Group without custom rules.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_settings = SecurityGroupConfig(
             name=self.sec_grp_name, description='hello group',
-            project_name=self.admin_os_creds.project_name)
-        self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(
-            self.os_creds, sec_grp_settings)
+            project_name=self.os_creds.project_name)
+        self.sec_grp_creator = OpenStackSecurityGroup(
+            self.admin_os_creds, sec_grp_settings)
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp)
 
         validation_utils.objects_equivalent(
@@ -278,14 +280,25 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
+        self.assertEqual(self.sec_grp_creator.get_security_group().id,
+                         sec_grp.id)
+
+        proj_creator = OpenStackSecurityGroup(
+            self.os_creds, SecurityGroupConfig(name=self.sec_grp_name))
+        proj_creator.create()
+
+        self.assertEqual(self.sec_grp_creator.get_security_group().id,
+                         proj_creator.get_security_group().id)
+
     def test_create_group_new_user_to_admin_project(self):
         """
         Tests the creation of an OpenStack Security Group without custom rules.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_settings = SecurityGroupConfig(
             name=self.sec_grp_name, description='hello group',
             project_name=self.os_creds.project_name)
@@ -294,7 +307,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp)
 
         validation_utils.objects_equivalent(
@@ -307,14 +320,15 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
     def test_create_delete_group(self):
         """
         Tests the creation of an OpenStack Security Group without custom rules.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_settings = SecurityGroupConfig(name=self.sec_grp_name,
                                                description='hello group')
         self.sec_grp_creator = create_security_group.OpenStackSecurityGroup(
@@ -324,12 +338,13 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group()))
 
         neutron_utils.delete_security_group(self.neutron, created_sec_grp)
         self.assertIsNone(neutron_utils.get_security_group(
-            self.neutron,
+            self.neutron, self.keystone,
             sec_grp_settings=self.sec_grp_creator.sec_grp_settings))
 
         self.sec_grp_creator.clean()
@@ -339,7 +354,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with one simple
         custom rule.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -353,7 +368,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
         rules = neutron_utils.get_rules_by_security_group(
@@ -364,7 +379,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
     def test_create_group_with_one_complex_rule(self):
@@ -372,7 +388,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with one simple
         custom rule.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -388,7 +404,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
         rules = neutron_utils.get_rules_by_security_group(
@@ -399,7 +415,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
     def test_create_group_with_several_rules(self):
@@ -407,7 +424,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with one simple
         custom rule.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -432,7 +449,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
         rules = neutron_utils.get_rules_by_security_group(
@@ -443,7 +460,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
     def test_add_rule(self):
@@ -451,7 +469,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with one simple
         custom rule then adds one after creation.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -465,7 +483,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
 
@@ -474,7 +492,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
         rules = neutron_utils.get_rules_by_security_group(
@@ -496,7 +515,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with two simple
         custom rules then removes one by the rule ID.
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -521,7 +540,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
         rules = neutron_utils.get_rules_by_security_group(
@@ -532,7 +551,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
         self.sec_grp_creator.remove_rule(
@@ -547,7 +567,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack Security Group with two simple
         custom rules then removes one by the rule setting object
         """
-        # Create Image
+        # Create Security Group
         sec_grp_rule_settings = list()
         sec_grp_rule_settings.append(
             SecurityGroupRuleConfig(
@@ -572,7 +592,7 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.sec_grp_creator.create()
 
         sec_grp = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         validation_utils.objects_equivalent(
             self.sec_grp_creator.get_security_group(), sec_grp)
 
@@ -584,7 +604,8 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
 
         self.assertTrue(
             validate_sec_grp(
-                self.neutron, self.sec_grp_creator.sec_grp_settings,
+                self.neutron, self.keystone,
+                self.sec_grp_creator.sec_grp_settings,
                 self.sec_grp_creator.get_security_group(), rules))
 
         self.sec_grp_creator.remove_rule(rule_setting=sec_grp_rule_settings[0])
@@ -594,11 +615,13 @@ class CreateSecurityGroupTests(OSIntegrationTestCase):
         self.assertEqual(len(rules) - 1, len(rules_after_del))
 
 
-def validate_sec_grp(neutron, sec_grp_settings, sec_grp, rules=list()):
+def validate_sec_grp(neutron, keystone, sec_grp_settings, sec_grp,
+                     rules=list()):
     """
     Returns True is the settings on a security group are properly contained
     on the SNAPS SecurityGroup domain object
     :param neutron: the neutron client
+    :param keystone: the keystone client
     :param sec_grp_settings: the security group configuration
     :param sec_grp: the SNAPS-OO security group object
     :param rules: collection of SNAPS-OO security group rule objects
@@ -607,10 +630,10 @@ def validate_sec_grp(neutron, sec_grp_settings, sec_grp, rules=list()):
     return (sec_grp.description == sec_grp_settings.description and
             sec_grp.name == sec_grp_settings.name and
             validate_sec_grp_rules(
-                neutron, sec_grp_settings.rule_settings, rules))
+                neutron, keystone, sec_grp_settings.rule_settings, rules))
 
 
-def validate_sec_grp_rules(neutron, rule_settings, rules):
+def validate_sec_grp_rules(neutron, keystone, rule_settings, rules):
     """
     Returns True is the settings on a security group rule are properly
     contained on the SNAPS SecurityGroupRule domain object.
@@ -618,6 +641,7 @@ def validate_sec_grp_rules(neutron, rule_settings, rules):
     this is the only means to tell if the rule is custom or defaulted by
     OpenStack
     :param neutron: the neutron client
+    :param keystone: the keystone client
     :param rule_settings: collection of SecurityGroupRuleConfig objects
     :param rules: a collection of SecurityGroupRule domain objects
     :return: T/F
@@ -628,7 +652,7 @@ def validate_sec_grp_rules(neutron, rule_settings, rules):
             match = False
             for rule in rules:
                 sec_grp = neutron_utils.get_security_group(
-                    neutron, sec_grp_name=rule_setting.sec_grp_name)
+                    neutron, keystone, sec_grp_name=rule_setting.sec_grp_name)
 
                 setting_eth_type = create_security_group.Ethertype.IPv4
                 if rule_setting.ethertype:
@@ -657,3 +681,69 @@ def validate_sec_grp_rules(neutron, rule_settings, rules):
                 return False
 
     return True
+
+
+class CreateMultipleSecurityGroupTests(OSIntegrationTestCase):
+    """
+    Test for the CreateSecurityGroup class and how it interacts with security
+    groups within other projects with the same name
+    """
+
+    def setUp(self):
+        """
+        Instantiates the CreateSecurityGroup object that is responsible for
+        downloading and creating an OS image file within OpenStack
+        """
+        super(self.__class__, self).__start__()
+
+        guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.sec_grp_name = guid + 'name'
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+
+        # Initialize for cleanup
+        self.admin_sec_grp_config = SecurityGroupConfig(
+            name=self.sec_grp_name, description='hello group')
+        self.sec_grp_creator_admin = OpenStackSecurityGroup(
+            self.admin_os_creds, self.admin_sec_grp_config)
+        self.sec_grp_creator_admin.create()
+        self.sec_grp_creator_proj = None
+
+    def tearDown(self):
+        """
+        Cleans the image and downloaded image file
+        """
+        if self.sec_grp_creator_admin:
+            self.sec_grp_creator_admin.clean()
+        if self.sec_grp_creator_proj:
+            self.sec_grp_creator_proj.clean()
+
+        super(self.__class__, self).__clean__()
+
+    def test_sec_grp_same_name_diff_proj(self):
+        """
+        Tests the creation of an OpenStack Security Group with the same name
+        within a different project/tenant.
+        """
+        # Create Security Group
+        sec_grp_config = SecurityGroupConfig(
+            name=self.sec_grp_name, description='hello group')
+        self.sec_grp_creator_proj = OpenStackSecurityGroup(
+            self.os_creds, sec_grp_config)
+        self.sec_grp_creator_proj.create()
+
+        self.assertNotEqual(
+            self.sec_grp_creator_admin.get_security_group().id,
+            self.sec_grp_creator_proj.get_security_group().id)
+
+        admin_sec_grp_creator = OpenStackSecurityGroup(
+            self.admin_os_creds, self.admin_sec_grp_config)
+        admin_sec_grp_creator.create()
+        self.assertEqual(self.sec_grp_creator_admin.get_security_group().id,
+                         admin_sec_grp_creator.get_security_group().id)
+
+        proj_sec_grp_creator = OpenStackSecurityGroup(
+            self.os_creds, sec_grp_config)
+        proj_sec_grp_creator.create()
+        self.assertEqual(self.sec_grp_creator_proj.get_security_group().id,
+                         proj_sec_grp_creator.get_security_group().id)
index 7155a29..7da5bc7 100644 (file)
@@ -22,7 +22,8 @@ import snaps
 from snaps import file_utils
 from snaps.config.flavor import FlavorConfig
 from snaps.config.image import ImageConfig
-from snaps.config.stack import StackConfigError, StackConfig
+from snaps.config.stack import (StackConfigError, StackConfig,
+    STATUS_UPDATE_COMPLETE)
 from snaps.openstack.create_flavor import OpenStackFlavor
 from snaps.openstack.create_image import OpenStackImage
 
@@ -35,11 +36,13 @@ import logging
 import unittest
 import uuid
 
+from snaps.openstack import create_stack
 from snaps.openstack.create_stack import (
     StackSettings, StackCreationError, StackError, OpenStackHeatStack)
 from snaps.openstack.tests import openstack_tests, create_instance_tests
 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
-from snaps.openstack.utils import heat_utils, neutron_utils, nova_utils
+from snaps.openstack.utils import (
+    heat_utils, neutron_utils, nova_utils, keystone_utils)
 
 __author__ = 'spisarski'
 
@@ -132,28 +135,27 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
     """
 
     def setUp(self):
+        self.user_roles = ['heat_stack_owner']
 
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.image_creator = OpenStackImage(
-            self.heat_creds, openstack_tests.cirros_image_settings(
+            self.os_creds, openstack_tests.cirros_image_settings(
                 name=self.guid + '-image',
                 image_metadata=self.image_metadata))
         self.image_creator.create()
 
         # Create Flavor
+        flavor_config = openstack_tests.get_flavor_config(
+            name=self.guid + '-flavor-name', ram=256, disk=10,
+            vcpus=1, metadata=self.flavor_metadata)
         self.flavor_creator = OpenStackFlavor(
-            self.admin_os_creds,
-            FlavorConfig(
-                name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1))
+            self.admin_os_creds, flavor_config)
         self.flavor_creator.create()
 
         self.network_name = self.guid + '-net'
@@ -206,8 +208,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
@@ -217,6 +219,12 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
         self.assertEqual(created_stack.id, retrieved_stack.id)
         self.assertEqual(0, len(self.stack_creator.get_outputs()))
 
+        derived_creator = create_stack.generate_creator(
+            self.os_creds, retrieved_stack,
+            [self.image_creator.image_settings])
+        derived_stack = derived_creator.get_stack()
+        self.assertEqual(retrieved_stack, derived_stack)
+
     def test_create_stack_short_timeout(self):
         """
         Tests the creation of an OpenStack stack from Heat template file.
@@ -230,9 +238,9 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             env_values=self.env_values, stack_create_timeout=0)
 
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
+            self.os_creds, stack_settings)
         with self.assertRaises(StackCreationError):
-            self.stack_creator.create()
+            self.stack_creator.create(block=True)
 
     def test_create_stack_template_dict(self):
         """
@@ -248,8 +256,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template=template_dict,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
@@ -272,8 +280,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template=template_dict,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
@@ -316,8 +324,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template=template_dict,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack1 = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack1 = self.stack_creator.create(block=True)
 
         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
                                                      created_stack1.id)
@@ -327,8 +335,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
         self.assertEqual(0, len(self.stack_creator.get_outputs()))
 
         # Should be retrieving the instance data
-        stack_creator2 = OpenStackHeatStack(self.heat_creds, stack_settings)
-        stack2 = stack_creator2.create()
+        stack_creator2 = OpenStackHeatStack(self.os_creds, stack_settings)
+        stack2 = stack_creator2.create(block=True)
         self.assertEqual(created_stack1.id, stack2.id)
 
     def test_retrieve_network_creators(self):
@@ -341,8 +349,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         net_creators = self.stack_creator.get_network_creators()
@@ -350,9 +358,14 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
         self.assertEqual(1, len(net_creators))
         self.assertEqual(self.network_name, net_creators[0].get_network().name)
 
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        # Need to use 'admin' creds as heat creates objects under it's own
+        # project/tenant
+        neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         net_by_name = neutron_utils.get_network(
-            neutron, network_name=net_creators[0].get_network().name)
+            neutron, keystone, network_name=net_creators[0].get_network().name)
         self.assertEqual(net_creators[0].get_network(), net_by_name)
         self.assertIsNotNone(neutron_utils.get_network_by_id(
             neutron, net_creators[0].get_network().id))
@@ -360,7 +373,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
         self.assertEqual(1, len(net_creators[0].get_network().subnets))
         subnet = net_creators[0].get_network().subnets[0]
         subnet_by_name = neutron_utils.get_subnet(
-            neutron, subnet_name=subnet.name)
+            neutron, net_creators[0].get_network(), subnet_name=subnet.name)
         self.assertEqual(subnet, subnet_by_name)
 
         subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id)
@@ -377,8 +390,8 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         vm_inst_creators = self.stack_creator.get_vm_inst_creators()
@@ -387,13 +400,16 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
         self.assertEqual(self.vm_inst_name,
                          vm_inst_creators[0].get_vm_inst().name)
 
-        nova = nova_utils.nova_client(self.admin_os_creds)
-        neutron = neutron_utils.neutron_client(self.admin_os_creds)
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(self.os_creds, self.os_session)
         vm_inst_by_name = nova_utils.get_server(
-            nova, neutron, server_name=vm_inst_creators[0].get_vm_inst().name)
+            nova, neutron, keystone,
+            server_name=vm_inst_creators[0].get_vm_inst().name)
+
         self.assertEqual(vm_inst_creators[0].get_vm_inst(), vm_inst_by_name)
         self.assertIsNotNone(nova_utils.get_server_object_by_id(
-            nova, neutron, vm_inst_creators[0].get_vm_inst().id))
+            nova, neutron, keystone, vm_inst_creators[0].get_vm_inst().id))
 
 
 class CreateStackFloatingIpTests(OSIntegrationTestCase):
@@ -403,19 +419,17 @@ class CreateStackFloatingIpTests(OSIntegrationTestCase):
     """
 
     def setUp(self):
+        self.user_roles = ['heat_stack_owner', 'admin']
 
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.image_creator = OpenStackImage(
-            self.heat_creds, openstack_tests.cirros_image_settings(
+            self.os_creds, openstack_tests.cirros_image_settings(
                 name=self.guid + '-image',
                 image_metadata=self.image_metadata))
         self.image_creator.create()
@@ -434,6 +448,7 @@ class CreateStackFloatingIpTests(OSIntegrationTestCase):
             'image2_name': self.image_creator.image_settings.name,
             'flavor1_name': self.flavor1_name,
             'flavor2_name': self.flavor2_name,
+            'flavor_extra_specs': self.flavor_metadata,
             'net_name': self.network_name,
             'subnet_name': self.subnet_name,
             'inst1_name': self.vm_inst1_name,
@@ -487,9 +502,9 @@ class CreateStackFloatingIpTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings,
+            self.os_creds, stack_settings,
             [self.image_creator.image_settings])
-        created_stack = self.stack_creator.create()
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
@@ -505,6 +520,39 @@ class CreateStackFloatingIpTests(OSIntegrationTestCase):
                 vm_settings = vm_inst_creator.instance_settings
                 self.assertEqual(0, len(vm_settings.floating_ip_settings))
 
+    def test_connect_via_ssh_heat_vm_derived(self):
+        """
+        Tests the the retrieval of two VM instance creators from a derived
+        OpenStackHeatStack object and attempt to connect via
+        SSH to the first one with a floating IP.
+        """
+        stack_settings = StackConfig(
+            name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
+            template_path=self.heat_tmplt_path,
+            env_values=self.env_values)
+        self.stack_creator = OpenStackHeatStack(
+            self.os_creds, stack_settings,
+            [self.image_creator.image_settings])
+        created_stack = self.stack_creator.create(block=True)
+        self.assertIsNotNone(created_stack)
+
+        derived_stack = create_stack.generate_creator(
+            self.os_creds, created_stack,
+            [self.image_creator.image_settings])
+
+        self.vm_inst_creators = derived_stack.get_vm_inst_creators(
+            heat_keypair_option='private_key')
+        self.assertIsNotNone(self.vm_inst_creators)
+        self.assertEqual(2, len(self.vm_inst_creators))
+
+        for vm_inst_creator in self.vm_inst_creators:
+            if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
+                self.assertTrue(
+                    create_instance_tests.validate_ssh_client(vm_inst_creator))
+            else:
+                vm_settings = vm_inst_creator.instance_settings
+                self.assertEqual(0, len(vm_settings.floating_ip_settings))
+
 
 class CreateStackNestedResourceTests(OSIntegrationTestCase):
     """
@@ -512,19 +560,125 @@ class CreateStackNestedResourceTests(OSIntegrationTestCase):
     """
 
     def setUp(self):
+        self.user_roles = ['heat_stack_owner']
 
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
+        self.stack_creator = None
+
+        self.image_creator = OpenStackImage(
+            self.os_creds, openstack_tests.cirros_image_settings(
+                name="{}-{}".format(self.guid, 'image'),
+                image_metadata=self.image_metadata))
+        self.image_creator.create()
+
+        flavor_config = openstack_tests.get_flavor_config(
+            name="{}-{}".format(self.guid, 'flavor-name'), ram=256, disk=10,
+            vcpus=1, metadata=self.flavor_metadata)
+        self.flavor_creator = OpenStackFlavor(
+            self.admin_os_creds, flavor_config)
+        self.flavor_creator.create()
+
+        env_values = {
+            'network_name': self.guid + '-network',
+            'public_network': self.ext_net_name,
+            'agent_image': self.image_creator.image_settings.name,
+            'agent_flavor': self.flavor_creator.flavor_settings.name,
+            'key_name': self.guid + '-key',
+        }
+
+        heat_tmplt_path = pkg_resources.resource_filename(
+            'snaps.openstack.tests.heat', 'agent-group.yaml')
+        heat_resource_path = pkg_resources.resource_filename(
+            'snaps.openstack.tests.heat', 'agent.yaml')
+
+        stack_settings = StackConfig(
+            name="{}-{}".format(
+                self.__class__.__name__, str(self.guid) + '-stack'),
+            template_path=heat_tmplt_path,
+            resource_files=[heat_resource_path],
+            env_values=env_values)
+
+        self.stack_creator = OpenStackHeatStack(
+            self.os_creds, stack_settings,
+            [self.image_creator.image_settings])
+
+        self.vm_inst_creators = list()
+
+    def tearDown(self):
+        """
+        Cleans the stack and downloaded stack file
+        """
+        if self.stack_creator:
+            try:
+                self.stack_creator.clean()
+            except:
+                pass
+
+        if self.image_creator:
+            try:
+                self.image_creator.clean()
+            except:
+                pass
 
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        if self.flavor_creator:
+            try:
+                self.flavor_creator.clean()
+            except:
+                pass
+
+        for vm_inst_creator in self.vm_inst_creators:
+            try:
+                keypair_settings = vm_inst_creator.keypair_settings
+                if keypair_settings and keypair_settings.private_filepath:
+                    expanded_path = os.path.expanduser(
+                        keypair_settings.private_filepath)
+                    os.chmod(expanded_path, 0o755)
+                    os.remove(expanded_path)
+            except:
+                pass
+
+        super(self.__class__, self).__clean__()
+
+    def test_nested(self):
+        """
+        Tests the creation of an OpenStack stack from Heat template file and
+        the retrieval of two VM instance creators and attempt to connect via
+        SSH to the first one with a floating IP.
+        """
+        created_stack = self.stack_creator.create(block=True)
+        self.assertIsNotNone(created_stack)
+
+        self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
+            heat_keypair_option='private_key')
+        self.assertIsNotNone(self.vm_inst_creators)
+        self.assertEqual(1, len(self.vm_inst_creators))
+
+        for vm_inst_creator in self.vm_inst_creators:
+            self.assertTrue(
+                create_instance_tests.validate_ssh_client(vm_inst_creator))
+
+
+class CreateStackUpdateTests(OSIntegrationTestCase):
+    """
+    Tests to ensure that stack update commands work
+    """
+
+    def setUp(self):
+        self.user_roles = ['heat_stack_owner']
+
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.image_creator = OpenStackImage(
-            self.heat_creds, openstack_tests.cirros_image_settings(
+            self.os_creds, openstack_tests.cirros_image_settings(
                 name=self.guid + '-image',
                 image_metadata=self.image_metadata))
         self.image_creator.create()
@@ -555,7 +709,7 @@ class CreateStackNestedResourceTests(OSIntegrationTestCase):
             env_values=env_values)
 
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings,
+            self.os_creds, stack_settings,
             [self.image_creator.image_settings])
 
         self.vm_inst_creators = list()
@@ -595,13 +749,14 @@ class CreateStackNestedResourceTests(OSIntegrationTestCase):
 
         super(self.__class__, self).__clean__()
 
-    def test_nested(self):
+    def test_update(self):
         """
-        Tests the creation of an OpenStack stack from Heat template file and
+        Tests the update of an OpenStack stack from Heat template file
+        by changing the number of VM instances from 1 to 2, and
         the retrieval of two VM instance creators and attempt to connect via
         SSH to the first one with a floating IP.
         """
-        created_stack = self.stack_creator.create()
+        created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(created_stack)
 
         self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
@@ -613,6 +768,28 @@ class CreateStackNestedResourceTests(OSIntegrationTestCase):
             self.assertTrue(
                 create_instance_tests.validate_ssh_client(vm_inst_creator))
 
+        env_values = {
+            'network_name': self.guid + '-network',
+            'public_network': self.ext_net_name,
+            'agent_count': 2,
+            'agent_image': self.image_creator.image_settings.name,
+            'agent_flavor': self.flavor_creator.flavor_settings.name,
+            'key_name': self.guid + '-key',
+        }
+
+        updated_stack = self.stack_creator.update(env_values, block=True)
+        self.assertIsNotNone(updated_stack)
+        self.assertEqual(STATUS_UPDATE_COMPLETE, updated_stack.status)
+
+        self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
+            heat_keypair_option='private_key')
+        self.assertIsNotNone(self.vm_inst_creators)
+        self.assertEqual(2, len(self.vm_inst_creators))
+
+        for vm_inst_creator in self.vm_inst_creators:
+            self.assertTrue(
+                create_instance_tests.validate_ssh_client(vm_inst_creator))
+
 
 class CreateStackRouterTests(OSIntegrationTestCase):
     """
@@ -625,15 +802,15 @@ class CreateStackRouterTests(OSIntegrationTestCase):
         Instantiates the CreateStack object that is responsible for downloading
         and creating an OS stack file within OpenStack
         """
+        self.user_roles = ['heat_stack_owner']
+
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.net_name = self.guid + '-net'
@@ -654,8 +831,8 @@ class CreateStackRouterTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        self.created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        self.created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(self.created_stack)
 
     def tearDown(self):
@@ -684,7 +861,7 @@ class CreateStackRouterTests(OSIntegrationTestCase):
         router = creator.get_router()
 
         ext_net = neutron_utils.get_network(
-            self.neutron, network_name=self.ext_net_name)
+            self.neutron, self.keystone, network_name=self.ext_net_name)
         self.assertEqual(ext_net.id, router.external_network_id)
 
 
@@ -696,14 +873,13 @@ class CreateStackVolumeTests(OSIntegrationTestCase):
 
     def setUp(self):
 
+        self.user_roles = ['heat_stack_owner', 'admin']
+
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.volume_name = self.guid + '-volume'
@@ -721,8 +897,8 @@ class CreateStackVolumeTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        self.created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        self.created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(self.created_stack)
 
     def tearDown(self):
@@ -791,14 +967,13 @@ class CreateStackFlavorTests(OSIntegrationTestCase):
 
     def setUp(self):
 
+        self.user_roles = ['heat_stack_owner', 'admin']
+
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.heat_tmplt_path = pkg_resources.resource_filename(
@@ -808,8 +983,8 @@ class CreateStackFlavorTests(OSIntegrationTestCase):
             name=self.guid + '-stack',
             template_path=self.heat_tmplt_path)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        self.created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        self.created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(self.created_stack)
 
     def tearDown(self):
@@ -851,15 +1026,14 @@ class CreateStackKeypairTests(OSIntegrationTestCase):
 
     def setUp(self):
 
+        self.user_roles = ['heat_stack_owner']
+
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
-        self.nova = nova_utils.nova_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.keypair_name = self.guid + '-kp'
@@ -875,8 +1049,8 @@ class CreateStackKeypairTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        self.created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        self.created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(self.created_stack)
 
         self.keypair_creators = list()
@@ -936,15 +1110,14 @@ class CreateStackSecurityGroupTests(OSIntegrationTestCase):
         Instantiates the CreateStack object that is responsible for downloading
         and creating an OS stack file within OpenStack
         """
+        self.user_roles = ['heat_stack_owner']
+
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
-        self.nova = nova_utils.nova_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.security_group_name = self.guid + '-sec-grp'
@@ -960,8 +1133,8 @@ class CreateStackSecurityGroupTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
-        self.created_stack = self.stack_creator.create()
+            self.os_creds, stack_settings)
+        self.created_stack = self.stack_creator.create(block=True)
         self.assertIsNotNone(self.created_stack)
 
     def tearDown(self):
@@ -1026,12 +1199,10 @@ class CreateStackNegativeTests(OSIntegrationTestCase):
     """
 
     def setUp(self):
+        self.user_roles = ['heat_stack_owner']
 
         super(self.__class__, self).__start__()
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
         self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.stack_creator = None
         self.heat_tmplt_path = pkg_resources.resource_filename(
@@ -1040,6 +1211,7 @@ class CreateStackNegativeTests(OSIntegrationTestCase):
     def tearDown(self):
         if self.stack_creator:
             self.stack_creator.clean()
+
         super(self.__class__, self).__clean__()
 
     def test_missing_dependencies(self):
@@ -1049,9 +1221,9 @@ class CreateStackNegativeTests(OSIntegrationTestCase):
         stack_settings = StackConfig(name=self.stack_name,
                                      template_path=self.heat_tmplt_path)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
+            self.os_creds, stack_settings)
         with self.assertRaises(HTTPBadRequest):
-            self.stack_creator.create()
+            self.stack_creator.create(block=True)
 
     def test_bad_stack_file(self):
         """
@@ -1060,9 +1232,9 @@ class CreateStackNegativeTests(OSIntegrationTestCase):
         stack_settings = StackConfig(
             name=self.stack_name, template_path='foo')
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
+            self.os_creds, stack_settings)
         with self.assertRaises(IOError):
-            self.stack_creator.create()
+            self.stack_creator.create(block=True)
 
 
 class CreateStackFailureTests(OSIntegrationTestCase):
@@ -1073,21 +1245,19 @@ class CreateStackFailureTests(OSIntegrationTestCase):
     """
 
     def setUp(self):
+        self.user_roles = ['heat_stack_owner']
 
         super(self.__class__, self).__start__()
 
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.heat_creds = self.admin_os_creds
-        self.heat_creds.project_name = self.admin_os_creds.project_name
-
-        self.heat_cli = heat_utils.heat_client(self.heat_creds)
+        self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
         self.stack_creator = None
 
         self.tmp_file = file_utils.save_string_to_file(
             ' ', str(uuid.uuid4()) + '-bad-image')
         self.image_creator = OpenStackImage(
-            self.heat_creds, ImageConfig(
+            self.os_creds, ImageConfig(
                 name=self.guid + 'image', image_file=self.tmp_file.name,
                 image_user='foo', img_format='qcow2'))
         self.image_creator.create()
@@ -1157,11 +1327,11 @@ class CreateStackFailureTests(OSIntegrationTestCase):
             template_path=self.heat_tmplt_path,
             env_values=self.env_values)
         self.stack_creator = OpenStackHeatStack(
-            self.heat_creds, stack_settings)
+            self.os_creds, stack_settings)
 
         with self.assertRaises(StackError):
             try:
-                self.stack_creator.create()
+                self.stack_creator.create(block=True)
             except StackError:
                 resources = heat_utils.get_resources(
                     self.heat_cli, self.stack_creator.get_stack().id)
index d3eb4a6..c15a71f 100644 (file)
@@ -106,10 +106,11 @@ class CreateUserSuccessTests(OSComponentTestCase):
         self.user_settings = UserConfig(
             name=guid + '-name',
             password=guid + '-password',
-            roles={'admin': self.os_creds.project_name},
+            roles={'admin': self.os_creds.project_name,
+                   'Admin': self.os_creds.project_name},
             domain_name=self.os_creds.user_domain_name)
 
-        self.keystone = keystone_utils.keystone_client(self.os_creds)
+        self.keystone = keystone_utils.keystone_client(self.os_creds, self.os_session)
 
         # Initialize for cleanup
         self.user_creator = None
@@ -121,6 +122,8 @@ class CreateUserSuccessTests(OSComponentTestCase):
         if self.user_creator:
             self.user_creator.clean()
 
+        super(self.__class__, self).__clean__()
+
     def test_create_user(self):
         """
         Tests the creation of an OpenStack user.
@@ -181,6 +184,8 @@ class CreateUserSuccessTests(OSComponentTestCase):
         self.assertEqual(created_user, retrieved_user)
 
         role = keystone_utils.get_role_by_name(self.keystone, 'admin')
+        if not role:
+            role = keystone_utils.get_role_by_name(self.keystone, 'Admin')
         self.assertIsNotNone(role)
 
         os_proj = keystone_utils.get_project(
index ca13860..3c9a346 100644 (file)
@@ -32,7 +32,7 @@ import uuid
 from snaps.openstack.create_volume import (
     VolumeSettings, OpenStackVolume)
 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
-from snaps.openstack.utils import cinder_utils
+from snaps.openstack.utils import cinder_utils, keystone_utils
 
 __author__ = 'spisarski'
 
@@ -129,7 +129,10 @@ class CreateSimpleVolumeSuccessTests(OSIntegrationTestCase):
         self.volume_settings = VolumeConfig(
             name=self.__class__.__name__ + '-' + str(guid))
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.volume_creator = None
 
     def tearDown(self):
@@ -152,7 +155,8 @@ class CreateSimpleVolumeSuccessTests(OSIntegrationTestCase):
         self.assertIsNotNone(created_volume)
 
         retrieved_volume = cinder_utils.get_volume(
-            self.cinder, volume_settings=self.volume_settings)
+            self.cinder, self.keystone, volume_settings=self.volume_settings,
+            project_name=self.os_creds.project_name)
 
         self.assertIsNotNone(retrieved_volume)
         self.assertEqual(created_volume.id, retrieved_volume.id)
@@ -170,7 +174,8 @@ class CreateSimpleVolumeSuccessTests(OSIntegrationTestCase):
         self.assertIsNotNone(created_volume)
 
         retrieved_volume = cinder_utils.get_volume(
-            self.cinder, volume_settings=self.volume_settings)
+            self.cinder, self.keystone, volume_settings=self.volume_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(retrieved_volume)
         self.assertEqual(created_volume, retrieved_volume)
 
@@ -178,7 +183,8 @@ class CreateSimpleVolumeSuccessTests(OSIntegrationTestCase):
         self.volume_creator.clean()
 
         self.assertIsNone(cinder_utils.get_volume(
-            self.cinder, volume_settings=self.volume_settings))
+            self.cinder, self.keystone, volume_settings=self.volume_settings,
+            project_name=self.os_creds.project_name))
 
         # Must not throw an exception when attempting to cleanup non-existent
         # volume
@@ -195,7 +201,8 @@ class CreateSimpleVolumeSuccessTests(OSIntegrationTestCase):
         volume1 = self.volume_creator.create(block=True)
 
         retrieved_volume = cinder_utils.get_volume(
-            self.cinder, volume_settings=self.volume_settings)
+            self.cinder, self.keystone, volume_settings=self.volume_settings,
+            project_name=self.os_creds.project_name)
         self.assertEqual(volume1, retrieved_volume)
 
         # Should be retrieving the instance data
@@ -218,7 +225,8 @@ class CreateSimpleVolumeFailureTests(OSIntegrationTestCase):
         super(self.__class__, self).__start__()
 
         self.guid = uuid.uuid4()
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
         self.volume_creator = None
 
     def tearDown(self):
@@ -274,21 +282,6 @@ class CreateSimpleVolumeFailureTests(OSIntegrationTestCase):
         with self.assertRaises(BadRequest):
             self.volume_creator.create(block=True)
 
-    def test_create_volume_bad_zone(self):
-        """
-        Tests the creation of an OpenStack volume with an availability zone
-        that does not exist to ensure it raises a BadRequest exception.
-        """
-        volume_settings = VolumeConfig(
-            name=self.__class__.__name__ + '-' + str(self.guid),
-            availability_zone='foo')
-
-        # Create Volume
-        self.volume_creator = OpenStackVolume(self.os_creds, volume_settings)
-
-        with self.assertRaises(BadRequest):
-            self.volume_creator.create(block=True)
-
 
 class CreateVolumeWithTypeTests(OSIntegrationTestCase):
     """
@@ -304,7 +297,7 @@ class CreateVolumeWithTypeTests(OSIntegrationTestCase):
         self.volume_type_name = guid + '-vol-type'
 
         self.volume_type_creator = OpenStackVolumeType(
-            self.os_creds, VolumeTypeConfig(name=self.volume_type_name))
+            self.admin_os_creds, VolumeTypeConfig(name=self.volume_type_name))
         self.volume_type_creator.create()
         self.volume_creator = None
 
@@ -332,8 +325,7 @@ class CreateVolumeWithTypeTests(OSIntegrationTestCase):
         Expect a NotFound to be raised when the volume type does not exist
         """
         self.volume_creator = OpenStackVolume(
-            self.os_creds,
-            VolumeConfig(
+            self.admin_os_creds, VolumeConfig(
                 name=self.volume_name, type_name=self.volume_type_name))
 
         created_volume = self.volume_creator.create(block=True)
@@ -349,7 +341,8 @@ class CreateVolumeWithImageTests(OSIntegrationTestCase):
     def setUp(self):
         super(self.__class__, self).__start__()
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.volume_name = guid + '-vol'
@@ -408,3 +401,87 @@ class CreateVolumeWithImageTests(OSIntegrationTestCase):
             self.cinder, created_volume.id)
 
         self.assertEqual(created_volume, retrieved_volume)
+
+
+class CreateVolMultipleCredsTests(OSIntegrationTestCase):
+    """
+    Test for the OpenStackVolume class and how it interacts with volumes
+    created with differenct credentials and to other projects with the same
+    name
+    """
+    def setUp(self):
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.volume_creators = list()
+
+    def tearDown(self):
+        for volume_creator in self.volume_creators:
+            volume_creator.clean()
+
+        super(self.__class__, self).__clean__()
+
+    # TODO - activate after cinder API bug has been fixed
+    # see https://bugs.launchpad.net/cinder/+bug/1641982 as to why this test
+    # is not activated
+    # def test_create_by_admin_to_other_proj(self):
+    #     """
+    #     Creates a volume as admin to the project of os_creds then instantiates
+    #     a creator object with the os_creds project to ensure it initializes
+    #     without creation
+    #     """
+    #     self.volume_creators.append(OpenStackVolume(
+    #         self.admin_os_creds, VolumeConfig(
+    #             name=self.guid + '-vol',
+    #             project_name=self.os_creds.project_name)))
+    #     admin_vol = self.volume_creators[0].create(block=True)
+    #
+    #     self.volume_creators.append(OpenStackVolume(
+    #         self.os_creds, VolumeConfig(name=self.guid + '-vol')))
+    #     proj_vol = self.volume_creators[1].create(block=True)
+    #
+    #     self.assertEqual(admin_vol, proj_vol)
+
+    def test_create_two_vol_same_name_diff_proj(self):
+        """
+        Creates a volume as admin to the project of os_creds then instantiates
+        a creator object with the os_creds project to ensure it initializes
+        without creation
+        """
+        vol_name = self.guid + '-vol'
+        self.volume_creators.append(OpenStackVolume(
+            self.admin_os_creds, VolumeConfig(name=vol_name)))
+        admin_vol = self.volume_creators[0].create(block=True)
+        self.assertIsNotNone(admin_vol)
+
+        admin_key = keystone_utils.keystone_client(
+            self.admin_os_creds, self.admin_os_session)
+        admin_proj = keystone_utils.get_project(
+            admin_key, project_name=self.admin_os_creds.project_name)
+        self.assertEqual(admin_vol.project_id, admin_proj.id)
+
+        admin_cinder = cinder_utils.cinder_client(
+            self.admin_os_creds, self.admin_os_session)
+        admin_vol_get = cinder_utils.get_volume(
+            admin_cinder, admin_key, volume_name=vol_name,
+            project_name=self.admin_os_creds.project_name)
+        self.assertIsNotNone(admin_vol_get)
+        self.assertEqual(admin_vol, admin_vol_get)
+
+        self.volume_creators.append(OpenStackVolume(
+            self.os_creds, VolumeConfig(name=vol_name)))
+        proj_vol = self.volume_creators[1].create(block=True)
+        self.assertIsNotNone(proj_vol)
+
+        self.assertNotEqual(admin_vol, proj_vol)
+
+        proj_key = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        proj_cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
+        proj_vol_get = cinder_utils.get_volume(
+            proj_cinder, proj_key, volume_name=vol_name,
+            project_name=self.os_creds.project_name)
+
+        self.assertIsNotNone(proj_vol_get)
+        self.assertEqual(proj_vol, proj_vol_get)
index 70c40cc..b797274 100644 (file)
@@ -29,7 +29,7 @@ import uuid
 
 from snaps.openstack import create_volume_type
 from snaps.openstack.create_volume_type import (
-    VolumeTypeSettings, VolumeTypeEncryptionSettings)
+    VolumeTypeSettings, VolumeTypeEncryptionSettings, OpenStackVolumeType)
 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
 from snaps.openstack.utils import cinder_utils
 
@@ -127,8 +127,10 @@ class CreateSimpleVolumeTypeSuccessTests(OSIntegrationTestCase):
         self.volume_type_settings = VolumeTypeConfig(
             name=self.__class__.__name__ + '-' + str(guid))
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
-        self.volume_type_creator = None
+        self.cinder = cinder_utils.cinder_client(
+            self.admin_os_creds, self.admin_os_session)
+        self.volume_type_creator = OpenStackVolumeType(
+            self.admin_os_creds, self.volume_type_settings)
 
     def tearDown(self):
         """
@@ -144,8 +146,6 @@ class CreateSimpleVolumeTypeSuccessTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack volume.
         """
         # Create VolumeType
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds, self.volume_type_settings)
         created_volume_type = self.volume_type_creator.create()
         self.assertIsNotNone(created_volume_type)
         self.assertEqual(self.volume_type_settings.name,
@@ -166,8 +166,6 @@ class CreateSimpleVolumeTypeSuccessTests(OSIntegrationTestCase):
         clean() does not raise an Exception.
         """
         # Create VolumeType
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds, self.volume_type_settings)
         created_volume_type = self.volume_type_creator.create()
         self.assertIsNotNone(created_volume_type)
 
@@ -192,8 +190,6 @@ class CreateSimpleVolumeTypeSuccessTests(OSIntegrationTestCase):
         Tests the creation of an OpenStack volume_type when one already exists.
         """
         # Create VolumeType
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds, self.volume_type_settings)
         volume_type1 = self.volume_type_creator.create()
 
         retrieved_volume_type = cinder_utils.get_volume_type(
@@ -202,7 +198,7 @@ class CreateSimpleVolumeTypeSuccessTests(OSIntegrationTestCase):
 
         # Should be retrieving the instance data
         os_volume_type_2 = create_volume_type.OpenStackVolumeType(
-            self.os_creds, self.volume_type_settings)
+            self.admin_os_creds, self.volume_type_settings)
         volume_type2 = os_volume_type_2.create()
         self.assertEqual(volume_type2, volume_type2)
 
@@ -216,7 +212,8 @@ class CreateVolumeTypeComplexTests(OSIntegrationTestCase):
     def setUp(self):
         super(self.__class__, self).__start__()
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.admin_os_creds, self.admin_os_session)
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
@@ -225,7 +222,7 @@ class CreateVolumeTypeComplexTests(OSIntegrationTestCase):
 
         qos_settings = QoSConfig(
             name=guid + '-qos-spec', consumer=Consumer.both)
-        self.qos_creator = OpenStackQoS(self.os_creds, qos_settings)
+        self.qos_creator = OpenStackQoS(self.admin_os_creds, qos_settings)
         self.qos_creator.create()
 
     def tearDown(self):
@@ -241,8 +238,8 @@ class CreateVolumeTypeComplexTests(OSIntegrationTestCase):
         """
         Creates a Volume Type object with an associated QoS Spec
         """
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds,
+        self.volume_type_creator = OpenStackVolumeType(
+            self.admin_os_creds,
             VolumeTypeConfig(
                 name=self.volume_type_name,
                 qos_spec_name=self.qos_creator.qos_settings.name))
@@ -270,8 +267,8 @@ class CreateVolumeTypeComplexTests(OSIntegrationTestCase):
         encryption_settings = VolumeTypeEncryptionConfig(
             name='foo', provider_class='bar',
             control_location=ControlLocation.back_end)
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds,
+        self.volume_type_creator = OpenStackVolumeType(
+            self.admin_os_creds,
             VolumeTypeConfig(
                 name=self.volume_type_name,
                 encryption=encryption_settings))
@@ -299,8 +296,8 @@ class CreateVolumeTypeComplexTests(OSIntegrationTestCase):
         encryption_settings = VolumeTypeEncryptionConfig(
             name='foo', provider_class='bar',
             control_location=ControlLocation.back_end)
-        self.volume_type_creator = create_volume_type.OpenStackVolumeType(
-            self.os_creds,
+        self.volume_type_creator = OpenStackVolumeType(
+            self.admin_os_creds,
             VolumeTypeConfig(
                 name=self.volume_type_name,
                 encryption=encryption_settings,
index 4b97495..494da0a 100644 (file)
@@ -70,7 +70,7 @@ resources:
   network:
         type: OS::Neutron::Net
         properties:
-          name: { get_param: agent_count }
+          name: { get_param: network_name }
 
   subnet:
         type: OS::Neutron::Subnet
index a191acc..e64c7fc 100644 (file)
@@ -41,6 +41,10 @@ parameters:
     label: Instance Flavor for second VM
     description: Flavor name for the second instance
     default: m1.med
+  flavor_extra_specs:
+    type: json
+    description: Instance Flavor extra specs
+    default: {}
   net_name:
     type: string
     label: Test network name
@@ -88,12 +92,14 @@ resources:
       ram: 1024
       vcpus: 2
       disk: 2
+      extra_specs: { get_param: flavor_extra_specs }
   flavor2:
     type: OS::Nova::Flavor
     properties:
       ram: 1024
       vcpus: 2
       disk: 2
+      extra_specs: { get_param: flavor_extra_specs }
 
   network:
     type: OS::Neutron::Net
@@ -140,10 +146,10 @@ resources:
       floating_network: { get_param: external_net_name }
 
   floating_ip_association:
-    type: OS::Nova::FloatingIPAssociation
+    type: OS::Neutron::FloatingIPAssociation
     properties:
-      floating_ip: { get_resource: floating_ip }
-      server_id: {get_resource: vm1}
+      floatingip_id: { get_resource: floating_ip }
+      port_id: {get_resource: port1}
 
   keypair:
     type: OS::Nova::KeyPair
@@ -151,21 +157,28 @@ resources:
       name: { get_param: keypair_name }
       save_private_key: True
 
+  port1:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: network }
+      security_groups: [{ get_resource: server_security_group }]
+      fixed_ips:
+        - subnet_id: { get_resource: subnet }
+
   vm1:
     type: OS::Nova::Server
-    depends_on: [subnet, keypair, flavor1]
+    depends_on: [subnet, keypair, flavor1, port1]
     properties:
       name: { get_param: inst1_name }
       image: { get_param: image1_name }
       flavor: { get_resource: flavor1 }
       key_name: {get_resource: keypair}
-      security_groups: [{ get_resource: server_security_group }]
       networks:
-        - network: { get_resource: network }
+        - port: { get_resource: port1 }
 
   vm2:
     type: OS::Nova::Server
-    depends_on: [subnet, flavor2]
+    depends_on: [subnet, keypair, flavor2]
     properties:
       name: { get_param: inst2_name }
       image: { get_param: image2_name }
index 3c32eb7..f3a1df7 100644 (file)
@@ -16,6 +16,7 @@ import logging
 import re
 
 from snaps import file_utils
+from snaps.config.flavor import FlavorConfig
 from snaps.config.image import ImageConfig
 from snaps.config.network import NetworkConfig, SubnetConfig
 from snaps.config.router import RouterConfig
@@ -312,22 +313,81 @@ def ubuntu_image_settings(name, url=None, image_metadata=None,
         public=public)
 
 
-def get_priv_net_config(net_name, subnet_name, router_name=None,
-                        cidr='10.55.0.0/24', external_net=None,
-                        netconf_override=None):
-    return OSNetworkConfig(net_name, subnet_name, cidr, router_name,
-                           external_gateway=external_net,
-                           netconf_override=netconf_override)
+def get_priv_net_config(project_name, net_name, mtu=None, subnet_name=None,
+                        router_name=None, cidr='10.55.0.0/24',
+                        external_net=None, netconf_override=None):
+    return OSNetworkConfig(
+        project_name, net_name, mtu, subnet_name, cidr, router_name,
+        external_gateway=external_net, netconf_override=netconf_override)
 
 
-def get_pub_net_config(net_name, subnet_name=None, router_name=None,
-                       cidr='10.55.1.0/24', external_net=None,
-                       netconf_override=None):
-    return OSNetworkConfig(net_name, subnet_name, cidr, router_name,
-                           external_gateway=external_net,
+def get_pub_net_config(
+        project_name, net_name, mtu=None, subnet_name=None, router_name=None,
+        cidr='10.55.1.0/24', external_net=None, netconf_override=None):
+    return OSNetworkConfig(project_name, net_name, mtu, subnet_name, cidr,
+                           router_name, external_gateway=external_net,
                            netconf_override=netconf_override)
 
 
+def get_flavor_config(name, ram, disk, vcpus, ephemeral=None, swap=None,
+                      rxtx_factor=None, is_public=None, metadata=None):
+    """This method replaces the hard coded basic element (e.g. ram, vcpu, disk
+     etc) with those are included in the new freeform dict() of metadata
+     parameter.
+
+    :param name: the flavor name (required)
+    :param ram: memory in MB to allocate to VM (required)
+    :param disk: disk storage in GB (required)
+    :param vcpus: the number of CPUs to allocate to VM (required)
+    :param ephemeral: the size of the ephemeral disk in GB (default=0)
+    :param swap: the size of the swap disk in GB (default=0)
+    :param rxtx_factor: the receive/transmit factor to be set on ports
+         if backend supports QoS extension (default=1.0)
+    :param is_public: flag that denotes whether or not other projects
+         can access image (default=True)
+    :param metadata: - freeform dict() for special metadata (optional)
+                     - freeform dict() for values of basic elements
+                     (e.g. ram, vcpu, disk, etc) could be added.
+                     As result the hard coded values of those elements will be
+                     overwritten by the new ones (optional)
+    :return: The FlavorConfig replacing the hard coded basic element values
+            (e.g. ram, vcpu, disk etc) with those are included in the metadata
+             dict [optional]. The metadata parameter in the FlavorConfig
+             consist of the metadata data only.
+    """
+
+    metadata_excl = metadata
+    if metadata:
+        if 'ram' in metadata:
+            ram = metadata['ram']
+            del metadata_excl['ram']
+        if 'disk' in metadata:
+            disk = metadata['disk']
+            del metadata_excl['disk']
+        if 'vcpus' in metadata:
+            vcpus = metadata['vcpus']
+            del metadata_excl['vcpus']
+        if 'ephemeral' in metadata:
+            ephemeral = metadata['ephemeral']
+            del metadata_excl['ephemeral']
+        if 'swap' in metadata:
+            swap = metadata['swap']
+            del metadata_excl['swap']
+        if 'rxtx_factor' in metadata:
+            rxtx_factor = metadata['rxtx_factor']
+            del metadata_excl['rxtx_factor']
+        if 'is_public' in metadata:
+            is_public = metadata['is_public']
+            del metadata_excl['is_public']
+        if 'metadata' in metadata:
+            metadata_excl = metadata['metadata']
+
+    return FlavorConfig(
+        name=name, ram=ram, disk=disk, vcpus=vcpus, ephemeral=ephemeral,
+        swap=swap, rxtx_factor=rxtx_factor, is_public=is_public,
+        metadata=metadata_excl)
+
+
 class OSNetworkConfig:
     """
     Represents the settings required for the creation of a network in OpenStack
@@ -335,8 +395,8 @@ class OSNetworkConfig:
     physical_network and segmentation_id
     """
 
-    def __init__(self, net_name, subnet_name=None, subnet_cidr=None,
-                 router_name=None, external_gateway=None,
+    def __init__(self, project_name, net_name, mtu=None, subnet_name=None,
+                 subnet_cidr=None, router_name=None, external_gateway=None,
                  netconf_override=None):
         """
         :param netconf_override: dict() containing the reconfigured
@@ -345,7 +405,7 @@ class OSNetworkConfig:
         """
         if subnet_name and subnet_cidr:
             network_conf = NetworkConfig(
-                name=net_name, subnet_settings=[
+                name=net_name, mtu=mtu, subnet_settings=[
                     SubnetConfig(cidr=subnet_cidr, name=subnet_name)])
         else:
             network_conf = NetworkConfig(name=net_name)
@@ -361,7 +421,10 @@ class OSNetworkConfig:
             if subnet_name:
                 self.router_settings = RouterConfig(
                     name=router_name, external_gateway=external_gateway,
-                    internal_subnets=[subnet_name])
+                    internal_subnets=[{'subnet': {
+                        'project_name': project_name,
+                        'network_name': net_name,
+                        'subnet_name': subnet_name}}])
             else:
                 self.router_settings = RouterConfig(
                     name=router_name, external_gateway=external_gateway)
index 7e910a4..8b0a7b4 100644 (file)
@@ -31,7 +31,8 @@ dev_os_env_file = pkg_resources.resource_filename(
 class OSComponentTestCase(unittest.TestCase):
 
     def __init__(self, method_name='runTest', os_creds=None, ext_net_name=None,
-                 image_metadata=None, log_level=logging.DEBUG):
+                 flavor_metadata=None, image_metadata=None,
+                 log_level=logging.DEBUG):
         """
         Super for test classes requiring a connection to OpenStack
         :param method_name: default 'runTest'
@@ -39,6 +40,8 @@ class OSComponentTestCase(unittest.TestCase):
                          in the package snaps.openstack.tests.conf.os_env.yaml
         :param ext_net_name: the name of the external network that is used for
                              creating routers for floating IPs
+        :param flavor_metadata: dict() to be sent directly into the Nova client
+                                generally used for page sizes
         :param image_metadata: ability to override images being used in the
                                tests (see examples/image-metadata)
         :param log_level: the logging level of your test run (default DEBUG)
@@ -47,23 +50,36 @@ class OSComponentTestCase(unittest.TestCase):
 
         logging.basicConfig(level=log_level)
 
+        self.ext_net_name = None
+        self.flavor_metadata = None
+
         if os_creds:
             self.os_creds = os_creds
         else:
-            self.os_creds = openstack_tests.get_credentials(
-                dev_os_env_file=dev_os_env_file)
-
-        self.ext_net_name = ext_net_name
-
-        if not self.ext_net_name and file_utils.file_exists(dev_os_env_file):
-            test_conf = file_utils.read_yaml(dev_os_env_file)
-            self.ext_net_name = test_conf.get('ext_net')
+            if file_utils.file_exists(dev_os_env_file):
+                self.os_creds = openstack_tests.get_credentials(
+                    dev_os_env_file=dev_os_env_file)
+                test_conf = file_utils.read_yaml(dev_os_env_file)
+                self.ext_net_name = test_conf.get('ext_net')
+                os_env_dict = file_utils.read_yaml(dev_os_env_file)
+                flavor_metadata = os_env_dict.get('flavor_metadata')
+                if flavor_metadata:
+                    self.flavor_metadata = {'metadata': flavor_metadata}
+            else:
+                raise Exception('Unable to obtain OSCreds')
+
+        self.os_session = keystone_utils.keystone_session(self.os_creds)
 
         self.image_metadata = image_metadata
+        if not self.ext_net_name:
+            self.ext_net_name = ext_net_name
+        if not self.flavor_metadata:
+            self.flavor_metadata = flavor_metadata
 
     @staticmethod
     def parameterize(testcase_klass, os_creds, ext_net_name,
-                     image_metadata=None, log_level=logging.DEBUG):
+                     flavor_metadata=None, image_metadata=None,
+                     log_level=logging.DEBUG):
         """ Create a suite containing all tests taken from the given
             subclass, passing them the parameter 'param'.
         """
@@ -71,10 +87,18 @@ class OSComponentTestCase(unittest.TestCase):
         test_names = test_loader.getTestCaseNames(testcase_klass)
         suite = unittest.TestSuite()
         for name in test_names:
-            suite.addTest(testcase_klass(name, os_creds, ext_net_name,
-                                         image_metadata, log_level))
+            suite.addTest(testcase_klass(
+                name, os_creds, ext_net_name, flavor_metadata, image_metadata,
+                log_level))
         return suite
 
+    def __clean__(self):
+        """
+        Cleans up keystone session.
+        """
+        if self.os_session:
+            keystone_utils.close_session(self.os_session)
+
 
 class OSIntegrationTestCase(OSComponentTestCase):
 
@@ -104,16 +128,17 @@ class OSIntegrationTestCase(OSComponentTestCase):
         """
         super(OSIntegrationTestCase, self).__init__(
             method_name=method_name, os_creds=os_creds,
-            ext_net_name=ext_net_name, image_metadata=image_metadata,
-            log_level=log_level)
+            ext_net_name=ext_net_name, flavor_metadata=flavor_metadata,
+            image_metadata=image_metadata, log_level=log_level)
         self.netconf_override = netconf_override
         self.use_keystone = use_keystone
         self.keystone = None
-        self.flavor_metadata = flavor_metadata
+        self.user_roles = None
+        self.proj_users = None
 
     @staticmethod
     def parameterize(testcase_klass, os_creds, ext_net_name,
-                     use_keystone=False, flavor_metadata=None,
+                     use_keystone=True, flavor_metadata=None,
                      image_metadata=None, netconf_override=None,
                      log_level=logging.DEBUG):
         """
@@ -143,10 +168,11 @@ class OSIntegrationTestCase(OSComponentTestCase):
         self.project_creator = None
         self.user_creator = None
         self.admin_os_creds = self.os_creds
-        self.role = None
+        self.admin_os_session = self.os_session
+        self.keystone = keystone_utils.keystone_client(
+            self.admin_os_creds, self.admin_os_session)
 
         if self.use_keystone:
-            self.keystone = keystone_utils.keystone_client(self.admin_os_creds)
             guid = self.__class__.__name__ + '-' + str(uuid.uuid4())[:-19]
             project_name = guid + '-proj'
             self.project_creator = deploy_utils.create_project(
@@ -154,19 +180,31 @@ class OSIntegrationTestCase(OSComponentTestCase):
                     name=project_name,
                     domain=self.admin_os_creds.project_domain_name))
 
+            # Set by implementing class for setting the user's roles
+            roles = dict()
+            if self.user_roles and isinstance(self.user_roles, list):
+                for user_role in self.user_roles:
+                    roles[user_role] = project_name
+
             self.user_creator = deploy_utils.create_user(
                 self.admin_os_creds, UserConfig(
                     name=guid + '-user', password=guid,
-                    project_name=project_name, roles={
-                        'admin': self.project_creator.project_settings.name},
+                    project_name=project_name, roles=roles,
                     domain_name=self.admin_os_creds.user_domain_name))
 
             self.os_creds = self.user_creator.get_os_creds(
                 self.project_creator.project_settings.name)
+            self.os_session = keystone_utils.keystone_session(self.os_creds)
 
             # add user to project
             self.project_creator.assoc_user(self.user_creator.get_user())
 
+            if self.proj_users and isinstance(self.proj_users, list):
+                for user_name in self.proj_users:
+                    user = keystone_utils.get_user(self.keystone, user_name)
+                    if user:
+                        self.project_creator.assoc_user(user)
+
     def __clean__(self):
         """
         Cleans up test user and project.
@@ -174,11 +212,13 @@ class OSIntegrationTestCase(OSComponentTestCase):
         called during setUp() else these objects will persist after the test is
         run
         """
-        if self.role:
-            keystone_utils.delete_role(self.keystone, self.role)
-
         if self.project_creator:
             self.project_creator.clean()
 
         if self.user_creator:
             self.user_creator.clean()
+
+        if self.admin_os_session:
+            keystone_utils.close_session(self.admin_os_session)
+
+        super(OSIntegrationTestCase, self).__clean__()
index 7f92908..5435f8f 100644 (file)
@@ -12,4 +12,5 @@
 # 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.
-__author__ = 'spisarski'
\ No newline at end of file
+
+__author__ = 'spisarski'
index c50a166..61abe22 100644 (file)
@@ -33,37 +33,55 @@ Utilities for basic neutron API calls
 """
 
 
-def cinder_client(os_creds):
+def cinder_client(os_creds, session=None):
     """
     Creates and returns a cinder client object
+    :param os_creds: the credentials for connecting to the OpenStack remote API
+    :param session: the keystone session object (optional)
     :return: the cinder client
     """
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
+
     return Client(version=os_creds.volume_api_version,
-                  session=keystone_utils.keystone_session(os_creds),
+                  session=session,
                   region_name=os_creds.region_name)
 
 
-def get_volume(cinder, volume_name=None, volume_settings=None):
+def get_volume(cinder, keystone=None, volume_name=None, volume_settings=None,
+               project_name=None):
     """
     Returns an OpenStack volume object for a given name
     :param cinder: the Cinder client
+    :param keystone: the Keystone client (required if project_name or
+                     volume_settings.project_name is not None
     :param volume_name: the volume name to lookup
     :param volume_settings: the volume settings used for lookups
+    :param project_name: the name of the project associated with the volume
     :return: the volume object or None
     """
     if volume_settings:
         volume_name = volume_settings.name
 
     volumes = cinder.volumes.list()
-    for volume in volumes:
-        if volume.name == volume_name:
-            return Volume(
-                name=volume.name, volume_id=volume.id,
-                description=volume.description, size=volume.size,
-                vol_type=volume.volume_type,
-                availability_zone=volume.availability_zone,
-                multi_attach=volume.multiattach,
-                attachments=volume.attachments)
+    for os_volume in volumes:
+        if os_volume.name == volume_name:
+            project_id = None
+            if hasattr(os_volume, 'os-vol-tenant-attr:tenant_id'):
+                project_id = getattr(
+                    os_volume, 'os-vol-tenant-attr:tenant_id')
+
+            if volume_settings and volume_settings.project_name:
+                project_name = volume_settings.project_name
+
+            if project_name:
+                project = keystone_utils.get_project_by_id(
+                    keystone, project_id)
+
+                if project and project.name == project_name:
+                    return __map_os_volume_to_domain(os_volume)
+            else:
+                return __map_os_volume_to_domain(os_volume)
 
 
 def __get_os_volume_by_id(cinder, volume_id):
@@ -83,12 +101,29 @@ def get_volume_by_id(cinder, volume_id):
     :param volume_id: the volume ID to lookup
     :return: the SNAPS-OO Domain Volume object or None
     """
-    volume = __get_os_volume_by_id(cinder, volume_id)
+    os_volume = __get_os_volume_by_id(cinder, volume_id)
+    return __map_os_volume_to_domain(os_volume)
+
+
+def __map_os_volume_to_domain(os_volume):
+    """
+    Returns a SNAPS-OO domain Volume object that is created by an OpenStack
+    Volume object
+    :param os_volume: the OpenStack volume object
+    :return: Volume domain object
+    """
+    project_id = None
+    if hasattr(os_volume, 'os-vol-tenant-attr:tenant_id'):
+        project_id = getattr(
+            os_volume, 'os-vol-tenant-attr:tenant_id')
+
     return Volume(
-        name=volume.name, volume_id=volume.id, description=volume.description,
-        size=volume.size, vol_type=volume.volume_type,
-        availability_zone=volume.availability_zone,
-        multi_attach=volume.multiattach, attachments=volume.attachments)
+        name=os_volume.name, volume_id=os_volume.id,
+        project_id=project_id, description=os_volume.description,
+        size=os_volume.size, vol_type=os_volume.volume_type,
+        availability_zone=os_volume.availability_zone,
+        multi_attach=os_volume.multiattach,
+        attachments=os_volume.attachments)
 
 
 def get_volume_status(cinder, volume):
@@ -102,27 +137,36 @@ def get_volume_status(cinder, volume):
     return os_volume.status
 
 
-def create_volume(cinder, volume_settings):
+def create_volume(cinder, keystone, volume_settings):
     """
     Creates and returns OpenStack volume object with an external URL
     :param cinder: the cinder client
+    :param keystone: the keystone client
     :param volume_settings: the volume settings object
     :return: the OpenStack volume object
     :raise Exception if using a file and it cannot be found
     """
-    volume = cinder.volumes.create(
-        name=volume_settings.name, description=volume_settings.description,
-        size=volume_settings.size, imageRef=volume_settings.image_name,
+    project_id = None
+    if volume_settings.project_name:
+        project = keystone_utils.get_project(
+            keystone, project_name=volume_settings.project_name)
+        if project:
+            project_id = project.id
+        else:
+            raise KeystoneUtilsException(
+                'Project cannot be found with name - '
+                + volume_settings.project_name)
+    os_volume = cinder.volumes.create(
+        name=volume_settings.name,
+        project_id=project_id,
+        description=volume_settings.description,
+        size=volume_settings.size,
+        imageRef=volume_settings.image_name,
         volume_type=volume_settings.type_name,
         availability_zone=volume_settings.availability_zone,
         multiattach=volume_settings.multi_attach)
 
-    return Volume(
-        name=volume.name, volume_id=volume.id,
-        description=volume.description,
-        size=volume.size, vol_type=volume.volume_type,
-        availability_zone=volume.availability_zone,
-        multi_attach=volume.multiattach, attachments=volume.attachments)
+    return __map_os_volume_to_domain(os_volume)
 
 
 def delete_volume(cinder, volume):
@@ -367,3 +411,9 @@ def delete_qos(cinder, qos):
     """
     logger.info('Deleting QoS named - %s', qos.name)
     cinder.qos_specs.delete(qos.id)
+
+
+class KeystoneUtilsException(Exception):
+    """
+    Exception when calls to the Keystone client cannot be served properly
+    """
index a127ad3..db20f2f 100644 (file)
@@ -34,13 +34,18 @@ Utilities for basic neutron API calls
 """
 
 
-def glance_client(os_creds):
+def glance_client(os_creds, session=None):
     """
     Creates and returns a glance client object
+    :param os_creds: the credentials for connecting to the OpenStack remote API
+    :param session: the keystone session object (optional)
     :return: the glance client
     """
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
+
     return Client(version=os_creds.image_api_version,
-                  session=keystone_utils.keystone_session(os_creds),
+                  session=session,
                   region_name=os_creds.region_name)
 
 
index e440717..17de020 100644 (file)
 import logging
 import os
 
-import yaml
 from heatclient.client import Client
 from heatclient.common.template_format import yaml_loader
 from novaclient.exceptions import NotFound
 from oslo_serialization import jsonutils
+import yaml
 
 from snaps import file_utils
 from snaps.domain.stack import Stack, Resource, Output
-
 from snaps.openstack.utils import (
     keystone_utils, neutron_utils, nova_utils, cinder_utils)
+from snaps.thread_utils import worker_pool
+
 
 __author__ = 'spisarski'
 
 logger = logging.getLogger('heat_utils')
 
 
-def heat_client(os_creds):
+def heat_client(os_creds, session=None):
     """
     Retrieves the Heat client
     :param os_creds: the OpenStack credentials
     :return: the client
     """
     logger.debug('Retrieving Heat Client')
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
     return Client(os_creds.heat_api_version,
-                  session=keystone_utils.keystone_session(os_creds),
+                  session=session,
                   region_name=os_creds.region_name)
 
 
@@ -65,7 +68,11 @@ def get_stack(heat_cli, stack_settings=None, stack_name=None):
 
     stacks = heat_cli.stacks.list(**stack_filter)
     for stack in stacks:
-        return Stack(name=stack.identifier, stack_id=stack.id)
+        return Stack(
+            name=stack.stack_name, stack_id=stack.id,
+            stack_project_id=stack.stack_user_project_id,
+            status=stack.stack_status,
+            status_reason=stack.stack_status_reason)
 
 
 def get_stack_by_id(heat_cli, stack_id):
@@ -76,7 +83,11 @@ def get_stack_by_id(heat_cli, stack_id):
     :return: the Stack domain object else None
     """
     stack = heat_cli.stacks.get(stack_id)
-    return Stack(name=stack.identifier, stack_id=stack.id)
+    return Stack(
+        name=stack.stack_name, stack_id=stack.id,
+        stack_project_id=stack.stack_user_project_id,
+        status=stack.stack_status,
+        status_reason=stack.stack_status_reason)
 
 
 def get_stack_status(heat_cli, stack_id):
@@ -133,6 +144,24 @@ def create_stack(heat_cli, stack_settings):
     return get_stack_by_id(heat_cli, stack_id=stack['stack']['id'])
 
 
+def update_stack(heat_cli, stack, env_vals):
+    """
+    Updates the specified parameters in the stack
+    :param heat_cli: the OpenStack heat client object
+    :param stack_settings: the stack configuration
+    """
+    args = dict()
+
+    args['stack_name'] = stack.name
+    args['existing'] = True
+
+    if env_vals:
+        args['parameters'] = env_vals
+        heat_cli.stacks.update(stack.id, **args)
+    else:
+        logger.warn('Stack not updated, env_vals are None')
+
+
 def delete_stack(heat_cli, stack):
     """
     Deletes the Heat stack
@@ -210,8 +239,14 @@ def get_stack_networks(heat_cli, neutron, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Neutron::Net')
+    workers = []
     for resource in resources:
-        network = neutron_utils.get_network_by_id(neutron, resource.id)
+        worker = worker_pool().apply_async(neutron_utils.get_network_by_id,
+                                           (neutron, resource.id))
+        workers.append(worker)
+
+    for worker in workers:
+        network = worker.get()
         if network:
             out.append(network)
 
@@ -229,8 +264,14 @@ def get_stack_routers(heat_cli, neutron, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Neutron::Router')
+    workers = []
     for resource in resources:
-        router = neutron_utils.get_router_by_id(neutron, resource.id)
+        worker = worker_pool().apply_async(neutron_utils.get_router_by_id,
+                                           (neutron, resource.id))
+        workers.append(worker)
+
+    for worker in workers:
+        router = worker.get()
         if router:
             out.append(router)
 
@@ -248,47 +289,68 @@ def get_stack_security_groups(heat_cli, neutron, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Neutron::SecurityGroup')
+    workers = []
     for resource in resources:
-        security_group = neutron_utils.get_security_group_by_id(
-            neutron, resource.id)
+        worker = worker_pool().apply_async(
+            neutron_utils.get_security_group_by_id,
+            (neutron, resource.id))
+        workers.append(worker)
+
+    for worker in workers:
+        security_group = worker.get()
         if security_group:
             out.append(security_group)
 
     return out
 
 
-def get_stack_servers(heat_cli, nova, neutron, stack):
+def get_stack_servers(heat_cli, nova, neutron, keystone, stack, project_name):
     """
     Returns a list of VMInst domain objects associated with a Stack
     :param heat_cli: the OpenStack heat client object
     :param nova: the OpenStack nova client object
     :param neutron: the OpenStack neutron client object
+    :param keystone: the OpenStack keystone client object
     :param stack: the SNAPS-OO Stack domain object
+    :param project_name: the associated project ID
     :return: a list of VMInst domain objects
     """
 
     out = list()
     srvr_res = get_resources(heat_cli, stack.id, 'OS::Nova::Server')
+    workers = []
     for resource in srvr_res:
+        worker = worker_pool().apply_async(
+            nova_utils.get_server_object_by_id,
+            (nova, neutron, keystone, resource.id, project_name))
+        workers.append((resource.id, worker))
+
+    for worker in workers:
+        resource_id = worker[0]
         try:
-            server = nova_utils.get_server_object_by_id(
-                nova, neutron, resource.id)
+            server = worker[1].get()
             if server:
                 out.append(server)
         except NotFound:
-            logger.warn('VmInst cannot be located with ID %s', resource.id)
+            logger.warn('VmInst cannot be located with ID %s', resource_id)
 
     res_grps = get_resources(heat_cli, stack.id, 'OS::Heat::ResourceGroup')
     for res_grp in res_grps:
         res_ress = get_resources(heat_cli, res_grp.id)
+        workers = []
         for res_res in res_ress:
             res_res_srvrs = get_resources(
                 heat_cli, res_res.id, 'OS::Nova::Server')
             for res_srvr in res_res_srvrs:
-                server = nova_utils.get_server_object_by_id(
-                    nova, neutron, res_srvr.id)
-                if server:
-                    out.append(server)
+                worker = worker_pool().apply_async(
+                    nova_utils.get_server_object_by_id,
+                    (nova, neutron, keystone, res_srvr.id, project_name))
+                workers.append(worker)
+
+        for worker in workers:
+            server = worker.get()
+            if server:
+                out.append(server)
 
     return out
 
@@ -304,13 +366,20 @@ def get_stack_keypairs(heat_cli, nova, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Nova::KeyPair')
+    workers = []
     for resource in resources:
+        worker = worker_pool().apply_async(
+            nova_utils.get_keypair_by_id, (nova, resource.id))
+        workers.append((resource.id, worker))
+
+    for worker in workers:
+        resource_id = worker[0]
         try:
-            keypair = nova_utils.get_keypair_by_id(nova, resource.id)
+            keypair = worker[1].get()
             if keypair:
                 out.append(keypair)
         except NotFound:
-            logger.warn('Keypair cannot be located with ID %s', resource.id)
+            logger.warn('Keypair cannot be located with ID %s', resource_id)
 
     return out
 
@@ -326,13 +395,20 @@ def get_stack_volumes(heat_cli, cinder, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Cinder::Volume')
+    workers = []
     for resource in resources:
+        worker = worker_pool().apply_async(
+            cinder_utils.get_volume_by_id, (cinder, resource.id))
+        workers.append((resource.id, worker))
+
+    for worker in workers:
+        resource_id = worker[0]
         try:
-            server = cinder_utils.get_volume_by_id(cinder, resource.id)
+            server = worker[1].get()
             if server:
                 out.append(server)
         except NotFound:
-            logger.warn('Volume cannot be located with ID %s', resource.id)
+            logger.warn('Volume cannot be located with ID %s', resource_id)
 
     return out
 
@@ -348,13 +424,20 @@ def get_stack_volume_types(heat_cli, cinder, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Cinder::VolumeType')
+    workers = []
     for resource in resources:
+        worker = worker_pool().apply_async(
+            cinder_utils.get_volume_type_by_id, (cinder, resource.id))
+        workers.append((resource.id, worker))
+
+    for worker in workers:
+        resource_id = worker[0]
         try:
-            vol_type = cinder_utils.get_volume_type_by_id(cinder, resource.id)
+            vol_type = worker[1].get()
             if vol_type:
                 out.append(vol_type)
         except NotFound:
-            logger.warn('VolumeType cannot be located with ID %s', resource.id)
+            logger.warn('VolumeType cannot be located with ID %s', resource_id)
 
     return out
 
@@ -371,13 +454,20 @@ def get_stack_flavors(heat_cli, nova, stack):
 
     out = list()
     resources = get_resources(heat_cli, stack.id, 'OS::Nova::Flavor')
+    workers = []
     for resource in resources:
+        worker = worker_pool().apply_async(
+            nova_utils.get_flavor_by_id, (nova, resource.id))
+        workers.append((resource.id, worker))
+
+    for worker in workers:
+        resource_id = worker[0]
         try:
-            flavor = nova_utils.get_flavor_by_id(nova, resource.id)
+            flavor = worker[1].get()
             if flavor:
                 out.append(flavor)
         except NotFound:
-            logger.warn('Flavor cannot be located with ID %s', resource.id)
+            logger.warn('Flavor cannot be located with ID %s', resource_id)
 
     return out
 
index 6262d06..4d3c0d3 100644 (file)
 # limitations under the License.
 import logging
 
+import keystoneauth1
 from keystoneclient.client import Client
 from keystoneauth1.identity import v3, v2
 from keystoneauth1 import session
 import requests
+from keystoneclient.exceptions import NotFound
 
 from snaps.domain.project import Project, Domain
 from snaps.domain.role import Role
@@ -26,6 +28,7 @@ from snaps.domain.user import User
 logger = logging.getLogger('keystone_utils')
 
 V2_VERSION_NUM = 2.0
+V3_VERSION_NUM = 3
 V2_VERSION_STR = 'v' + str(V2_VERSION_NUM)
 
 
@@ -77,15 +80,29 @@ def keystone_session(os_creds):
                            verify=os_creds.cacert)
 
 
-def keystone_client(os_creds):
+def close_session(session):
+    """
+    Closes a keystone session
+    :param session: a session.Session object
+    """
+    if isinstance(session, keystoneauth1.session.Session):
+        session.session.close()
+
+
+def keystone_client(os_creds, session=None):
     """
     Returns the keystone client
     :param os_creds: the OpenStack credentials (OSCreds) object
+    :param session: the keystone session object (optional)
     :return: the client
     """
+
+    if not session:
+        session = keystone_session(os_creds)
+
     return Client(
         version=os_creds.identity_api_version,
-        session=keystone_session(os_creds),
+        session=session,
         interface=os_creds.interface,
         region_name=os_creds.region_name)
 
@@ -105,26 +122,16 @@ def get_endpoint(os_creds, service_type, interface='public'):
         interface=interface)
 
 
-def get_project(keystone=None, os_creds=None, project_settings=None,
-                project_name=None):
+def get_project(keystone=None, project_settings=None, project_name=None):
     """
     Returns the first project where the project_settings is used for the query
     if not None, else the project_name parameter is used for the query. If both
     parameters are None, None is returned
     :param keystone: the Keystone client
-    :param os_creds: the OpenStack credentials used to obtain the Keystone
-                     client if the keystone parameter is None
     :param project_settings: a ProjectConfig object
     :param project_name: the name to query
     :return: the SNAPS-OO Project domain object or None
     """
-    if not keystone:
-        if os_creds:
-            keystone = keystone_client(os_creds)
-        else:
-            raise KeystoneException(
-                'Cannot lookup project without the proper credentials')
-
     proj_filter = dict()
 
     if project_name:
@@ -152,6 +159,26 @@ def get_project(keystone=None, os_creds=None, project_settings=None,
                            domain_id=domain_id)
 
 
+def get_project_by_id(keystone, proj_id):
+    """
+    Returns the first project where the project_settings is used for the query
+    if not None, else the project_name parameter is used for the query. If both
+    parameters are None, None is returned
+    :param keystone: the Keystone client
+    :param proj_id: the project ID
+    """
+    if proj_id and len(proj_id) > 0:
+        try:
+            os_proj = keystone.projects.get(proj_id)
+            if os_proj:
+                return Project(name=os_proj.name, project_id=os_proj.id,
+                               domain_id=os_proj)
+        except NotFound:
+            pass
+        except KeyError:
+            pass
+
+
 def create_project(keystone, project_settings):
     """
     Creates a project
@@ -184,7 +211,7 @@ def create_project(keystone, project_settings):
 def delete_project(keystone, project):
     """
     Deletes a project
-    :param keystone: the Keystone clien
+    :param keystone: the Keystone client
     :param project: the SNAPS-OO Project domain object
     """
     logger.info('Deleting project with name - %s', project.name)
@@ -237,8 +264,8 @@ def create_user(keystone, user_settings):
     """
     project = None
     if user_settings.project_name:
-        project = get_project(keystone=keystone,
-                              project_name=user_settings.project_name)
+        project = get_project(
+            keystone=keystone, project_name=user_settings.project_name)
 
     if keystone.version == V2_VERSION_STR:
         project_id = None
index 05d4cb5..00ea822 100644 (file)
@@ -24,6 +24,7 @@ import os
 import time
 from keystoneauth1.exceptions import Unauthorized
 
+from snaps import file_utils
 from snaps.config.flavor import FlavorConfig
 from snaps.config.image import ImageConfig
 from snaps.config.keypair import KeypairConfig
@@ -48,7 +49,8 @@ from snaps.openstack.create_user import OpenStackUser
 from snaps.openstack.create_volume import OpenStackVolume
 from snaps.openstack.create_volume_type import OpenStackVolumeType
 from snaps.openstack.os_credentials import OSCreds, ProxySettings
-from snaps.openstack.utils import deploy_utils, neutron_utils
+from snaps.openstack.utils import deploy_utils, neutron_utils, keystone_utils
+from snaps.openstack.utils.nova_utils import RebootType
 from snaps.provisioning import ansible_utils
 
 logger = logging.getLogger('lanuch_utils')
@@ -118,7 +120,7 @@ def launch_config(config, tmplt_file, deploy, clean, clean_image):
             users_dict)
         creators.append(vol_type_dict)
 
-        # Create volume types
+        # Create volumes
         vol_dict = __create_instances(
             os_creds_dict, OpenStackVolume, VolumeConfig,
             os_config.get('volumes'), 'volume', clean, users_dict)
@@ -307,6 +309,8 @@ def __create_instances(os_creds_dict, creator_class, config_class, config,
                             creator.create()
 
                         out[inst_config['name']] = creator
+                    else:
+                        raise Exception('Unable to instantiate creator')
 
         logger.info('Initialized configured %ss', config_key)
 
@@ -415,10 +419,9 @@ def __apply_ansible_playbooks(ansible_configs, os_creds_dict, vm_dict,
                             'SSH requests')
                         return False
 
-            os_creds = os_creds_dict.get('admin-creds')
             __apply_ansible_playbook(
-                ansible_config, os_creds, vm_dict, image_dict, flavor_dict,
-                networks_dict, routers_dict)
+                ansible_config, os_creds_dict, vm_dict, image_dict,
+                flavor_dict, networks_dict, routers_dict)
 
         # Return to original directory
         os.chdir(orig_cwd)
@@ -426,12 +429,13 @@ def __apply_ansible_playbooks(ansible_configs, os_creds_dict, vm_dict,
     return True
 
 
-def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
-                             flavor_dict, networks_dict, routers_dict):
+def __apply_ansible_playbook(ansible_config, os_creds_dict, vm_dict,
+                             image_dict, flavor_dict, networks_dict,
+                             routers_dict):
     """
     Applies an Ansible configuration setting
     :param ansible_config: the configuration settings
-    :param os_creds: the OpenStack admin credentials object
+    :param os_creds_dict: dict where the key is the name and value is OSCreds
     :param vm_dict: the dictionary of newly instantiated VMs where the name is
                     the key
     :param image_dict: the dictionary of newly instantiated images where the
@@ -457,8 +461,8 @@ def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
                             'completed')
 
             variables = __get_variables(
-                ansible_config.get('variables'), os_creds, vm_dict, image_dict,
-                flavor_dict, networks_dict, routers_dict)
+                ansible_config.get('variables'), os_creds_dict, vm_dict,
+                image_dict, flavor_dict, networks_dict, routers_dict)
 
             retval = ansible_utils.apply_playbook(
                 ansible_config['playbook_location'], floating_ips, remote_user,
@@ -478,7 +482,7 @@ def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
                     for vm_name in post_proc_config['reboot']:
                         if vm_name in vm_dict:
                             logger.info('Rebooting VM - %s', vm_name)
-                            vm_dict[vm_name].reboot()
+                            vm_dict[vm_name].reboot(RebootType.hard)
 
             return retval
 
@@ -526,13 +530,13 @@ def __get_connection_info(ansible_config, vm_dict):
     return None
 
 
-def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict,
-                    networks_dict, routers_dict):
+def __get_variables(var_config, os_creds_dict, vm_dict, image_dict,
+                    flavor_dict, networks_dict, routers_dict):
     """
     Returns a dictionary of substitution variables to be used for Ansible
     templates
     :param var_config: the variable configuration settings
-    :param os_creds: the OpenStack admin credentials object
+    :param os_creds_dict: dict where the key is the name and value is OSCreds
     :param vm_dict: the dictionary of newly instantiated VMs where the name is
                     the key
     :param image_dict: the dictionary of newly instantiated images where the
@@ -549,7 +553,7 @@ def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict,
         variables = dict()
         for key, value in var_config.items():
             value = __get_variable_value(
-                value, os_creds, vm_dict, image_dict, flavor_dict,
+                value, os_creds_dict, vm_dict, image_dict, flavor_dict,
                 networks_dict, routers_dict)
             if key and value:
                 variables[key] = value
@@ -564,13 +568,13 @@ def __get_variables(var_config, os_creds, vm_dict, image_dict, flavor_dict,
     return None
 
 
-def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
+def __get_variable_value(var_config_values, os_creds_dict, vm_dict, image_dict,
                          flavor_dict, networks_dict, routers_dict):
     """
     Returns the associated variable value for use by Ansible for substitution
     purposes
     :param var_config_values: the configuration dictionary
-    :param os_creds: the OpenStack admin credentials object
+    :param os_creds_dict: dict where the key is the name and value is OSCreds
     :param vm_dict: the dictionary of newly instantiated VMs where the name is
                     the key
     :param image_dict: the dictionary of newly instantiated images where the
@@ -588,12 +592,14 @@ def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
     if var_config_values['type'] == 'vm-attr':
         return __get_vm_attr_variable_value(var_config_values, vm_dict)
     if var_config_values['type'] == 'os_creds':
-        return __get_os_creds_variable_value(var_config_values, os_creds)
+        return __get_os_creds_variable_value(var_config_values, os_creds_dict)
+    if var_config_values['type'] == 'os_creds_dict':
+        return str(__get_os_creds_dict(var_config_values, os_creds_dict))
     if var_config_values['type'] == 'network':
         return __get_network_variable_value(var_config_values, networks_dict)
     if var_config_values['type'] == 'router':
         return __get_router_variable_value(var_config_values, routers_dict,
-                                           os_creds)
+                                           os_creds_dict)
     if var_config_values['type'] == 'port':
         return __get_vm_port_variable_value(var_config_values, vm_dict)
     if var_config_values['type'] == 'floating_ip':
@@ -602,6 +608,8 @@ def __get_variable_value(var_config_values, os_creds, vm_dict, image_dict,
         return __get_image_variable_value(var_config_values, image_dict)
     if var_config_values['type'] == 'flavor':
         return __get_flavor_variable_value(var_config_values, flavor_dict)
+    if var_config_values['type'] == 'vm-yaml':
+        return __create_yaml(var_config_values, vm_dict)
     return None
 
 
@@ -630,13 +638,19 @@ def __get_vm_attr_variable_value(var_config_values, vm_dict):
             return vm.get_image_user()
 
 
-def __get_os_creds_variable_value(var_config_values, os_creds):
+def __get_os_creds_variable_value(var_config_values, os_creds_dict):
     """
     Returns the associated OS credentials value
     :param var_config_values: the configuration dictionary
-    :param os_creds: the admin OpenStack OSCreds object
+    :param os_creds_dict: dict of OpenStack credentials where the key is the
+                          name
     :return: the value
     """
+    if 'creds_name' in var_config_values:
+        os_creds = os_creds_dict.get[var_config_values['creds_name']]
+    else:
+        os_creds = os_creds_dict.get('admin-creds')
+
     if os_creds:
         if var_config_values['value'] == 'username':
             logger.info("Returning OS username")
@@ -652,6 +666,21 @@ def __get_os_creds_variable_value(var_config_values, os_creds):
             return os_creds.project_name
 
 
+def __get_os_creds_dict(var_config_values, os_creds_dict):
+    """
+    Returns the associated OS credentials as a dict
+    :param var_config_values: the configuration dictionary
+    :param os_creds_dict: dict of creds where the key is the username
+    :return: the value dict
+    """
+    if 'creds_name' in var_config_values:
+        os_creds = os_creds_dict.get[var_config_values['creds_name']]
+    else:
+        os_creds = os_creds_dict.get('admin-creds')
+    if os_creds:
+        return os_creds.to_dict()
+
+
 def __get_network_variable_value(var_config_values, networks_dict):
     """
     Returns the associated network value
@@ -675,6 +704,12 @@ def __get_network_variable_value(var_config_values, networks_dict):
                                 return subnet.gateway_ip
                             if 'ip_range' == var_config_values['value']:
                                 return subnet.start + ' ' + subnet.end
+                            if 'ip_range_start' == var_config_values['value']:
+                                return subnet.start
+                            if 'ip_range_end' == var_config_values['value']:
+                                return subnet.end
+                            if 'cidr' == var_config_values['value']:
+                                return subnet.cidr
                             if 'cidr_ip' == var_config_values['value']:
                                 cidr_split = subnet.cidr.split('/')
                                 return cidr_split[0]
@@ -693,32 +728,43 @@ def __get_network_variable_value(var_config_values, networks_dict):
                                 return broadcast_ip
 
 
-def __get_router_variable_value(var_config_values, routers_dict, os_creds):
+def __get_router_variable_value(var_config_values, routers_dict,
+                                os_creds_dict):
     """
     Returns the associated network value
     :param var_config_values: the configuration dictionary
     :param routers_dict: the dictionary containing all networks where the key
                           is the network name
-    :param os_creds: the admin OpenStack credentials
+    :param os_creds_dict: dict of OpenStack credentials where the key is the
+                          name
     :return: the value
     """
+    if 'creds_name' in var_config_values:
+        os_creds = os_creds_dict.get[var_config_values['creds_name']]
+    else:
+        os_creds = os_creds_dict.get('admin-creds')
+
     router_name = var_config_values.get('router_name')
     router_creator = routers_dict[router_name]
 
     if router_creator:
         if 'external_fixed_ip' == var_config_values.get('attr'):
-            neutron = neutron_utils.neutron_client(os_creds)
-            ext_nets = neutron_utils.get_external_networks(neutron)
+            session = keystone_utils.keystone_session(os_creds)
+            neutron = neutron_utils.neutron_client(os_creds, session)
+            try:
+                ext_nets = neutron_utils.get_external_networks(neutron)
 
-            subnet_name = var_config_values.get('subnet_name')
+                subnet_name = var_config_values.get('subnet_name')
 
-            for ext_net in ext_nets:
-                for subnet in ext_net.subnets:
-                    if subnet_name == subnet.name:
-                        router = router_creator.get_router()
-                        for fixed_ips in router.external_fixed_ips:
-                            if subnet.id == fixed_ips['subnet_id']:
-                                return fixed_ips['ip_address']
+                for ext_net in ext_nets:
+                    for subnet in ext_net.subnets:
+                        if subnet_name == subnet.name:
+                            router = router_creator.get_router()
+                            for fixed_ips in router.external_fixed_ips:
+                                if subnet.id == fixed_ips['subnet_id']:
+                                    return fixed_ips['ip_address']
+            finally:
+                keystone_utils.close_session(session)
 
 
 def __get_vm_port_variable_value(var_config_values, vm_dict):
@@ -801,6 +847,36 @@ def __get_flavor_variable_value(var_config_values, flavor_dict):
                     return flavor_creator.get_flavor().id
 
 
+def __create_yaml(var_config_values, vm_dict):
+    """
+    Creates a yaml file containing an OpenStack pod's credentials with a list
+    of server IDs that can be used for obtaining SNAPS-OO instances for
+    manipulation such as rebooting
+    :param var_config_values: the configuration dictionary
+    :param vm_dict: the dictionary containing all vm creators where the
+                    key is the name
+    :return: the name of the generated file
+    """
+    out_dict = dict()
+    out_dict['vms'] = list()
+    req_vm_names = var_config_values.get('vms')
+
+    for name, vm_creator in vm_dict.items():
+        vm_inst = vm_creator.get_vm_inst()
+        if vm_inst and vm_inst.name in req_vm_names:
+            out_dict['vms'].append({
+                'name': str(vm_inst.name),
+                'id': str(vm_inst.id),
+                'os_creds': vm_creator.get_os_creds().to_dict()
+            })
+
+    out_file = file_utils.persist_dict_to_yaml(
+        out_dict, var_config_values.get('file_name'))
+
+    if out_file:
+        return out_file.name
+
+
 def __cleanup(creators, clean_image=False):
     """
     Cleans up environment
index 96ba6d1..1f39cfe 100644 (file)
@@ -24,15 +24,18 @@ __author__ = 'spisarski'
 logger = logging.getLogger('magnum_utils')
 
 
-def magnum_client(os_creds):
+def magnum_client(os_creds, session=None):
     """
     Retrieves the Magnum client
     :param os_creds: the OpenStack credentialsf
+    :param session: the keystone session object (optional)
     :return: the client
     """
     logger.debug('Retrieving Magnum Client')
-    return Client(str(os_creds.magnum_api_version),
-                  session=keystone_utils.keystone_session(os_creds))
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
+
+    return Client(str(os_creds.magnum_api_version), session=session)
 
 
 def get_cluster_template(magnum, template_config=None, template_name=None):
index 725e251..c199b99 100644 (file)
@@ -33,15 +33,18 @@ Utilities for basic neutron API calls
 """
 
 
-def neutron_client(os_creds):
+def neutron_client(os_creds, session=None):
     """
     Instantiates and returns a client for communications with OpenStack's
     Neutron server
     :param os_creds: the credentials for connecting to the OpenStack remote API
+    :param session: the keystone session object (optional)
     :return: the client object
     """
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
     return Client(api_version=os_creds.network_api_version,
-                  session=keystone_utils.keystone_session(os_creds),
+                  session=session,
                   region_name=os_creds.region_name)
 
 
@@ -101,17 +104,18 @@ def delete_network(neutron, network):
         neutron.delete_network(network.id)
 
 
-def get_network(neutron, network_settings=None, network_name=None,
-                project_id=None):
+def get_network(neutron, keystone, network_settings=None, network_name=None,
+                project_name=None):
     """
     Returns Network SNAPS-OO domain object the first network found with
     either the given attributes from the network_settings object if not None,
     else the query will use just the name from the network_name parameter.
-    When the project_id is included, that will be added to the query filter.
-    :param neutron: the client
+    When the project_name is included, that will be added to the query filter.
+    :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param network_settings: the NetworkConfig object used to create filter
     :param network_name: the name of the network to retrieve
-    :param project_id: the id of the network's project
+    :param project_name: the name of the network's project
     :return: a SNAPS-OO Network domain object
     """
     net_filter = dict()
@@ -120,13 +124,20 @@ def get_network(neutron, network_settings=None, network_name=None,
     elif network_name:
         net_filter['name'] = network_name
 
-    if project_id:
-        net_filter['project_id'] = project_id
-
     networks = neutron.list_networks(**net_filter)
     for network, netInsts in networks.items():
         for inst in netInsts:
-            return __map_network(neutron, inst)
+            if project_name:
+                if 'project_id' in inst.keys():
+                    project = keystone_utils.get_project_by_id(
+                        keystone, inst['project_id'])
+                else:
+                    project = keystone_utils.get_project_by_id(
+                        keystone, inst['tenant_id'])
+                if project and project.name == project_name:
+                    return __map_network(neutron, inst)
+            else:
+                return __map_network(neutron, inst)
 
 
 def __get_os_network_by_id(neutron, network_id):
@@ -199,16 +210,17 @@ def delete_subnet(neutron, subnet):
         neutron.delete_subnet(subnet.id)
 
 
-def get_subnet(neutron, subnet_settings=None, subnet_name=None):
+def get_subnet(neutron, network, subnet_settings=None, subnet_name=None):
     """
     Returns the first subnet object that fits the query else None including
     if subnet_settings or subnet_name parameters are None.
     :param neutron: the client
+    :param network: the associated SNAPS-OO Network domain object
     :param subnet_settings: the subnet settings of the object to retrieve
     :param subnet_name: the name of the subnet to retrieve
     :return: a SNAPS-OO Subnet domain object or None
     """
-    sub_filter = dict()
+    sub_filter = {'network_id': network.id}
     if subnet_settings:
         sub_filter['name'] = subnet_settings.name
         sub_filter['cidr'] = subnet_settings.cidr
@@ -239,6 +251,30 @@ def get_subnet(neutron, subnet_settings=None, subnet_name=None):
         return Subnet(**subnet)
 
 
+def get_subnet_by_name(neutron, keystone, subnet_name, project_name=None):
+    """
+    Returns the first subnet object that fits the query else None including
+    if subnet_settings or subnet_name parameters are None.
+    :param neutron: the Neutron client
+    :param keystone: the Keystone client
+    :param subnet_name: the name of the subnet to retrieve
+    :param project_name: the name of the associated project to the subnet to
+                         retrieve
+    :return: a SNAPS-OO Subnet domain object or None
+    """
+    sub_filter = {'name': subnet_name}
+    subnets = neutron.list_subnets(**sub_filter)
+    for subnet in subnets['subnets']:
+        subnet = Subnet(**subnet)
+        if project_name:
+            project = keystone_utils.get_project_by_id(
+                keystone, subnet.project_id)
+            if project and project.name == project_name:
+                return subnet
+        else:
+            return subnet
+
+
 def get_subnet_by_id(neutron, subnet_id):
     """
     Returns a SNAPS-OO Subnet domain object for a given ID
@@ -321,14 +357,17 @@ def get_router_by_id(neutron, router_id):
         return __map_router(neutron, router['router'])
 
 
-def get_router(neutron, router_settings=None, router_name=None):
+def get_router(neutron, keystone, router_settings=None, router_name=None,
+               project_name=None):
     """
     Returns the first router object (dictionary) found the given the settings
     values if not None, else finds the first with the value of the router_name
     parameter, else None
-    :param neutron: the client
+    :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param router_settings: the RouterConfig object
     :param router_name: the name of the network to retrieve
+    :param project_name: the name of the router's project
     :return: a SNAPS-OO Router domain object
     """
     router_filter = dict()
@@ -341,12 +380,17 @@ def get_router(neutron, router_settings=None, router_name=None):
     else:
         return None
 
-    routers = neutron.list_routers(**router_filter)
-
-    for routerInst in routers['routers']:
-        return __map_router(neutron, routerInst)
-
-    return None
+    os_routers = neutron.list_routers(**router_filter)
+    for os_router in os_routers['routers']:
+        if project_name:
+            if 'project_id' in os_router.keys():
+                project = keystone_utils.get_project_by_id(
+                    keystone, os_router['project_id'])
+            else:
+                project = keystone_utils.get_project_by_id(
+                    keystone, os_router['tenant_id'])
+            if project and project.name == project_name:
+                return __map_router(neutron, os_router)
 
 
 def __map_router(neutron, os_router):
@@ -460,10 +504,7 @@ def create_port(neutron, os_creds, port_settings):
     logger.info('Creating port for network with name - %s',
                 port_settings.network_name)
     os_port = neutron.create_port(body=json_body)['port']
-    return Port(name=os_port['name'], id=os_port['id'],
-                ips=os_port['fixed_ips'],
-                mac_address=os_port['mac_address'],
-                allowed_address_pairs=os_port['allowed_address_pairs'])
+    return Port(**os_port)
 
 
 def delete_port(neutron, port):
@@ -476,13 +517,16 @@ def delete_port(neutron, port):
     neutron.delete_port(port.id)
 
 
-def get_port(neutron, port_settings=None, port_name=None):
+def get_port(neutron, keystone, port_settings=None, port_name=None,
+             project_name=None):
     """
     Returns the first port object (dictionary) found for the given query
-    :param neutron: the client
+    :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param port_settings: the PortConfig object used for generating the query
     :param port_name: if port_settings is None, this name is the value to place
                       into the query
+    :param project_name: the associated project name
     :return: a SNAPS-OO Port domain object
     """
     port_filter = dict()
@@ -496,9 +540,15 @@ def get_port(neutron, port_settings=None, port_name=None):
             port_filter['device_id'] = port_settings.device_id
         if port_settings.mac_address:
             port_filter['mac_address'] = port_settings.mac_address
+        if port_settings.project_name:
+            project_name = port_settings.project_name
         if port_settings.network_name:
-            network = get_network(neutron,
-                                  network_name=port_settings.network_name)
+            network = get_network(
+                neutron, keystone, network_name=port_settings.network_name)
+            if network and not (network.shared or network.external):
+                network = get_network(
+                    neutron, keystone, network_name=port_settings.network_name,
+                    project_name=project_name)
             if network:
                 port_filter['network_id'] = network.id
     elif port_name:
@@ -506,7 +556,17 @@ def get_port(neutron, port_settings=None, port_name=None):
 
     ports = neutron.list_ports(**port_filter)
     for port in ports['ports']:
-        return Port(**port)
+        if project_name:
+            if 'project_id' in port.keys():
+                project = keystone_utils.get_project_by_id(
+                    keystone, port['project_id'])
+            else:
+                project = keystone_utils.get_project_by_id(
+                    keystone, port['tenant_id'])
+            if project and project.name == project_name:
+                return Port(**port)
+        else:
+            return Port(**port)
     return None
 
 
@@ -572,30 +632,31 @@ def delete_security_group(neutron, sec_grp):
     neutron.delete_security_group(sec_grp.id)
 
 
-def get_security_group(neutron, sec_grp_settings=None, sec_grp_name=None,
-                       project_id=None):
+def get_security_group(neutron, keystone, sec_grp_settings=None,
+                       sec_grp_name=None, project_name=None):
     """
     Returns the first security group for a given query. The query gets built
     from the sec_grp_settings parameter if not None, else only the name of
     the security group will be used, else if the query parameters are None then
     None will be returned
-    :param neutron: the client
+    :param neutron: the neutron client
+    :param keystone: the keystone client
     :param sec_grp_settings: an instance of SecurityGroupConfig object
     :param sec_grp_name: the name of security group object to retrieve
-    :param project_id: the ID of the project/tentant object that owns the
+    :param project_name: the name of the project/tentant object that owns the
                        secuity group to retrieve
     :return: a SNAPS-OO SecurityGroup domain object or None if not found
     """
 
     sec_grp_filter = dict()
-    if project_id:
-        sec_grp_filter['tenant_id'] = project_id
 
     if sec_grp_settings:
         sec_grp_filter['name'] = sec_grp_settings.name
 
         if sec_grp_settings.description:
             sec_grp_filter['description'] = sec_grp_settings.description
+        if sec_grp_settings.project_name:
+            project_name = sec_grp_settings.project_name
     elif sec_grp_name:
         sec_grp_filter['name'] = sec_grp_name
     else:
@@ -603,7 +664,17 @@ def get_security_group(neutron, sec_grp_settings=None, sec_grp_name=None,
 
     groups = neutron.list_security_groups(**sec_grp_filter)
     for group in groups['security_groups']:
-        return __map_os_security_group(neutron, group)
+        if project_name:
+            if 'project_id' in group.keys():
+                project = keystone_utils.get_project_by_id(
+                    keystone, group['project_id'])
+            else:
+                project = keystone_utils.get_project_by_id(
+                    keystone, group['tenant_id'])
+            if project and project_name == project.name:
+                return __map_os_security_group(neutron, group)
+        else:
+            return __map_os_security_group(neutron, group)
 
 
 def __map_os_security_group(neutron, os_sec_grp):
@@ -635,17 +706,35 @@ def get_security_group_by_id(neutron, sec_grp_id):
     return None
 
 
-def create_security_group_rule(neutron, sec_grp_rule_settings):
+def list_security_groups(neutron):
+
+    """
+    Lists the available security groups
+    :param neutron: the neutron client
+    """
+    logger.info('Listing the available security groups')
+    sec_groups = []
+    response = neutron.list_security_groups()
+    for sg in response['security_groups']:
+        sec_groups.append(__map_os_security_group(neutron, sg))
+
+    return sec_groups
+
+
+def create_security_group_rule(neutron, keystone, sec_grp_rule_settings,
+                               proj_name):
     """
     Creates a security group rule in OpenStack
-    :param neutron: the client
+    :param neutron: the neutron client
+    :param keystone: the keystone client
     :param sec_grp_rule_settings: the security group rule settings
+    :param proj_name: the default project name
     :return: a SNAPS-OO SecurityGroupRule domain object
     """
     logger.info('Creating security group to security group - %s',
                 sec_grp_rule_settings.sec_grp_name)
     os_rule = neutron.create_security_group_rule(
-        sec_grp_rule_settings.dict_for_neutron(neutron))
+        sec_grp_rule_settings.dict_for_neutron(neutron, keystone, proj_name))
     return SecurityGroupRule(**os_rule['security_group_rule'])
 
 
@@ -716,14 +805,11 @@ def get_external_networks(neutron):
     return out
 
 
-def get_floating_ips(neutron, ports=None):
+def get_port_floating_ips(neutron, ports):
     """
-    Returns all of the floating IPs
-    When ports is not None, FIPs returned must be associated with one of the
-    ports in the list and a tuple 2 where the first element being the port's
-    ID and the second being the FloatingIp SNAPS-OO domain object.
-    When ports is None, all known FloatingIp SNAPS-OO domain objects will be
-    returned in a list
+    Returns all of the floating IPs associated with the ports returned in a
+    list of tuples where the port object is in the first position and the
+    floating IP object is in the second
     :param neutron: the Neutron client
     :param ports: a list of tuple 2 where index 0 is the port name and index 1
                   is the SNAPS-OO Port object
@@ -733,21 +819,30 @@ def get_floating_ips(neutron, ports=None):
     out = list()
     fips = neutron.list_floatingips()
     for fip in fips['floatingips']:
-        if ports:
-            for port_name, port in ports:
-                if port and port.id == fip['port_id']:
-                    out.append((port.id, FloatingIp(**fip)))
-                    break
-        else:
-            out.append(FloatingIp(**fip))
+        for port_name, port in ports:
+            if port and port.id == fip['port_id']:
+                out.append((port.id, FloatingIp(**fip)))
+                break
+    return out
+
 
+def get_floating_ips(neutron):
+    """
+    Returns a list of all of the floating IPs
+    :param neutron: the Neutron client
+    """
+    out = list()
+    fips = neutron.list_floatingips()
+    for fip in fips['floatingips']:
+        out.append(FloatingIp(**fip))
     return out
 
 
-def create_floating_ip(neutron, ext_net_name, port_id=None):
+def create_floating_ip(neutron, keystone, ext_net_name, port_id=None):
     """
     Returns the floating IP object that was created with this call
     :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param ext_net_name: the name of the external network on which to apply the
                          floating IP address
     :param port_id: the ID of the port to which the floating IP will be
@@ -755,7 +850,7 @@ def create_floating_ip(neutron, ext_net_name, port_id=None):
     :return: the SNAPS FloatingIp object
     """
     logger.info('Creating floating ip to external network - ' + ext_net_name)
-    ext_net = get_network(neutron, network_name=ext_net_name)
+    ext_net = get_network(neutron, keystone, network_name=ext_net_name)
     if ext_net:
         body = {'floatingip': {'floating_network_id': ext_net.id}}
         if port_id:
index a8e051e..005b56f 100644 (file)
@@ -35,33 +35,41 @@ __author__ = 'spisarski'
 
 logger = logging.getLogger('nova_utils')
 
+POLL_INTERVAL = 3
+
 """
 Utilities for basic OpenStack Nova API calls
 """
 
 
-def nova_client(os_creds):
+def nova_client(os_creds, session=None):
     """
     Instantiates and returns a client for communications with OpenStack's Nova
     server
     :param os_creds: The connection credentials to the OpenStack API
+    :param session: the keystone session object (optional)
     :return: the client object
     """
     logger.debug('Retrieving Nova Client')
+    if not session:
+        session = keystone_utils.keystone_session(os_creds)
+
     return Client(os_creds.compute_api_version,
-                  session=keystone_utils.keystone_session(os_creds),
+                  session=session,
                   region_name=os_creds.region_name)
 
 
-def create_server(nova, neutron, glance, instance_config, image_config,
-                  keypair_config=None):
+def create_server(nova, keystone, neutron, glance, instance_config,
+                  image_config, project_name, keypair_config=None):
     """
     Creates a VM instance
     :param nova: the nova client (required)
+    :param keystone: the keystone client for retrieving projects (required)
     :param neutron: the neutron client for retrieving ports (required)
     :param glance: the glance client (required)
     :param instance_config: the VMInstConfig object (required)
     :param image_config: the VM's ImageConfig object (required)
+    :param project_name: the associated project name (required)
     :param keypair_config: the VM's KeypairConfig object (optional)
     :return: a snaps.domain.VmInst object
     """
@@ -69,7 +77,9 @@ def create_server(nova, neutron, glance, instance_config, image_config,
     ports = list()
 
     for port_setting in instance_config.port_settings:
-        port = neutron_utils.get_port(neutron, port_settings=port_setting)
+        port = neutron_utils.get_port(
+            neutron, keystone, port_settings=port_setting,
+            project_name=project_name)
         if port:
             ports.append(port)
         else:
@@ -118,22 +128,26 @@ def create_server(nova, neutron, glance, instance_config, image_config,
 
         server = nova.servers.create(**args)
 
-        return __map_os_server_obj_to_vm_inst(neutron, server)
+        return __map_os_server_obj_to_vm_inst(
+            neutron, keystone, server, project_name)
     else:
         raise NovaException(
             'Cannot create instance, image cannot be located with name %s',
             image_config.name)
 
 
-def get_server(nova, neutron, vm_inst_settings=None, server_name=None):
+def get_server(nova, neutron, keystone, vm_inst_settings=None,
+               server_name=None, project_id=None):
     """
     Returns a VmInst object for the first server instance found.
     :param nova: the Nova client
     :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param vm_inst_settings: the VmInstanceConfig object from which to build
                              the query if not None
     :param server_name: the server with this name to return if vm_inst_settings
                         is not None
+    :param project_id: the assocaited project ID
     :return: a snaps.domain.VmInst object or None if not found
     """
     search_opts = dict()
@@ -144,7 +158,8 @@ def get_server(nova, neutron, vm_inst_settings=None, server_name=None):
 
     servers = nova.servers.list(search_opts=search_opts)
     for server in servers:
-        return __map_os_server_obj_to_vm_inst(neutron, server)
+        return __map_os_server_obj_to_vm_inst(
+            neutron, keystone, server, project_id)
 
 
 def get_server_connection(nova, vm_inst_settings=None, server_name=None):
@@ -168,11 +183,14 @@ def get_server_connection(nova, vm_inst_settings=None, server_name=None):
         return server.links[0]
 
 
-def __map_os_server_obj_to_vm_inst(neutron, os_server):
+def __map_os_server_obj_to_vm_inst(neutron, keystone, os_server,
+                                   project_name=None):
     """
     Returns a VmInst object for an OpenStack Server object
-    :param neutron: the Neutron client (when None, ports will be empty)
+    :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param os_server: the OpenStack server object
+    :param project_name: the associated project name
     :return: an equivalent SNAPS-OO VmInst domain object
     """
     sec_grp_names = list()
@@ -185,10 +203,17 @@ def __map_os_server_obj_to_vm_inst(neutron, os_server):
     out_ports = list()
     if len(os_server.networks) > 0:
         for net_name, ips in os_server.networks.items():
-            network = neutron_utils.get_network(neutron, network_name=net_name)
-            ports = neutron_utils.get_ports(neutron, network, ips)
-            for port in ports:
-                out_ports.append(port)
+            network = neutron_utils.get_network(
+                neutron, keystone, network_name=net_name,
+                project_name=project_name)
+            if network:
+                ports = neutron_utils.get_ports(neutron, network, ips)
+                for port in ports:
+                    out_ports.append(port)
+            else:
+                raise NovaException(
+                    'Unable to locate network in project {} with '
+                    'name {}'.format(project_name, net_name))
 
     volumes = None
     if hasattr(os_server, 'os-extended-volumes:volumes_attached'):
@@ -198,7 +223,9 @@ def __map_os_server_obj_to_vm_inst(neutron, os_server):
         name=os_server.name, inst_id=os_server.id,
         image_id=os_server.image['id'], flavor_id=os_server.flavor['id'],
         ports=out_ports, keypair_name=os_server.key_name,
-        sec_grp_names=sec_grp_names, volume_ids=volumes)
+        sec_grp_names=sec_grp_names, volume_ids=volumes,
+        compute_host=os_server._info.get('OS-EXT-SRV-ATTR:host'),
+        availability_zone=os_server._info.get('OS-EXT-AZ:availability_zone'))
 
 
 def __get_latest_server_os_object(nova, server):
@@ -247,28 +274,35 @@ def get_server_console_output(nova, server):
     return None
 
 
-def get_latest_server_object(nova, neutron, server):
+def get_latest_server_object(nova, neutron, keystone, server, project_name):
     """
     Returns a server with a given id
     :param nova: the Nova client
     :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param server: the old server object
+    :param project_name: the associated project name
     :return: the list of servers or None if not found
     """
     server = __get_latest_server_os_object(nova, server)
-    return __map_os_server_obj_to_vm_inst(neutron, server)
+    return __map_os_server_obj_to_vm_inst(
+        neutron, keystone, server, project_name)
 
 
-def get_server_object_by_id(nova, neutron, server_id):
+def get_server_object_by_id(nova, neutron, keystone, server_id,
+                            project_name=None):
     """
     Returns a server with a given id
     :param nova: the Nova client
     :param neutron: the Neutron client
+    :param keystone: the Keystone client
     :param server_id: the server's id
+    :param project_name: the associated project name
     :return: an SNAPS-OO VmInst object or None if not found
     """
     server = __get_latest_server_os_object_by_id(nova, server_id)
-    return __map_os_server_obj_to_vm_inst(neutron, server)
+    return __map_os_server_obj_to_vm_inst(
+        neutron, keystone, server, project_name)
 
 
 def get_server_security_group_names(nova, server):
@@ -280,8 +314,9 @@ def get_server_security_group_names(nova, server):
     """
     out = list()
     os_vm_inst = __get_latest_server_os_object(nova, server)
-    for sec_grp_dict in os_vm_inst.security_groups:
-        out.append(sec_grp_dict['name'])
+    if hasattr(os_vm_inst, 'security_groups'):
+        for sec_grp_dict in os_vm_inst.security_groups:
+            out.append(sec_grp_dict['name'])
     return out
 
 
@@ -711,60 +746,73 @@ def update_quotas(nova, project_id, compute_quotas):
     return nova.quotas.update(project_id, **update_values)
 
 
-def attach_volume(nova, neutron, server, volume, timeout=None):
+def attach_volume(nova, neutron, keystone, server, volume, project_name,
+                  timeout=120):
     """
-    Attaches a volume to a server
+    Attaches a volume to a server. When the timeout parameter is used, a VmInst
+    object with the proper volume updates is returned unless it has not been
+    updated in the allotted amount of time then an Exception will be raised.
     :param nova: the nova client
     :param neutron: the neutron client
+    :param keystone: the neutron client
     :param server: the VMInst domain object
     :param volume: the Volume domain object
+    :param project_name: the associated project name
     :param timeout: denotes the amount of time to block to determine if the
-                    has been properly attached. When None, do not wait.
-    :return: the value from the nova call
+                    has been properly attached.
+    :return: updated VmInst object
     """
     nova.volumes.create_server_volume(server.id, volume.id)
 
-    if timeout:
-        start_time = time.time()
-        while time.time() < start_time + timeout:
-            vm = get_server_object_by_id(nova, neutron, server.id)
-            for vol_dict in vm.volume_ids:
-                if volume.id == vol_dict['id']:
-                    return vm
+    start_time = time.time()
+    while time.time() < start_time + timeout:
+        vm = get_server_object_by_id(
+            nova, neutron, keystone, server.id, project_name)
+        for vol_dict in vm.volume_ids:
+            if volume.id == vol_dict['id']:
+                return vm
+        time.sleep(POLL_INTERVAL)
 
-        return None
-    else:
-        return get_server_object_by_id(nova, neutron, server.id)
+    raise NovaException(
+        'Attach failed on volume - {} and server - {}'.format(
+            volume.id, server.id))
 
 
-def detach_volume(nova, neutron, server, volume, timeout=None):
+def detach_volume(nova, neutron, keystone, server, volume, project_name,
+                  timeout=120):
     """
-    Attaches a volume to a server
+    Detaches a volume to a server. When the timeout parameter is used, a VmInst
+    object with the proper volume updates is returned unless it has not been
+    updated in the allotted amount of time then an Exception will be raised.
     :param nova: the nova client
     :param neutron: the neutron client
+    :param keystone: the keystone client
     :param server: the VMInst domain object
     :param volume: the Volume domain object
+    :param project_name: the associated project name
     :param timeout: denotes the amount of time to block to determine if the
-                    has been properly detached. When None, do not wait.
-    :return: the value from the nova call
+                    has been properly detached.
+    :return: updated VmInst object
     """
     nova.volumes.delete_server_volume(server.id, volume.id)
 
-    if timeout:
-        start_time = time.time()
-        while time.time() < start_time + timeout:
-            vm = get_server_object_by_id(nova, neutron, server.id)
-            found = False
+    start_time = time.time()
+    while time.time() < start_time + timeout:
+        vm = get_server_object_by_id(
+            nova, neutron, keystone, server.id, project_name)
+        if len(vm.volume_ids) == 0:
+            return vm
+        else:
+            ids = list()
             for vol_dict in vm.volume_ids:
-                if volume.id == vol_dict['id']:
-                    found = True
-
-            if not found:
+                ids.append(vol_dict['id'])
+            if volume.id not in ids:
                 return vm
+        time.sleep(POLL_INTERVAL)
 
-        return None
-    else:
-        return get_server_object_by_id(nova, neutron, server.id)
+    raise NovaException(
+        'Detach failed on volume - {} server - {}'.format(
+            volume.id, server.id))
 
 
 class RebootType(enum.Enum):
index 2cf6047..e43f8f5 100644 (file)
@@ -224,14 +224,16 @@ def create_keypair_config(heat_cli, stack, keypair, pk_output_key):
     return KeypairConfig(name=keypair.name)
 
 
-def create_vm_inst_config(nova, neutron, server):
+def create_vm_inst_config(nova, keystone, neutron, server, project_name):
     """
     Returns a VmInstanceConfig object
     note: if the server instance is not active, the PortSettings objects will
     not be generated resulting in an invalid configuration
     :param nova: the nova client
+    :param keystone: the keystone client
     :param neutron: the neutron client
     :param server: a SNAPS-OO VmInst domain object
+    :param project_name: the associated project name
     :return:
     """
 
@@ -244,7 +246,7 @@ def create_vm_inst_config(nova, neutron, server):
     kwargs['port_settings'] = __create_port_configs(neutron, server.ports)
     kwargs['security_group_names'] = server.sec_grp_names
     kwargs['floating_ip_settings'] = __create_floatingip_config(
-        neutron, kwargs['port_settings'])
+        neutron, keystone, kwargs['port_settings'], project_name)
 
     return VmInstanceConfig(**kwargs)
 
@@ -281,11 +283,12 @@ def __create_port_configs(neutron, ports):
     return out
 
 
-def __create_floatingip_config(neutron, port_settings):
+def __create_floatingip_config(neutron, keystone, port_settings, project_name):
     """
     Returns a list of FloatingIpConfig objects as they pertain to an
     existing deployed server instance
     :param neutron: the neutron client
+    :param keystone: the keystone client
     :param port_settings: list of SNAPS-OO PortConfig objects
     :return: a list of FloatingIpConfig objects or an empty list if no
              floating IPs have been created
@@ -296,10 +299,11 @@ def __create_floatingip_config(neutron, port_settings):
 
     fip_ports = list()
     for port_setting in port_settings:
-        setting_port = neutron_utils.get_port(neutron, port_setting)
+        setting_port = neutron_utils.get_port(
+            neutron, keystone, port_setting, project_name=project_name)
         if setting_port:
             network = neutron_utils.get_network(
-                neutron, network_name=port_setting.network_name)
+                neutron, keystone, network_name=port_setting.network_name)
             network_ports = neutron_utils.get_ports(neutron, network)
             if network_ports:
                 for setting_port in network_ports:
@@ -307,7 +311,7 @@ def __create_floatingip_config(neutron, port_settings):
                         fip_ports.append((port_setting.name, setting_port))
                         break
 
-    floating_ips = neutron_utils.get_floating_ips(neutron, fip_ports)
+    floating_ips = neutron_utils.get_port_floating_ips(neutron, fip_ports)
 
     for port_id, floating_ip in floating_ips:
         router = neutron_utils.get_router_by_id(neutron, floating_ip.router_id)
index b624b09..073d574 100644 (file)
@@ -26,7 +26,7 @@ from snaps.openstack import create_volume
 from snaps.openstack.create_qos import Consumer
 from snaps.openstack.tests import validation_utils
 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
-from snaps.openstack.utils import cinder_utils
+from snaps.openstack.utils import cinder_utils, keystone_utils
 
 __author__ = 'spisarski'
 
@@ -43,7 +43,7 @@ class CinderSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        cinder = cinder_utils.cinder_client(self.os_creds)
+        cinder = cinder_utils.cinder_client(self.os_creds, self.os_session)
         volumes = cinder.volumes.list()
         self.assertIsNotNone(volumes)
         self.assertTrue(isinstance(volumes, list))
@@ -74,7 +74,10 @@ class CinderUtilsVolumeTests(OSComponentTestCase):
         guid = uuid.uuid4()
         self.volume_name = self.__class__.__name__ + '-' + str(guid)
         self.volume = None
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -94,14 +97,15 @@ class CinderUtilsVolumeTests(OSComponentTestCase):
         """
         volume_settings = VolumeConfig(name=self.volume_name)
         self.volume = cinder_utils.create_volume(
-            self.cinder, volume_settings)
+            self.cinder, self.keystone, volume_settings)
         self.assertIsNotNone(self.volume)
         self.assertEqual(self.volume_name, self.volume.name)
 
         self.assertTrue(volume_active(self.cinder, self.volume))
 
         volume = cinder_utils.get_volume(
-            self.cinder, volume_settings=volume_settings)
+            self.cinder, self.keystone, volume_settings=volume_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(volume)
         validation_utils.objects_equivalent(self.volume, volume)
 
@@ -111,21 +115,24 @@ class CinderUtilsVolumeTests(OSComponentTestCase):
         """
         volume_settings = VolumeConfig(name=self.volume_name)
         self.volume = cinder_utils.create_volume(
-            self.cinder, volume_settings)
+            self.cinder, self.keystone, volume_settings)
         self.assertIsNotNone(self.volume)
         self.assertEqual(self.volume_name, self.volume.name)
 
         self.assertTrue(volume_active(self.cinder, self.volume))
 
         volume = cinder_utils.get_volume(
-            self.cinder, volume_settings=volume_settings)
+            self.cinder, self.keystone, volume_settings=volume_settings,
+            project_name=self.os_creds.project_name)
         self.assertIsNotNone(volume)
         validation_utils.objects_equivalent(self.volume, volume)
 
         cinder_utils.delete_volume(self.cinder, self.volume)
         self.assertTrue(volume_deleted(self.cinder, self.volume))
         self.assertIsNone(
-            cinder_utils.get_volume(self.cinder, volume_settings))
+            cinder_utils.get_volume(
+                self.cinder, self.keystone, volume_settings,
+                project_name=self.os_creds.project_name))
 
 
 def volume_active(cinder, volume):
@@ -181,7 +188,8 @@ class CinderUtilsQoSTests(OSComponentTestCase):
         self.qos_name = self.__class__.__name__ + '-' + str(guid)
         self.specs = {'foo': 'bar '}
         self.qos = None
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -193,6 +201,8 @@ class CinderUtilsQoSTests(OSComponentTestCase):
             except NotFound:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_qos_both(self):
         """
         Tests the cinder_utils.create_qos()
@@ -278,7 +288,8 @@ class CinderUtilsSimpleVolumeTypeTests(OSComponentTestCase):
         volume_type_name = self.__class__.__name__ + '-' + str(guid)
         self.volume_type_settings = VolumeTypeConfig(name=volume_type_name)
         self.volume_type = None
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -290,6 +301,8 @@ class CinderUtilsSimpleVolumeTypeTests(OSComponentTestCase):
             except NotFound:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_simple_volume_type(self):
         """
         Tests the cinder_utils.create_volume_type(), get_volume_type(), and
@@ -346,7 +359,8 @@ class CinderUtilsAddEncryptionTests(OSComponentTestCase):
         self.encryption_name = self.__class__.__name__ + '-' + str(guid)
         self.encryption = None
 
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
         volume_type_name = self.__class__.__name__ + '-' + str(guid) + '-type'
         self.volume_type = cinder_utils.create_volume_type(
@@ -369,6 +383,8 @@ class CinderUtilsAddEncryptionTests(OSComponentTestCase):
             except NotFound:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_simple_encryption(self):
         """
         Tests the cinder_utils.create_volume_encryption(),
@@ -463,7 +479,8 @@ class CinderUtilsVolumeTypeCompleteTests(OSComponentTestCase):
         self.qos_name = self.__class__.__name__ + '-' + str(guid) + '-qos'
         self.vol_type_name = self.__class__.__name__ + '-' + str(guid)
         self.specs = {'foo': 'bar'}
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
         qos_settings = QoSConfig(
             name=self.qos_name, specs=self.specs, consumer=Consumer.both)
         self.qos = cinder_utils.create_qos(self.cinder, qos_settings)
@@ -491,6 +508,8 @@ class CinderUtilsVolumeTypeCompleteTests(OSComponentTestCase):
             except NotFound:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_with_encryption(self):
         """
         Tests the cinder_utils.create_volume_type() where encryption has been
index e61b795..e761ed8 100644 (file)
@@ -39,7 +39,7 @@ class GlanceSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        glance = glance_utils.glance_client(self.os_creds)
+        glance = glance_utils.glance_client(self.os_creds, self.os_session)
         image = glance_utils.get_image(glance, image_name='foo')
         self.assertIsNone(image)
 
@@ -69,7 +69,8 @@ class GlanceUtilsTests(OSComponentTestCase):
         guid = uuid.uuid4()
         self.image_name = self.__class__.__name__ + '-' + str(guid)
         self.image = None
-        self.glance = glance_utils.glance_client(self.os_creds)
+        self.glance = glance_utils.glance_client(
+            self.os_creds, self.os_session)
         if self.image_metadata:
             self.glance_test_meta = self.image_metadata.get('glance_tests')
         else:
@@ -89,6 +90,8 @@ class GlanceUtilsTests(OSComponentTestCase):
         if os.path.exists(self.tmp_dir) and os.path.isdir(self.tmp_dir):
             shutil.rmtree(self.tmp_dir)
 
+        super(self.__class__, self).__clean__()
+
     def test_create_image_minimal_url(self):
         """
         Tests the glance_utils.create_image() function with a URL unless the
index 67fbdec..fa240bd 100644 (file)
@@ -31,7 +31,7 @@ from snaps.openstack.tests import openstack_tests
 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
 from snaps.openstack.utils import (
     heat_utils, neutron_utils, nova_utils, settings_utils, glance_utils,
-    cinder_utils)
+    cinder_utils, keystone_utils)
 
 __author__ = 'spisarski'
 
@@ -47,12 +47,12 @@ class HeatSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        heat = heat_utils.heat_client(self.os_creds)
+        heat = heat_utils.heat_client(self.os_creds, self.os_session)
 
         # This should not throw an exception
         stacks = heat.stacks.list()
         for stack in stacks:
-            print stack
+            logger.info('Stack - %s', stack)
 
     def test_heat_connect_fail(self):
         """
@@ -70,7 +70,7 @@ class HeatSmokeTests(OSComponentTestCase):
         # This should throw an exception
         with self.assertRaises(Exception):
             for stack in stacks:
-                print stack
+                logger.info('Stack - %s', stack)
 
 
 class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
@@ -115,7 +115,8 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
             env_values=env_values)
         self.stack1 = None
         self.stack2 = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -145,6 +146,8 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_stack(self):
         """
         Tests the creation of an OpenStack Heat stack1 that does not exist.
@@ -174,7 +177,7 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
 
         self.assertTrue(stack_active(self.heat_client, self.stack1))
 
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
         networks = heat_utils.get_stack_networks(
             self.heat_client, neutron, self.stack1)
         self.assertIsNotNone(networks)
@@ -185,9 +188,12 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
         self.assertEqual(1, len(subnets))
         self.assertEqual(self.subnet_name, subnets[0].name)
 
-        nova = nova_utils.nova_client(self.os_creds)
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         servers = heat_utils.get_stack_servers(
-            self.heat_client, nova, neutron, self.stack1)
+            self.heat_client, nova, neutron, keystone, self.stack1,
+            self.os_creds.project_name)
         self.assertIsNotNone(servers)
         self.assertEqual(1, len(servers))
         self.assertEqual(self.vm_inst_name, servers[0].name)
@@ -275,7 +281,8 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
         stack_settings = StackConfig(
             name=stack_name, template_path=heat_tmplt_path,
             env_values=env_values)
-        self.heat_client = heat_utils.heat_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
         self.stack = heat_utils.create_stack(self.heat_client, stack_settings)
 
         self.assertTrue(stack_active(self.heat_client, self.stack))
@@ -307,14 +314,22 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
                     time.sleep(3)
 
                 if not is_deleted:
-                    nova = nova_utils.nova_client(self.os_creds)
-                    neutron = neutron_utils.neutron_client(self.os_creds)
-                    glance = glance_utils.glance_client(self.os_creds)
+                    nova = nova_utils.nova_client(
+                        self.os_creds, self.os_session)
+                    keystone = keystone_utils.keystone_client(
+                        self.os_creds, self.os_session)
+                    neutron = neutron_utils.neutron_client(
+                        self.os_creds, self.os_session)
+                    glance = glance_utils.glance_client(
+                        self.os_creds, self.os_session)
+
                     servers = heat_utils.get_stack_servers(
-                        self.heat_client, nova, neutron, self.stack)
+                        self.heat_client, nova, neutron, keystone, self.stack,
+                        self.os_creds.project_name)
                     for server in servers:
                         vm_settings = settings_utils.create_vm_inst_config(
-                            nova, neutron, server)
+                            nova, keystone, neutron, server,
+                            self.os_creds.project_name)
                         img_settings = settings_utils.determine_image_config(
                             glance, server,
                             [self.image_creator1.image_settings,
@@ -354,6 +369,8 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
             os.chmod(expanded_path, 0o755)
             os.remove(expanded_path)
 
+        super(self.__class__, self).__clean__()
+
     def test_get_settings_from_stack(self):
         """
         Tests that a heat template with floating IPs and can have the proper
@@ -361,13 +378,13 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
         """
         resources = heat_utils.get_resources(self.heat_client, self.stack.id)
         self.assertIsNotNone(resources)
-        self.assertEqual(12, len(resources))
+        self.assertEqual(13, len(resources))
 
         options = heat_utils.get_outputs(self.heat_client, self.stack)
         self.assertIsNotNone(options)
         self.assertEqual(1, len(options))
 
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
         networks = heat_utils.get_stack_networks(
             self.heat_client, neutron, self.stack)
         self.assertIsNotNone(networks)
@@ -379,11 +396,13 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
         self.assertIsNotNone(network_settings)
         self.assertEqual(self.network_name, network_settings.name)
 
-        nova = nova_utils.nova_client(self.os_creds)
-        glance = glance_utils.glance_client(self.os_creds)
-
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
+        glance = glance_utils.glance_client(self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         servers = heat_utils.get_stack_servers(
-            self.heat_client, nova, neutron, self.stack)
+            self.heat_client, nova, neutron, keystone, self.stack,
+            self.os_creds.project_name)
         self.assertIsNotNone(servers)
         self.assertEqual(2, len(servers))
 
@@ -452,8 +471,10 @@ class HeatUtilsRouterTests(OSComponentTestCase):
             name=stack_name, template_path=heat_tmplt_path,
             env_values=env_values)
         self.stack = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -465,6 +486,8 @@ class HeatUtilsRouterTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_router_with_stack(self):
         """
         Tests the creation of an OpenStack router with Heat and the retrieval
@@ -498,8 +521,10 @@ class HeatUtilsRouterTests(OSComponentTestCase):
         router = routers[0]
         self.assertEqual(self.router_name, router.name)
 
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         ext_net = neutron_utils.get_network(
-            self.neutron, network_name=self.ext_net_name)
+            self.neutron, keystone, network_name=self.ext_net_name)
         self.assertEqual(ext_net.id, router.external_network_id)
 
 
@@ -527,8 +552,10 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
             name=stack_name, template_path=heat_tmplt_path,
             env_values=env_values)
         self.stack = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -540,6 +567,8 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_vol_with_stack(self):
         """
         Tests the creation of an OpenStack volume with Heat.
@@ -607,8 +636,10 @@ class HeatUtilsFlavorTests(OSComponentTestCase):
         self.stack_settings = StackConfig(
             name=stack_name, template_path=heat_tmplt_path)
         self.stack = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
+        self.nova = nova_utils.nova_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -620,6 +651,8 @@ class HeatUtilsFlavorTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_flavor_with_stack(self):
         """
         Tests the creation of an OpenStack volume with Heat.
@@ -666,8 +699,10 @@ class HeatUtilsKeypairTests(OSComponentTestCase):
             name=stack_name, template_path=heat_tmplt_path,
             env_values=env_values)
         self.stack = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
+        self.nova = nova_utils.nova_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -679,6 +714,8 @@ class HeatUtilsKeypairTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_keypair_with_stack(self):
         """
         Tests the creation of an OpenStack keypair with Heat.
@@ -729,8 +766,10 @@ class HeatUtilsSecurityGroupTests(OSComponentTestCase):
             name=stack_name, template_path=heat_tmplt_path,
             env_values=env_values)
         self.stack = None
-        self.heat_client = heat_utils.heat_client(self.os_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.heat_client = heat_utils.heat_client(
+            self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -742,6 +781,8 @@ class HeatUtilsSecurityGroupTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_security_group_with_stack(self):
         """
         Tests the creation of an OpenStack SecurityGroup with Heat.
index 2916003..cc3a8ad 100644 (file)
@@ -31,7 +31,8 @@ class KeystoneSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        keystone = keystone_utils.keystone_client(self.os_creds)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
         users = keystone.users.list()
         self.assertIsNotNone(users)
@@ -66,17 +67,19 @@ class KeystoneUtilsTests(OSComponentTestCase):
         self.project_name = self.guid + '-projName'
         self.project = None
         self.role = None
-        self.keystone = keystone_utils.keystone_client(self.os_creds)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
         Cleans the remote OpenStack objects
         """
         if self.project:
-            neutron = neutron_utils.neutron_client(self.os_creds)
+            neutron = neutron_utils.neutron_client(
+                self.os_creds, self.os_session)
             default_sec_grp = neutron_utils.get_security_group(
-                neutron, sec_grp_name='default',
-                project_id=self.project.id)
+                neutron, self.keystone, sec_grp_name='default',
+                project_name=self.os_creds.project_name)
             if default_sec_grp:
                 try:
                     neutron_utils.delete_security_group(
@@ -92,6 +95,8 @@ class KeystoneUtilsTests(OSComponentTestCase):
         if self.role:
             keystone_utils.delete_role(self.keystone, self.role)
 
+        super(self.__class__, self).__clean__()
+
     def test_create_user_minimal(self):
         """
         Tests the keystone_utils.create_user() function
index f841c48..d87d97a 100644 (file)
@@ -44,7 +44,8 @@ class MagnumSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        magnum = magnum_utils.magnum_client(self.os_creds)
+        magnum = magnum_utils.magnum_client(
+            self.os_creds, self.os_session)
 
         # This should not throw an exception
         self.assertIsNotNone(magnum.clusters.list())
@@ -70,7 +71,8 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase):
     def setUp(self):
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.cluster_type_name = self.guid + '-cluster-type'
-        self.magnum = magnum_utils.magnum_client(self.os_creds)
+        self.magnum = magnum_utils.magnum_client(
+            self.os_creds, self.os_session)
 
         metadata = self.image_metadata
         if not metadata:
@@ -130,6 +132,8 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_cluster_template_simple(self):
         config = ClusterTemplateConfig(
             name=self.cluster_type_name,
index bc7491e..a55f779 100644 (file)
@@ -41,7 +41,7 @@ class NeutronSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
 
         networks = neutron.list_networks()
 
@@ -70,7 +70,7 @@ class NeutronSmokeTests(OSComponentTestCase):
         configured self.ext_net_name is contained within the returned list
         :return:
         """
-        neutron = neutron_utils.neutron_client(self.os_creds)
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
         ext_networks = neutron_utils.get_external_networks(neutron)
         found = False
         for network in ext_networks:
@@ -88,9 +88,13 @@ class NeutronUtilsNetworkTests(OSComponentTestCase):
     def setUp(self):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.port_name = str(guid) + '-port'
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.network = None
         self.net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net')
 
     def tearDown(self):
@@ -100,6 +104,8 @@ class NeutronUtilsNetworkTests(OSComponentTestCase):
         if self.network:
             neutron_utils.delete_network(self.neutron, self.network)
 
+        super(self.__class__, self).__clean__()
+
     def test_create_network(self):
         """
         Tests the neutron_utils.create_network() function
@@ -109,7 +115,9 @@ class NeutronUtilsNetworkTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
         self.assertEqual(len(self.net_config.network_settings.subnet_settings),
                          len(self.network.subnets))
 
@@ -142,9 +150,13 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
     def setUp(self):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.port_name = str(guid) + '-port'
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.network = None
         self.net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
             external_net=self.ext_net_name)
 
@@ -158,6 +170,8 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_subnet(self):
         """
         Tests the neutron_utils.create_network() function
@@ -167,14 +181,17 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         subnet_query1 = neutron_utils.get_subnet(
-            self.neutron, subnet_name=subnet_setting.name)
+            self.neutron, self.network, subnet_name=subnet_setting.name)
         self.assertEqual(self.network.subnets[0], subnet_query1)
 
         subnet_query2 = neutron_utils.get_subnets_by_network(self.neutron,
@@ -183,6 +200,12 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
         self.assertEqual(1, len(subnet_query2))
         self.assertEqual(self.network.subnets[0], subnet_query2[0])
 
+        subnet_query3 = neutron_utils.get_subnet_by_name(
+            self.neutron, self.keystone, subnet_setting.name,
+            self.os_creds.project_name)
+        self.assertIsNotNone(subnet_query3)
+        self.assertEqual(self.network.subnets[0], subnet_query3)
+
     def test_create_subnet_null_name(self):
         """
         Tests the neutron_utils.create_neutron_subnet() function for an
@@ -193,7 +216,9 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         with self.assertRaises(Exception):
             SubnetConfig(cidr=self.net_config.subnet_cidr)
@@ -208,20 +233,23 @@ class NeutronUtilsSubnetTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
         self.assertFalse(validate_subnet(
-            self.neutron, '', subnet_setting.cidr, True))
+            self.neutron, self.network, '', subnet_setting.cidr, True))
 
         subnet_query1 = neutron_utils.get_subnet(
-            self.neutron, subnet_name=subnet_setting.name)
+            self.neutron, self.network, subnet_name=subnet_setting.name)
         self.assertEqual(self.network.subnets[0], subnet_query1)
 
-        subnet_query2 = neutron_utils.get_subnets_by_network(self.neutron,
-                                                             self.network)
+        subnet_query2 = neutron_utils.get_subnets_by_network(
+            self.neutron, self.network)
         self.assertIsNotNone(subnet_query2)
         self.assertEqual(1, len(subnet_query2))
         self.assertEqual(self.network.subnets[0], subnet_query2[0])
@@ -254,7 +282,8 @@ class NeutronUtilsIPv6Tests(OSComponentTestCase):
 
     def setUp(self):
         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
         self.network = None
 
     def tearDown(self):
@@ -267,6 +296,8 @@ class NeutronUtilsIPv6Tests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_network_slaac(self):
         """
         Tests the neutron_utils.create_network() with an IPv6 subnet where DHCP
@@ -487,12 +518,16 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
     def setUp(self):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.port_name = str(guid) + '-port'
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.network = None
         self.port = None
         self.router = None
         self.interface_router = None
         self.net_config = openstack_tests.get_pub_net_config(
+            project_name=self.os_creds.project_name,
             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
             router_name=guid + '-pub-router', external_net=self.ext_net_name)
 
@@ -507,7 +542,9 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         if self.router:
             try:
                 neutron_utils.delete_router(self.neutron, self.router)
-                validate_router(self.neutron, self.router.name, False)
+                validate_router(
+                    self.neutron, self.keystone, self.router.name,
+                    self.os_creds.project_name, False)
             except:
                 pass
 
@@ -520,14 +557,17 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         if self.network:
             neutron_utils.delete_network(self.neutron, self.network)
 
+        super(self.__class__, self).__clean__()
+
     def test_create_router_simple(self):
         """
         Tests the neutron_utils.create_router()
         """
         self.router = neutron_utils.create_router(
             self.neutron, self.os_creds, self.net_config.router_settings)
-        validate_router(self.neutron, self.net_config.router_settings.name,
-                        True)
+        validate_router(
+            self.neutron, self.keystone, self.net_config.router_settings.name,
+            self.os_creds.project_name, True)
 
     def test_create_router_with_public_interface(self):
         """
@@ -535,18 +575,19 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         """
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.net_config = openstack_tests.OSNetworkConfig(
-            self.net_config.network_settings.name,
-            subnet_setting.name,
-            subnet_setting.cidr,
-            self.net_config.router_settings.name,
-            self.ext_net_name)
+            project_name=self.os_creds.project_name,
+            net_name=self.net_config.network_settings.name,
+            subnet_name=subnet_setting.name, subnet_cidr=subnet_setting.cidr,
+            router_name=self.net_config.router_settings.name,
+            external_gateway=self.ext_net_name)
         self.router = neutron_utils.create_router(
             self.neutron, self.os_creds, self.net_config.router_settings)
-        validate_router(self.neutron, self.net_config.router_settings.name,
-                        True)
+        validate_router(
+            self.neutron, self.keystone, self.net_config.router_settings.name,
+            self.os_creds.project_name, True)
 
         ext_net = neutron_utils.get_network(
-            self.neutron, network_name=self.ext_net_name)
+            self.neutron, self.keystone, network_name=self.ext_net_name)
         self.assertEqual(self.router.external_network_id, ext_net.id)
 
     def test_add_interface_router(self):
@@ -558,16 +599,20 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         self.router = neutron_utils.create_router(
             self.neutron, self.os_creds, self.net_config.router_settings)
-        validate_router(self.neutron, self.net_config.router_settings.name,
-                        True)
+        validate_router(
+            self.neutron, self.keystone, self.net_config.router_settings.name,
+            self.os_creds.project_name, True)
 
         self.interface_router = neutron_utils.add_interface_router(
             self.neutron, self.router, self.network.subnets[0])
@@ -584,11 +629,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         with self.assertRaises(NeutronException):
             self.interface_router = neutron_utils.add_interface_router(
@@ -604,12 +652,15 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         self.router = neutron_utils.create_router(
             self.neutron, self.os_creds, self.net_config.router_settings)
-        validate_router(self.neutron, self.net_config.router_settings.name,
-                        True)
+        validate_router(
+            self.neutron, self.keystone, self.net_config.router_settings.name,
+            self.os_creds.project_name, True)
 
         with self.assertRaises(NeutronException):
             self.interface_router = neutron_utils.add_interface_router(
@@ -625,12 +676,15 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         self.router = neutron_utils.create_router(
             self.neutron, self.os_creds, self.net_config.router_settings)
-        validate_router(self.neutron, self.net_config.router_settings.name,
-                        True)
+        validate_router(
+            self.neutron, self.keystone, self.net_config.router_settings.name,
+            self.os_creds.project_name, True)
 
         for subnet in self.network.subnets:
             neutron_utils.delete_subnet(self.neutron, subnet)
@@ -648,11 +702,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         self.port = neutron_utils.create_port(
             self.neutron, self.os_creds, PortConfig(
@@ -672,11 +729,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
-        self.assertTrue(validate_subnet(self.neutron, subnet_setting.name,
-                                        subnet_setting.cidr, True))
+        self.assertTrue(validate_subnet(
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         self.port = neutron_utils.create_port(
             self.neutron, self.os_creds, PortConfig(
@@ -696,11 +756,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         self.port = neutron_utils.create_port(
             self.neutron, self.os_creds,
@@ -740,11 +803,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         with self.assertRaises(Exception):
             self.port = neutron_utils.create_port(
@@ -766,11 +832,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         with self.assertRaises(Exception):
             self.port = neutron_utils.create_port(
@@ -792,11 +861,14 @@ class NeutronUtilsRouterTests(OSComponentTestCase):
         self.assertEqual(self.net_config.network_settings.name,
                          self.network.name)
         self.assertTrue(validate_network(
-            self.neutron, self.net_config.network_settings.name, True))
+            self.neutron, self.keystone,
+            self.net_config.network_settings.name, True,
+            self.os_creds.project_name))
 
         subnet_setting = self.net_config.network_settings.subnet_settings[0]
         self.assertTrue(validate_subnet(
-            self.neutron, subnet_setting.name, subnet_setting.cidr, True))
+            self.neutron, self.network, subnet_setting.name,
+            subnet_setting.cidr, True))
 
         with self.assertRaises(Exception):
             self.port = neutron_utils.create_port(
@@ -820,8 +892,10 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
 
         self.security_groups = list()
         self.security_group_rules = list()
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
-        self.keystone = keystone_utils.keystone_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -837,26 +911,27 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_delete_simple_sec_grp(self):
         """
         Tests the neutron_utils.create_security_group() function
         """
         sec_grp_settings = SecurityGroupConfig(name=self.sec_grp_name)
-        security_group = neutron_utils.create_security_group(self.neutron,
-                                                             self.keystone,
-                                                             sec_grp_settings)
+        security_group = neutron_utils.create_security_group(
+            self.neutron, self.keystone, sec_grp_settings)
 
         self.assertTrue(sec_grp_settings.name, security_group.name)
 
         sec_grp_get = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp_get)
         self.assertTrue(validation_utils.objects_equivalent(
             security_group, sec_grp_get))
 
         neutron_utils.delete_security_group(self.neutron, security_group)
         sec_grp_get = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNone(sec_grp_get)
 
     def test_create_sec_grp_no_name(self):
@@ -869,9 +944,8 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
         with self.assertRaises(Exception):
             sec_grp_settings = SecurityGroupConfig()
             self.security_groups.append(
-                neutron_utils.create_security_group(self.neutron,
-                                                    self.keystone,
-                                                    sec_grp_settings))
+                neutron_utils.create_security_group(
+                    self.neutron, self.keystone, sec_grp_settings))
 
     def test_create_sec_grp_no_rules(self):
         """
@@ -880,14 +954,14 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
         sec_grp_settings = SecurityGroupConfig(
             name=self.sec_grp_name, description='hello group')
         self.security_groups.append(
-            neutron_utils.create_security_group(self.neutron, self.keystone,
-                                                sec_grp_settings))
+            neutron_utils.create_security_group(
+                self.neutron, self.keystone, sec_grp_settings))
 
         self.assertTrue(sec_grp_settings.name, self.security_groups[0].name)
         self.assertEqual(sec_grp_settings.name, self.security_groups[0].name)
 
         sec_grp_get = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp_get)
         self.assertEqual(self.security_groups[0], sec_grp_get)
 
@@ -903,23 +977,26 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
             rule_settings=[sec_grp_rule_settings])
 
         self.security_groups.append(
-            neutron_utils.create_security_group(self.neutron, self.keystone,
-                                                sec_grp_settings))
+            neutron_utils.create_security_group(
+                self.neutron, self.keystone, sec_grp_settings))
         free_rules = neutron_utils.get_rules_by_security_group(
             self.neutron, self.security_groups[0])
         for free_rule in free_rules:
             self.security_group_rules.append(free_rule)
 
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.security_group_rules.append(
             neutron_utils.create_security_group_rule(
-                self.neutron, sec_grp_settings.rule_settings[0]))
+                self.neutron, keystone, sec_grp_settings.rule_settings[0],
+                self.os_creds.project_name))
 
         # Refresh object so it is populated with the newly added rule
         security_group = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
 
-        rules = neutron_utils.get_rules_by_security_group(self.neutron,
-                                                          security_group)
+        rules = neutron_utils.get_rules_by_security_group(
+            self.neutron, security_group)
 
         self.assertTrue(
             validation_utils.objects_equivalent(
@@ -928,7 +1005,7 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
         self.assertTrue(sec_grp_settings.name, security_group.name)
 
         sec_grp_get = neutron_utils.get_security_group(
-            self.neutron, sec_grp_settings=sec_grp_settings)
+            self.neutron, self.keystone, sec_grp_settings=sec_grp_settings)
         self.assertIsNotNone(sec_grp_get)
         self.assertEqual(security_group, sec_grp_get)
 
@@ -954,6 +1031,33 @@ class NeutronUtilsSecurityGroupTests(OSComponentTestCase):
         self.assertEqual(self.security_groups[0].id, sec_grp_1b.id)
         self.assertEqual(self.security_groups[1].id, sec_grp_2b.id)
 
+    def test_create_list_sec_grp_no_rules(self):
+        """
+        Tests the neutron_utils.create_security_group() and
+        list_security_groups function
+        """
+        sec_grp_settings = SecurityGroupConfig(
+            name=self.sec_grp_name + "-1", description='hello group')
+        self.security_groups.append(neutron_utils.create_security_group(
+            self.neutron, self.keystone, sec_grp_settings))
+
+        sec_grp_settings2 = SecurityGroupConfig(
+            name=self.sec_grp_name + "-2", description='hola group')
+        self.security_groups.append(neutron_utils.create_security_group(
+            self.neutron, self.keystone, sec_grp_settings2))
+
+        returned_sec_groups = neutron_utils.list_security_groups(self.neutron)
+
+        self.assertIsNotNone(returned_sec_groups)
+        worked = 0
+        for sg in returned_sec_groups:
+            if sec_grp_settings.name == sg.name:
+                worked += 1
+            elif sec_grp_settings2.name == sg.name:
+                worked += 1
+
+        self.assertEqual(worked, 2)
+
 
 class NeutronUtilsFloatingIpTests(OSComponentTestCase):
     """
@@ -965,7 +1069,10 @@ class NeutronUtilsFloatingIpTests(OSComponentTestCase):
         Instantiates the CreateImage object that is responsible for downloading
         and creating an OS image file within OpenStack
         """
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
         self.floating_ip = None
 
     def tearDown(self):
@@ -979,6 +1086,8 @@ class NeutronUtilsFloatingIpTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_floating_ips(self):
         """
         Tests the creation of a floating IP
@@ -986,8 +1095,8 @@ class NeutronUtilsFloatingIpTests(OSComponentTestCase):
         """
         initial_fips = neutron_utils.get_floating_ips(self.neutron)
 
-        self.floating_ip = neutron_utils.create_floating_ip(self.neutron,
-                                                            self.ext_net_name)
+        self.floating_ip = neutron_utils.create_floating_ip(
+            self.neutron, self.keystone, self.ext_net_name)
         all_fips = neutron_utils.get_floating_ips(self.neutron)
         self.assertEqual(len(initial_fips) + 1, len(all_fips))
         returned = neutron_utils.get_floating_ip(self.neutron,
@@ -1001,36 +1110,43 @@ Validation routines
 """
 
 
-def validate_network(neutron, name, exists):
+def validate_network(neutron, keystone, name, exists, project_name, mtu=None):
     """
     Returns true if a network for a given name DOES NOT exist if the exists
     parameter is false conversely true. Returns false if a network for a given
     name DOES exist if the exists parameter is true conversely false.
     :param neutron: The neutron client
+    :param keystone: The keystone client
     :param name: The expected network name
     :param exists: Whether or not the network name should exist or not
+    :param project_name: the associated project name
     :return: True/False
     """
-    network = neutron_utils.get_network(neutron, network_name=name)
+    network = neutron_utils.get_network(
+        neutron, keystone, network_name=name, project_name=project_name)
     if exists and network:
         return True
     if not exists and not network:
         return True
+    if mtu:
+        return mtu == network.mtu
     return False
 
 
-def validate_subnet(neutron, name, cidr, exists):
+def validate_subnet(neutron, network, name, cidr, exists):
     """
     Returns true if a subnet for a given name DOES NOT exist if the exists
     parameter is false conversely true. Returns false if a subnet for a given
     name DOES exist if the exists parameter is true conversely false.
     :param neutron: The neutron client
+    :param network: The SNAPS-OO Network domain object
     :param name: The expected subnet name
     :param cidr: The expected CIDR value
     :param exists: Whether or not the network name should exist or not
     :return: True/False
     """
-    subnet = neutron_utils.get_subnet(neutron, subnet_name=name)
+    subnet = neutron_utils.get_subnet(
+        neutron, network, subnet_name=name)
     if exists and subnet and subnet.name == name:
         return subnet.cidr == cidr
     if not exists and not subnet:
@@ -1038,17 +1154,21 @@ def validate_subnet(neutron, name, cidr, exists):
     return False
 
 
-def validate_router(neutron, name, exists):
+def validate_router(neutron, keystone, name, project_name, exists):
     """
     Returns true if a router for a given name DOES NOT exist if the exists
     parameter is false conversely true. Returns false if a router for a given
     name DOES exist if the exists parameter is true conversely false.
     :param neutron: The neutron client
+    :param keystone: The keystone client
     :param name: The expected router name
+    :param project_name: The name of the project in which the router should
+                         exist
     :param exists: Whether or not the network name should exist or not
     :return: True/False
     """
-    router = neutron_utils.get_router(neutron, router_name=name)
+    router = neutron_utils.get_router(
+        neutron, keystone, router_name=name, project_name=project_name)
     if exists and router:
         return True
     return False
index 77dc5dd..7c343f8 100644 (file)
@@ -32,7 +32,8 @@ from snaps.openstack.create_volume import OpenStackVolume
 from snaps.openstack.tests import openstack_tests
 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
 from snaps.openstack.utils import (
-    nova_utils, neutron_utils, glance_utils, cinder_utils)
+    nova_utils, neutron_utils, glance_utils, cinder_utils, keystone_utils)
+from snaps.openstack.utils.nova_utils import NovaException
 
 __author__ = 'spisarski'
 
@@ -48,7 +49,7 @@ class NovaSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that the proper credentials can connect.
         """
-        nova = nova_utils.nova_client(self.os_creds)
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         # This should not throw an exception
         nova.flavors.list()
@@ -57,7 +58,7 @@ class NovaSmokeTests(OSComponentTestCase):
         """
         Tests to ensure that get_hypervisors() function works.
         """
-        nova = nova_utils.nova_client(self.os_creds)
+        nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         hosts = nova_utils.get_hypervisor_hosts(nova)
         # This should not throw an exception
@@ -94,7 +95,7 @@ class NovaUtilsKeypairTests(OSComponentTestCase):
         self.priv_key_file_path = 'tmp/' + guid
         self.pub_key_file_path = self.priv_key_file_path + '.pub'
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.keys = nova_utils.create_keys()
         self.public_key = nova_utils.public_key_openssh(self.keys)
         self.keypair_name = guid
@@ -122,6 +123,8 @@ class NovaUtilsKeypairTests(OSComponentTestCase):
         except:
             pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_keypair(self):
         """
         Tests the creation of an OpenStack keypair that does not exist.
@@ -175,7 +178,7 @@ class NovaUtilsFlavorTests(OSComponentTestCase):
         self.flavor_settings = FlavorConfig(
             name=guid + '-name', flavor_id=guid + '-id', ram=1, disk=1,
             vcpus=1, ephemeral=1, swap=2, rxtx_factor=3.0, is_public=False)
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
         self.flavor = None
 
     def tearDown(self):
@@ -188,6 +191,8 @@ class NovaUtilsFlavorTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_flavor(self):
         """
         Tests the creation of an OpenStack keypair that does not exist.
@@ -241,9 +246,14 @@ class NovaUtilsInstanceTests(OSComponentTestCase):
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.nova = nova_utils.nova_client(self.os_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
-        self.glance = glance_utils.glance_client(self.os_creds)
+        self.nova = nova_utils.nova_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        self.glance = glance_utils.glance_client(
+            self.os_creds, self.os_session)
 
         self.image_creator = None
         self.network_creator = None
@@ -259,15 +269,17 @@ class NovaUtilsInstanceTests(OSComponentTestCase):
             self.image_creator.create()
 
             network_settings = openstack_tests.get_priv_net_config(
-                guid + '-net', guid + '-subnet').network_settings
+                project_name=self.os_creds.project_name,
+                net_name="{}-{}".format(guid, 'net'),
+                subnet_name="{}-{}".format(guid, 'subnet')).network_settings
             self.network_creator = OpenStackNetwork(
                 self.os_creds, network_settings)
             self.network_creator.create()
 
-            self.flavor_creator = OpenStackFlavor(
-                self.os_creds,
-                FlavorConfig(
-                    name=guid + '-flavor-name', ram=256, disk=10, vcpus=1))
+            flavor_config = openstack_tests.get_flavor_config(
+                name="{}-{}".format(guid, 'flavor-name'), ram=256, disk=10,
+                vcpus=1, metadata=self.flavor_metadata)
+            self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_config)
             self.flavor_creator.create()
 
             port_settings = PortConfig(
@@ -314,6 +326,8 @@ class NovaUtilsInstanceTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_create_instance(self):
         """
         Tests the nova_utils.create_server() method
@@ -321,26 +335,30 @@ class NovaUtilsInstanceTests(OSComponentTestCase):
         """
 
         self.vm_inst = nova_utils.create_server(
-            self.nova, self.neutron, self.glance, self.instance_settings,
-            self.image_creator.image_settings)
+            self.nova, self.keystone, self.neutron, self.glance,
+            self.instance_settings, self.image_creator.image_settings,
+            self.os_creds.project_name)
 
         self.assertIsNotNone(self.vm_inst)
 
         # Wait until instance is ACTIVE
         iters = 0
         active = False
+        status = None
         while iters < 60:
-            if create_instance.STATUS_ACTIVE == nova_utils.get_server_status(
-                    self.nova, self.vm_inst):
+            status = nova_utils.get_server_status(self.nova, self.vm_inst)
+            if create_instance.STATUS_ACTIVE == status:
                 active = True
                 break
 
             time.sleep(3)
             iters += 1
 
-        self.assertTrue(active)
+        self.assertTrue(active, msg='VM {} status {} is not {}'.format(
+            self.vm_inst.name, status, create_instance.STATUS_ACTIVE))
         vm_inst = nova_utils.get_latest_server_object(
-            self.nova, self.neutron, self.vm_inst)
+            self.nova, self.neutron, self.keystone, self.vm_inst,
+            self.os_creds.project_name)
 
         self.assertEqual(self.vm_inst.name, vm_inst.name)
         self.assertEqual(self.vm_inst.id, vm_inst.id)
@@ -359,8 +377,9 @@ class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 
-        self.nova = nova_utils.nova_client(self.os_creds)
-        self.cinder = cinder_utils.cinder_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
+        self.cinder = cinder_utils.cinder_client(
+            self.os_creds, self.os_session)
 
         self.image_creator = None
         self.network_creator = None
@@ -376,15 +395,19 @@ class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
             self.image_creator.create()
 
             network_settings = openstack_tests.get_priv_net_config(
-                guid + '-net', guid + '-subnet').network_settings
+                project_name=self.os_creds.project_name,
+                net_name="{}-{}".format(guid, 'net'),
+                subnet_name="{}-{}".format(guid, 'subnet')).network_settings
+
             self.network_creator = OpenStackNetwork(
                 self.os_creds, network_settings)
             self.network_creator.create()
 
+            flavor_settings = openstack_tests.get_flavor_config(
+                name=guid + '-flavor', ram=256, disk=10, vcpus=1,
+                metadata=self.flavor_metadata)
             self.flavor_creator = OpenStackFlavor(
-                self.os_creds,
-                FlavorConfig(
-                    name=guid + '-flavor-name', ram=256, disk=10, vcpus=1))
+                self.os_creds, flavor_settings)
             self.flavor_creator.create()
 
             # Create Volume
@@ -438,9 +461,12 @@ class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_add_remove_volume(self):
         """
-        Tests the nova_utils.create_server() method
+        Tests the nova_utils.attach_volume() and detach_volume functions with
+        a timeout value
         :return:
         """
 
@@ -448,25 +474,36 @@ class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
         self.assertEqual(0, len(self.volume_creator.get_volume().attachments))
 
         # Attach volume to VM
-        neutron = neutron_utils.neutron_client(self.os_creds)
-        nova_utils.attach_volume(
-            self.nova, neutron, self.instance_creator.get_vm_inst(),
-            self.volume_creator.get_volume(), 120)
+        neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        self.assertIsNotNone(nova_utils.attach_volume(
+            self.nova, neutron, keystone, self.instance_creator.get_vm_inst(),
+            self.volume_creator.get_volume(), self.os_creds.project_name))
+
+        vol_attach = None
+        vol_detach = None
+        attached = False
+        start_time = time.time()
+        while time.time() < start_time + 120:
+            vol_attach = cinder_utils.get_volume_by_id(
+                self.cinder, self.volume_creator.get_volume().id)
+
+            if len(vol_attach.attachments) > 0:
+                attached = True
+                break
 
-        vol_attach = cinder_utils.get_volume_by_id(
-            self.cinder, self.volume_creator.get_volume().id)
-        vm_attach = nova_utils.get_server_object_by_id(
-            self.nova, neutron, self.instance_creator.get_vm_inst().id)
+            time.sleep(3)
 
-        # Detach volume to VM
-        nova_utils.detach_volume(
-            self.nova, neutron, self.instance_creator.get_vm_inst(),
-            self.volume_creator.get_volume(), 120)
+        self.assertTrue(attached)
+        self.assertIsNotNone(vol_attach)
 
-        vol_detach = cinder_utils.get_volume_by_id(
-            self.cinder, self.volume_creator.get_volume().id)
-        vm_detach = nova_utils.get_server_object_by_id(
-            self.nova, neutron, self.instance_creator.get_vm_inst().id)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        vm_attach = nova_utils.get_server_object_by_id(
+            self.nova, neutron, keystone,
+            self.instance_creator.get_vm_inst().id, self.os_creds.project_name)
 
         # Validate Attachment
         self.assertIsNotNone(vol_attach)
@@ -475,8 +512,103 @@ class NovaUtilsInstanceVolumeTests(OSComponentTestCase):
         self.assertEqual(vm_attach.volume_ids[0]['id'],
                          vol_attach.attachments[0]['volume_id'])
 
+        # Detach volume to VM
+        self.assertIsNotNone(nova_utils.detach_volume(
+            self.nova, neutron, keystone, self.instance_creator.get_vm_inst(),
+            self.volume_creator.get_volume(), self.os_creds.project_name))
+
+        start_time = time.time()
+        while time.time() < start_time + 120:
+            vol_detach = cinder_utils.get_volume_by_id(
+                self.cinder, self.volume_creator.get_volume().id)
+            if len(vol_detach.attachments) == 0:
+                attached = False
+                break
+
+            time.sleep(3)
+
+        self.assertFalse(attached)
+        self.assertIsNotNone(vol_detach)
+
+        vm_detach = nova_utils.get_server_object_by_id(
+            self.nova, neutron, keystone,
+            self.instance_creator.get_vm_inst().id, self.os_creds.project_name)
+
         # Validate Detachment
         self.assertIsNotNone(vol_detach)
         self.assertEqual(self.volume_creator.get_volume().id, vol_detach.id)
+
         self.assertEqual(0, len(vol_detach.attachments))
         self.assertEqual(0, len(vm_detach.volume_ids))
+
+    def test_attach_volume_nowait(self):
+        """
+        Tests the nova_utils.attach_volume() with a timeout value that is too
+        small to have the volume attachment data to be included on the VmInst
+        object that was supposed to be returned
+        """
+
+        self.assertIsNotNone(self.volume_creator.get_volume())
+        self.assertEqual(0, len(self.volume_creator.get_volume().attachments))
+
+        # Attach volume to VM
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        with self.assertRaises(NovaException):
+            nova_utils.attach_volume(
+                self.nova, neutron, keystone,
+                self.instance_creator.get_vm_inst(),
+                self.volume_creator.get_volume(), self.os_creds.project_name,
+                0)
+
+    def test_detach_volume_nowait(self):
+        """
+        Tests the nova_utils.detach_volume() with a timeout value that is too
+        small to have the volume attachment data to be included on the VmInst
+        object that was supposed to be returned
+        """
+
+        self.assertIsNotNone(self.volume_creator.get_volume())
+        self.assertEqual(0, len(self.volume_creator.get_volume().attachments))
+
+        # Attach volume to VM
+        neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        nova_utils.attach_volume(
+            self.nova, neutron, keystone, self.instance_creator.get_vm_inst(),
+            self.volume_creator.get_volume(), self.os_creds.project_name)
+
+        # Check VmInst for attachment
+        keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        latest_vm = nova_utils.get_server_object_by_id(
+            self.nova, neutron, keystone,
+            self.instance_creator.get_vm_inst().id, self.os_creds.project_name)
+        self.assertEqual(1, len(latest_vm.volume_ids))
+
+        # Check Volume for attachment
+        vol_attach = None
+        attached = False
+        start_time = time.time()
+        while time.time() < start_time + 120:
+            vol_attach = cinder_utils.get_volume_by_id(
+                self.cinder, self.volume_creator.get_volume().id)
+
+            if len(vol_attach.attachments) > 0:
+                attached = True
+                break
+
+            time.sleep(3)
+
+        self.assertTrue(attached)
+        self.assertIsNotNone(vol_attach)
+
+        # Detach volume
+        with self.assertRaises(NovaException):
+            nova_utils.detach_volume(
+                self.nova, neutron, keystone,
+                self.instance_creator.get_vm_inst(),
+                self.volume_creator.get_volume(), self.os_creds.project_name,
+                0)
index cbd78d8..3d080d4 100644 (file)
@@ -37,7 +37,7 @@ from snaps.openstack.create_security_group import OpenStackSecurityGroup
 from snaps.openstack.tests import openstack_tests
 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
 from snaps.openstack.utils import (
-    neutron_utils, settings_utils, nova_utils, glance_utils)
+    neutron_utils, settings_utils, nova_utils, glance_utils, keystone_utils)
 
 __author__ = 'spisarski'
 
@@ -58,7 +58,8 @@ class SettingsUtilsNetworkingTests(OSComponentTestCase):
         self.network_name = guid + '-net'
         self.subnet_name = guid + '-subnet'
         self.net_creator = None
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
     def tearDown(self):
         """
@@ -70,6 +71,8 @@ class SettingsUtilsNetworkingTests(OSComponentTestCase):
             except:
                 pass
 
+        super(self.__class__, self).__clean__()
+
     def test_derive_net_settings_no_subnet(self):
         """
         Validates the utility function settings_utils#create_network_config
@@ -154,9 +157,14 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
         Instantiates the CreateImage object that is responsible for downloading
         and creating an OS image file within OpenStack
         """
-        self.nova = nova_utils.nova_client(self.os_creds)
-        self.glance = glance_utils.glance_client(self.os_creds)
-        self.neutron = neutron_utils.neutron_client(self.os_creds)
+        self.nova = nova_utils.nova_client(
+            self.os_creds, self.os_session)
+        self.keystone = keystone_utils.keystone_client(
+            self.os_creds, self.os_session)
+        self.glance = glance_utils.glance_client(
+            self.os_creds, self.os_session)
+        self.neutron = neutron_utils.neutron_client(
+            self.os_creds, self.os_session)
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.keypair_priv_filepath = 'tmp/' + guid
@@ -188,6 +196,7 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
 
             # First network is public
             self.pub_net_config = openstack_tests.get_pub_net_config(
+                project_name=self.os_creds.project_name,
                 net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
                 router_name=guid + '-pub-router',
                 external_net=self.ext_net_name)
@@ -314,7 +323,7 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
         if os.path.isfile(self.test_file_local_path):
             os.remove(self.test_file_local_path)
 
-        super(self.__class__, self).__clean__()
+        super(self.__class__, self).__clean__()
 
     def test_derive_vm_inst_config(self):
         """
@@ -324,10 +333,11 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
         self.inst_creator.create(block=True)
 
         server = nova_utils.get_server(
-            self.nova, self.neutron,
+            self.nova, self.neutron, self.keystone,
             vm_inst_settings=self.inst_creator.instance_settings)
         derived_vm_settings = settings_utils.create_vm_inst_config(
-            self.nova, self.neutron, server)
+            self.nova, self.keystone, self.neutron, server,
+            self.os_creds.project_name)
         self.assertIsNotNone(derived_vm_settings)
         self.assertIsNotNone(derived_vm_settings.port_settings)
         self.assertIsNotNone(derived_vm_settings.floating_ip_settings)
@@ -340,7 +350,7 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
         self.inst_creator.create(block=True)
 
         server = nova_utils.get_server(
-            self.nova, self.neutron,
+            self.nova, self.neutron, self.keystone,
             vm_inst_settings=self.inst_creator.instance_settings)
         derived_image_settings = settings_utils.determine_image_config(
             self.glance, server, [self.image_creator.image_settings])
@@ -356,8 +366,9 @@ class SettingsUtilsUnitTests(unittest.TestCase):
 
     def test_vol_settings_from_vol(self):
         volume = Volume(
-            name='vol-name', volume_id='vol-id', description='desc', size=99,
-            vol_type='vol-type', availability_zone='zone1', multi_attach=True)
+            name='vol-name', volume_id='vol-id', project_id='proj-id',
+            description='desc', size=99, vol_type='vol-type',
+            availability_zone='zone1', multi_attach=True)
         settings = settings_utils.create_volume_config(volume)
         self.assertEqual(volume.name, settings.name)
         self.assertEqual(volume.description, settings.description)
index 83fe449..757797e 100644 (file)
@@ -21,8 +21,8 @@ import paramiko
 
 try:
     from ansible.parsing.dataloader import DataLoader
-    from ansible.vars import VariableManager
-    from ansible.inventory import Inventory
+    from ansible.vars.manager import VariableManager
+    from ansible.inventory.manager import InventoryManager
     from ansible.executor.playbook_executor import PlaybookExecutor
 except:
     pass
@@ -52,7 +52,8 @@ def apply_playbook(playbook_path, hosts_inv, host_user,
     :return: the results
     """
     if not os.path.isfile(playbook_path):
-        raise AnsibleException('Requested playbook not found - ' + playbook_path)
+        raise AnsibleException(
+            'Requested playbook not found - ' + playbook_path)
 
     pk_file_path = None
     if ssh_priv_key_file_path:
@@ -72,15 +73,14 @@ def apply_playbook(playbook_path, hosts_inv, host_user,
     import ansible.constants
     ansible.constants.HOST_KEY_CHECKING = False
 
-    variable_manager = VariableManager()
+    loader = DataLoader()
+    inventory = InventoryManager(loader=loader)
+    for host in hosts_inv:
+        inventory.add_host(host=host, group='ungrouped')
+    variable_manager = VariableManager(loader=loader, inventory=inventory)
     if variables:
         variable_manager.extra_vars = variables
 
-    loader = DataLoader()
-    inventory = Inventory(loader=loader, variable_manager=variable_manager,
-                          host_list=hosts_inv)
-    variable_manager.set_inventory(inventory)
-
     ssh_extra_args = None
     if proxy_setting and proxy_setting.ssh_proxy_cmd:
         ssh_extra_args = '-o ProxyCommand=\'%s\'' % proxy_setting.ssh_proxy_cmd
@@ -90,14 +90,14 @@ def apply_playbook(playbook_path, hosts_inv, host_user,
                     'connection', 'module_path', 'forks', 'remote_user',
                     'private_key_file', 'ssh_common_args', 'ssh_extra_args',
                     'become', 'become_method', 'become_user', 'verbosity',
-                    'check', 'timeout'])
+                    'check', 'timeout', 'diff'])
 
     ansible_opts = options(
         listtags=False, listtasks=False, listhosts=False, syntax=False,
         connection='ssh', module_path=None, forks=100, remote_user=host_user,
         private_key_file=pk_file_path, ssh_common_args=None,
         ssh_extra_args=ssh_extra_args, become=None, become_method=None,
-        become_user=None, verbosity=11111, check=False, timeout=30)
+        become_user=None, verbosity=11111, check=False, timeout=30, diff=None)
 
     logger.debug('Setting up Ansible Playbook Executor for playbook - ' +
                  playbook_path)
index 851dd64..209b1e0 100644 (file)
@@ -19,7 +19,6 @@ import os
 import pkg_resources
 from scp import SCPClient
 
-from snaps.config.flavor import FlavorConfig
 from snaps.config.keypair import KeypairConfig
 from snaps.config.network import PortConfig
 from snaps.config.security_group import (
@@ -58,7 +57,7 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
         """
         super(self.__class__, self).__start__()
 
-        self.nova = nova_utils.nova_client(self.os_creds)
+        self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
 
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
         self.keypair_priv_filepath = 'tmp/' + guid
@@ -84,13 +83,15 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
             os_image_settings = openstack_tests.ubuntu_image_settings(
                 name=guid + '-' + '-image',
                 image_metadata=self.image_metadata)
-            self.image_creator = create_image.OpenStackImage(self.os_creds,
-                                                             os_image_settings)
+            self.image_creator = create_image.OpenStackImage(
+                self.os_creds, os_image_settings)
             self.image_creator.create()
 
             # First network is public
             self.pub_net_config = openstack_tests.get_pub_net_config(
-                net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
+                project_name=self.os_creds.project_name,
+                net_name=guid + '-pub-net',
+                mtu=1450, subnet_name=guid + '-pub-subnet',
                 router_name=guid + '-pub-router',
                 external_net=self.ext_net_name)
 
@@ -104,11 +105,12 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
             self.router_creator.create()
 
             # Create Flavor
+            flavor_config = openstack_tests.get_flavor_config(
+                name=guid + '-flavor-name', ram=2048, disk=10,
+                vcpus=2, metadata=self.flavor_metadata)
+
             self.flavor_creator = create_flavor.OpenStackFlavor(
-                self.admin_os_creds,
-                FlavorConfig(
-                    name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2,
-                    metadata=self.flavor_metadata))
+                self.admin_os_creds, flavor_config)
             self.flavor_creator.create()
 
             # Create Key/Pair
index d3c1fd6..d46fe86 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 import argparse
-import json
 import logging
 import unittest
+from concurrencytest import ConcurrentTestSuite, fork_for_tests
 
-from snaps import test_suite_builder, file_utils
+from snaps import file_utils
+from snaps import test_suite_builder as tsb
 from snaps.openstack.tests import openstack_tests
 
 __author__ = 'spisarski'
@@ -30,14 +31,13 @@ LOG_LEVELS = {'FATAL': logging.FATAL, 'CRITICAL': logging.CRITICAL,
               'INFO': logging.INFO, 'DEBUG': logging.DEBUG}
 
 
-def __create_test_suite(
+def __create_concurrent_test_suite(
         source_filename, ext_net_name, proxy_settings, ssh_proxy_cmd,
         run_unit_tests, run_connection_tests, run_api_tests,
         run_integration_tests, run_staging_tests, flavor_metadata,
-        image_metadata, use_keystone, use_floating_ips, continuous_integration,
-        log_level):
+        image_metadata, use_floating_ips, continuous_integration, log_level):
     """
-    Compiles the tests that should run
+    Compiles the tests that can be run concurrently
     :param source_filename: the OpenStack credentials file (required)
     :param ext_net_name: the name of the external network to use for floating
                          IPs (required)
@@ -56,9 +56,6 @@ def __create_test_suite(
                             created for test VM instance
     :param image_metadata: dict() object containing the metadata for overriding
                            default images within the tests
-    :param use_keystone: when true, tests creating users and projects will be
-                         exercised and must be run on a host that
-                         has access to the cloud's administrative network
     :param use_floating_ips: when true, tests requiring floating IPs will be
                              executed
     :param continuous_integration: when true, tests for CI will be run
@@ -73,43 +70,100 @@ def __create_test_suite(
 
     # Tests that do not require a remote connection to an OpenStack cloud
     if run_unit_tests:
-        test_suite_builder.add_unit_tests(suite)
+        tsb.add_unit_tests(suite)
 
     # Basic connection tests
     if run_connection_tests:
-        test_suite_builder.add_openstack_client_tests(
+        tsb.add_openstack_client_tests(
             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
-            use_keystone=use_keystone, log_level=log_level)
+            use_keystone=True, log_level=log_level)
 
     # Tests the OpenStack API calls
     if run_api_tests:
-        test_suite_builder.add_openstack_api_tests(
+        tsb.add_openstack_api_tests(
             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
-            use_keystone=use_keystone, image_metadata=image_metadata,
-            log_level=log_level)
+            use_keystone=True, flavor_metadata=flavor_metadata,
+            image_metadata=image_metadata, log_level=log_level)
 
     # Long running integration type tests
     if run_integration_tests:
-        test_suite_builder.add_openstack_integration_tests(
+        tsb.add_openstack_integration_tests(
             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
-            use_keystone=use_keystone, flavor_metadata=flavor_metadata,
+            use_keystone=True, flavor_metadata=flavor_metadata,
             image_metadata=image_metadata, use_floating_ips=use_floating_ips,
             log_level=log_level)
 
     if run_staging_tests:
-        test_suite_builder.add_openstack_staging_tests(
+        tsb.add_openstack_staging_tests(
             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
             log_level=log_level)
 
     if continuous_integration:
-        test_suite_builder.add_openstack_ci_tests(
+        tsb.add_openstack_ci_tests(
             suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
-            use_keystone=use_keystone, flavor_metadata=flavor_metadata,
+            use_keystone=True, flavor_metadata=flavor_metadata,
             image_metadata=image_metadata, use_floating_ips=use_floating_ips,
             log_level=log_level)
     return suite
 
 
+def __create_sequential_test_suite(
+        source_filename, ext_net_name, proxy_settings, ssh_proxy_cmd,
+        run_integration_tests, flavor_metadata, image_metadata,
+        use_floating_ips, log_level):
+    """
+    Compiles the tests that cannot be run in parallel
+    :param source_filename: the OpenStack credentials file (required)
+    :param ext_net_name: the name of the external network to use for floating
+                         IPs (required)
+    :param run_integration_tests: when true, the integration tests are executed
+    :param proxy_settings: <host>:<port> of the proxy server (optional)
+    :param ssh_proxy_cmd: the command used to connect via SSH over some proxy
+                          server (optional)
+    :param flavor_metadata: dict() object containing the metadata for flavors
+                            created for test VM instance
+    :param image_metadata: dict() object containing the metadata for overriding
+                           default images within the tests
+    :param use_floating_ips: when true, tests requiring floating IPs will be
+                             executed
+    :param log_level: the logging level
+    :return:
+    """
+    if use_floating_ips and run_integration_tests:
+        suite = unittest.TestSuite()
+
+        os_creds = openstack_tests.get_credentials(
+            os_env_file=source_filename, proxy_settings_str=proxy_settings,
+            ssh_proxy_cmd=ssh_proxy_cmd)
+
+        tsb.add_ansible_integration_tests(
+                suite=suite, os_creds=os_creds, ext_net_name=ext_net_name,
+                use_keystone=True, flavor_metadata=flavor_metadata,
+                image_metadata=image_metadata, log_level=log_level)
+
+        return suite
+
+
+def __output_results(results):
+    """
+    Sends the test results to the logger
+    :param results:
+    :return:
+    """
+
+    if results.errors:
+        logger.error('Number of errors in test suite - %s',
+                     len(results.errors))
+        for test, message in results.errors:
+            logger.error(str(test) + " ERROR with " + message)
+
+    if results.failures:
+        logger.error('Number of failures in test suite - %s',
+                     len(results.failures))
+        for test, message in results.failures:
+            logger.error(str(test) + " FAILED with " + message)
+
+
 def main(arguments):
     """
     Begins running unit tests.
@@ -123,13 +177,16 @@ def main(arguments):
 
     flavor_metadata = None
     if arguments.flavor_metadata:
-        flavor_metadata = json.loads(arguments.flavor_metadata)
+        flavor_metadata = {
+            'metadata': {'hw:mem_page_size': arguments.flavor_metadata}}
 
     image_metadata = None
     if arguments.image_metadata_file:
         image_metadata = file_utils.read_yaml(arguments.image_metadata_file)
 
-    suite = None
+    concurrent_suite = None
+    sequential_suite = None
+
     if arguments.env and arguments.ext_net:
         unit = arguments.include_unit != ARG_NOT_SET
         connection = arguments.include_connection != ARG_NOT_SET
@@ -144,40 +201,61 @@ def main(arguments):
             api = True
             integration = True
 
-        suite = __create_test_suite(
+        concurrent_suite = __create_concurrent_test_suite(
             arguments.env, arguments.ext_net, arguments.proxy,
             arguments.ssh_proxy_cmd, unit, connection, api,
             integration, staging, flavor_metadata, image_metadata,
-            arguments.use_keystone != ARG_NOT_SET,
             arguments.floating_ips != ARG_NOT_SET,
             ci, log_level)
+
+        if (arguments.include_integration != ARG_NOT_SET
+                and arguments.floating_ips != ARG_NOT_SET):
+            sequential_suite = __create_sequential_test_suite(
+                arguments.env, arguments.ext_net, arguments.proxy,
+                arguments.ssh_proxy_cmd, integration, flavor_metadata,
+                image_metadata,
+                arguments.floating_ips != ARG_NOT_SET, log_level)
     else:
         logger.error('Environment file or external network not defined')
         exit(1)
 
     i = 0
     while i < int(arguments.num_runs):
-        result = unittest.TextTestRunner(verbosity=2).run(suite)
         i += 1
 
-        if result.errors:
-            logger.error('Number of errors in test suite - %s',
-                         len(result.errors))
-            for test, message in result.errors:
-                logger.error(str(test) + " ERROR with " + message)
-
-        if result.failures:
-            logger.error('Number of failures in test suite - %s',
-                         len(result.failures))
-            for test, message in result.failures:
-                logger.error(str(test) + " FAILED with " + message)
-
-        if ((result.errors and len(result.errors) > 0)
-                or (result.failures and len(result.failures) > 0)):
-            logger.error('See above for test failures')
-            exit(1)
-        else:
-            logger.info('All tests completed successfully in run #%s', i)
+        if concurrent_suite:
+            logger.info('Running Concurrent Tests')
+            concurrent_runner = unittest.TextTestRunner(verbosity=2)
+            concurrent_suite = ConcurrentTestSuite(
+                concurrent_suite, fork_for_tests(int(arguments.threads)))
+            concurrent_results = concurrent_runner.run(concurrent_suite)
+            __output_results(concurrent_results)
+
+            if ((concurrent_results.errors
+                    and len(concurrent_results.errors) > 0)
+                    or (concurrent_results.failures
+                        and len(concurrent_results.failures) > 0)):
+                logger.error('See above for test failures')
+                exit(1)
+            else:
+                logger.info(
+                    'Concurrent tests completed successfully in run #%s', i)
+
+        if sequential_suite:
+            logger.info('Running Sequential Tests')
+            sequential_runner = unittest.TextTestRunner(verbosity=2)
+            sequential_results = sequential_runner.run(sequential_suite)
+            __output_results(sequential_results)
+
+            if ((sequential_results.errors
+                    and len(sequential_results.errors) > 0)
+                or (sequential_results.failures
+                    and len(sequential_results.failures) > 0)):
+                logger.error('See above for test failures')
+                exit(1)
+            else:
+                logger.info(
+                    'Sequential tests completed successfully in run #%s', i)
 
     logger.info('Successful completion of %s test runs', i)
     exit(0)
@@ -226,16 +304,10 @@ if __name__ == '__main__':
         '-f', '--floating-ips', dest='floating_ips', default=ARG_NOT_SET,
         nargs='?', help='When argument is set, all integration tests requiring'
                         ' Floating IPs will be executed')
-    parser.add_argument(
-        '-k', '--use-keystone', dest='use_keystone', default=ARG_NOT_SET,
-        nargs='?',
-        help='When argument is set, the tests will exercise the keystone APIs '
-             'and must be run on a machine that has access to the admin '
-             'network and is able to create users and groups')
     parser.add_argument(
         '-fm', '--flavor-meta', dest='flavor_metadata',
-        help='JSON string to be used as flavor metadata for all test instances'
-             ' created')
+        help='hw:mem_page_size flavor setting value (i.e. large). '
+             'Required for DPDK')
     parser.add_argument(
         '-im', '--image-meta', dest='image_metadata_file', default=None,
         help='Location of YAML file containing the image metadata')
@@ -247,6 +319,9 @@ if __name__ == '__main__':
     parser.add_argument(
         '-r', '--num-runs', dest='num_runs', default=1,
         help='Number of test runs to execute (default 1)')
+    parser.add_argument(
+        '-t', '--threads', dest='threads', default=4,
+        help='Number of threads to execute the tests (default 4)')
 
     args = parser.parse_args()
 
index 7b3ece7..52008a6 100644 (file)
@@ -65,18 +65,19 @@ from snaps.openstack.tests.create_image_tests import (
     CreateImageSuccessTests, CreateImageNegativeTests,
     CreateMultiPartImageTests)
 from snaps.openstack.tests.create_instance_tests import (
-    CreateInstanceSingleNetworkTests,  CreateInstanceOnComputeHost,
+    CreateInstanceSingleNetworkTests, CreateInstanceOnComputeHost,
     CreateInstanceSimpleTests, FloatingIpSettingsUnitTests,
     InstanceSecurityGroupTests, VmInstanceSettingsUnitTests,
     CreateInstancePortManipulationTests, SimpleHealthCheck,
     CreateInstanceFromThreePartImage, CreateInstanceMockOfflineTests,
     CreateInstanceTwoNetTests, CreateInstanceVolumeTests,
-    CreateInstanceIPv6NetworkTests)
+    CreateInstanceIPv6NetworkTests, CreateInstanceExternalNetTests)
 from snaps.openstack.tests.create_keypairs_tests import (
     CreateKeypairsTests, KeypairSettingsUnitTests, CreateKeypairsCleanupTests)
 from snaps.openstack.tests.create_network_tests import (
     CreateNetworkSuccessTests, NetworkSettingsUnitTests, PortSettingsUnitTests,
-    SubnetSettingsUnitTests, CreateNetworkTypeTests, CreateNetworkIPv6Tests)
+    SubnetSettingsUnitTests, CreateNetworkTypeTests, CreateNetworkIPv6Tests,
+    CreateMultipleNetworkTests, CreateNetworkGatewayTests)
 from snaps.openstack.tests.create_project_tests import (
     CreateProjectSuccessTests, ProjectSettingsUnitTests,
     CreateProjectUserTests)
@@ -84,21 +85,23 @@ from snaps.openstack.tests.create_qos_tests import (
     QoSSettingsUnitTests, CreateQoSTests)
 from snaps.openstack.tests.create_router_tests import (
     CreateRouterSuccessTests, CreateRouterNegativeTests,
-    RouterSettingsUnitTests)
+    RouterSettingsUnitTests, CreateMultipleRouterTests,
+    CreateRouterSecurityGroupTests, CreateRouterSharedNetworksTests)
 from snaps.openstack.tests.create_security_group_tests import (
     CreateSecurityGroupTests, SecurityGroupRuleSettingsUnitTests,
-    SecurityGroupSettingsUnitTests)
+    SecurityGroupSettingsUnitTests, CreateMultipleSecurityGroupTests)
 from snaps.openstack.tests.create_stack_tests import (
     StackSettingsUnitTests, CreateStackSuccessTests, CreateStackNegativeTests,
     CreateStackFlavorTests, CreateStackFloatingIpTests,
     CreateStackNestedResourceTests, CreateStackKeypairTests,
-    CreateStackVolumeTests, CreateStackSecurityGroupTests)
+    CreateStackVolumeTests, CreateStackSecurityGroupTests,
+    CreateStackUpdateTests)
 from snaps.openstack.tests.create_user_tests import (
     UserSettingsUnitTests, CreateUserSuccessTests)
 from snaps.openstack.tests.create_volume_tests import (
     VolumeSettingsUnitTests, CreateSimpleVolumeSuccessTests,
     CreateVolumeWithTypeTests, CreateVolumeWithImageTests,
-    CreateSimpleVolumeFailureTests)
+    CreateSimpleVolumeFailureTests, CreateVolMultipleCredsTests)
 from snaps.openstack.tests.create_volume_type_tests import (
     VolumeTypeSettingsUnitTests, CreateSimpleVolumeTypeSuccessTests,
     CreateVolumeTypeComplexTests)
@@ -315,7 +318,8 @@ def add_openstack_client_tests(suite, os_creds, ext_net_name,
 
 
 def add_openstack_api_tests(suite, os_creds, ext_net_name, use_keystone=True,
-                            image_metadata=None, log_level=logging.INFO):
+                            flavor_metadata=None, image_metadata=None,
+                            log_level=logging.INFO):
     """
     Adds tests written to exercise all existing OpenStack APIs
     :param suite: the unittest.TestSuite object to which to add the tests
@@ -326,6 +330,9 @@ def add_openstack_api_tests(suite, os_creds, ext_net_name, use_keystone=True,
     :param use_keystone: when True, tests requiring direct access to Keystone
                          are added as these need to be running on a host that
                          has access to the cloud's private network
+    :param flavor_metadata: dict() object containing the metadata required by
+                            your flavor based on your configuration:
+                            (i.e. {'hw:mem_page_size': 'any'})
     :param image_metadata: dict() object containing metadata for creating an
                            image with custom config
                            (see YAML files in examples/image-metadata)
@@ -381,7 +388,7 @@ def add_openstack_api_tests(suite, os_creds, ext_net_name, use_keystone=True,
     suite.addTest(OSComponentTestCase.parameterize(
         NovaUtilsInstanceVolumeTests, os_creds=os_creds,
         ext_net_name=ext_net_name, log_level=log_level,
-        image_metadata=image_metadata))
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata))
     suite.addTest(OSComponentTestCase.parameterize(
         CreateFlavorTests, os_creds=os_creds, ext_net_name=ext_net_name,
         log_level=log_level))
@@ -467,6 +474,11 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
         use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateMultipleSecurityGroupTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
     suite.addTest(OSIntegrationTestCase.parameterize(
         CreateImageSuccessTests, os_creds=os_creds, ext_net_name=ext_net_name,
         use_keystone=use_keystone,
@@ -498,11 +510,21 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateNetworkGatewayTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
     suite.addTest(OSIntegrationTestCase.parameterize(
         CreateNetworkIPv6Tests, os_creds=os_creds,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateMultipleNetworkTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
     suite.addTest(OSIntegrationTestCase.parameterize(
         CreateRouterSuccessTests, os_creds=os_creds, ext_net_name=ext_net_name,
         use_keystone=use_keystone,
@@ -513,6 +535,21 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateMultipleRouterTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateRouterSecurityGroupTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateRouterSharedNetworksTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
     suite.addTest(OSIntegrationTestCase.parameterize(
         CreateQoSTests, os_creds=os_creds,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
@@ -548,6 +585,11 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateVolMultipleCredsTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
 
     # VM Instances
     suite.addTest(OSIntegrationTestCase.parameterize(
@@ -565,6 +607,11 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
         flavor_metadata=flavor_metadata, image_metadata=image_metadata,
         log_level=log_level))
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        CreateInstanceExternalNetTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
     suite.addTest(OSIntegrationTestCase.parameterize(
         CreateInstancePortManipulationTests, os_creds=os_creds,
         ext_net_name=ext_net_name, use_keystone=use_keystone,
@@ -643,12 +690,43 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
             flavor_metadata=flavor_metadata, image_metadata=image_metadata,
             log_level=log_level))
         suite.addTest(OSIntegrationTestCase.parameterize(
-            AnsibleProvisioningTests, os_creds=os_creds,
+            CreateStackUpdateTests, os_creds=os_creds,
             ext_net_name=ext_net_name, use_keystone=use_keystone,
             flavor_metadata=flavor_metadata, image_metadata=image_metadata,
             log_level=log_level))
 
 
+def add_ansible_integration_tests(suite, os_creds, ext_net_name,
+                                  use_keystone=True, flavor_metadata=None,
+                                  image_metadata=None, log_level=logging.INFO):
+    """
+    Adds tests written to exercise all long-running OpenStack integration tests
+    meaning they will be creating VM instances and potentially performing some
+    SSH functions through floatingIPs
+    :param suite: the unittest.TestSuite object to which to add the tests
+    :param os_creds: and instance of OSCreds that holds the credentials
+                     required by OpenStack
+    :param ext_net_name: the name of an external network on the cloud under
+                         test
+    :param use_keystone: when True, tests requiring direct access to Keystone
+                         are added as these need to be running on a host that
+                         has access to the cloud's private network
+    :param image_metadata: dict() object containing metadata for creating an
+                           image with custom config
+                           (see YAML files in examples/image-metadata)
+    :param flavor_metadata: dict() object containing the metadata required by
+                            your flavor based on your configuration:
+                            (i.e. {'hw:mem_page_size': 'large'})
+    :param log_level: the logging level
+    :return: None as the tests will be adding to the 'suite' parameter object
+    """
+    suite.addTest(OSIntegrationTestCase.parameterize(
+        AnsibleProvisioningTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, use_keystone=use_keystone,
+        flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+        log_level=log_level))
+
+
 def add_openstack_ci_tests(
         suite, os_creds, ext_net_name, use_keystone=True, flavor_metadata=None,
         image_metadata=None, use_floating_ips=True, log_level=logging.INFO):
index befe37a..e09a9cc 100644 (file)
@@ -31,7 +31,7 @@ class FileUtilsTests(unittest.TestCase):
 
     def setUp(self):
         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
-        self.tmp_dir = '.tmp/'
+        self.tmp_dir = 'tmp/'
         self.test_dir = self.tmp_dir + str(guid)
         if not os.path.exists(self.test_dir):
             os.makedirs(self.test_dir)
@@ -44,7 +44,7 @@ class FileUtilsTests(unittest.TestCase):
             self.tmp_file_opened.close()
 
         if os.path.exists(self.test_dir) and os.path.isdir(self.test_dir):
-            shutil.rmtree(self.tmp_dir)
+            shutil.rmtree(self.test_dir)
 
     def testFileIsDirectory(self):
         """
diff --git a/snaps/thread_utils.py b/snaps/thread_utils.py
new file mode 100644 (file)
index 0000000..3a3eb4d
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
+#                    and others.  All rights reserved.
+#
+# 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.
+
+from multiprocessing.pool import ThreadPool
+
+_pool = None
+
+
+# Define a thread pool with a limit for how many simultaneous API requests
+# can be in progress at once.
+def worker_pool(size=5):
+    global _pool
+    if _pool is None:
+        _pool = ThreadPool(processes=size)
+    return _pool