add stackforge/openstacklib to 3rdparty
authorMartin Zobel-Helas <zobel@debian.org>
Sun, 21 Jun 2015 19:44:10 +0000 (19:44 +0000)
committerMartin Zobel-Helas <zobel@debian.org>
Sun, 21 Jun 2015 19:44:10 +0000 (19:44 +0000)
Signed-off-by: Martin Zobel-Helas <zobel@debian.org>
30 files changed:
3rdparty/Puppetfile
3rdparty/modules/openstacklib/Gemfile [new file with mode: 0644]
3rdparty/modules/openstacklib/LICENSE [new file with mode: 0644]
3rdparty/modules/openstacklib/README.md [new file with mode: 0644]
3rdparty/modules/openstacklib/Rakefile [new file with mode: 0644]
3rdparty/modules/openstacklib/checksums.json [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/db/mysql.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/policy.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/policy/base.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/service_validation.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/metadata.json [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/classes/init_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/spec_helper.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb [new file with mode: 0644]

index d3c0c2d..67741c4 100644 (file)
@@ -10,3 +10,5 @@ mod 'puppetlabs/inifile', '1.3.0'
 
 mod 'elasticsearch/elasticsearch', '0.9.5'
 mod 'nanliu/staging', '1.0.3'
+
+mod 'stackforge/openstacklib', '5.1.0'
diff --git a/3rdparty/modules/openstacklib/Gemfile b/3rdparty/modules/openstacklib/Gemfile
new file mode 100644 (file)
index 0000000..fedea52
--- /dev/null
@@ -0,0 +1,22 @@
+source 'https://rubygems.org'
+
+group :development, :test do
+  gem 'puppetlabs_spec_helper', :require => false
+  gem 'metadata-json-lint'
+  gem 'puppet-lint', '~> 0.3.2'
+  gem 'rspec-puppet', '~> 1.0.1'
+  gem 'rake', '10.1.1'
+  gem 'rspec'
+  gem 'mocha'
+  gem 'json'
+  gem 'faraday', '0.8.8',       :require => false
+  gem 'vcr',                    :require => false
+end
+
+if puppetversion = ENV['PUPPET_GEM_VERSION']
+  gem 'puppet', puppetversion, :require => false
+else
+  gem 'puppet', :require => false
+end
+
+# vim:ft=ruby
diff --git a/3rdparty/modules/openstacklib/LICENSE b/3rdparty/modules/openstacklib/LICENSE
new file mode 100644 (file)
index 0000000..7aaad11
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!) The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2014 Puppet Labs Inc
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/3rdparty/modules/openstacklib/README.md b/3rdparty/modules/openstacklib/README.md
new file mode 100644 (file)
index 0000000..4e9b7ae
--- /dev/null
@@ -0,0 +1,271 @@
+openstacklib
+============
+
+5.1.0 - 2014.2 - Juno
+#### Table of Contents
+
+1. [Overview - What is the openstacklib module?](#overview)
+2. [Module Description - What does the module do?](#module-description)
+3. [Setup - The basics of getting started with openstacklib](#setup)
+4. [Implementation - An under-the-hood peek at what the module is doing](#implementation)
+5. [Limitations - OS compatibility, etc.](#limitations)
+6. [Development - Guide for contributing to the module](#development)
+7. [Contributors - Those with commits](#contributors)
+8. [Release Notes - Notes on the most recent updates to the module](#release-notes)
+
+Overview
+--------
+
+The openstacklib module is a part of [Stackforge](https://github.com/stackforge),
+an effort by the Openstack infrastructure team to provide continuous integration
+testing and code review for Openstack and Openstack community projects not part
+of the core software.  The module itself is used to expose common functionality
+between Openstack modules as a library that can be utilized to avoid code
+duplication.
+
+Module Description
+------------------
+
+The openstacklib module is a library module for other Openstack modules to
+utilize. A thorough description will be added later.
+
+This module is tested in combination with other modules needed to build and
+leverage an entire Openstack software stack.  These modules can be found, all
+pulled together in the [openstack module](https://github.com/stackforge/puppet-openstack).
+
+Setup
+-----
+
+### Installing openstacklib
+
+    example% puppet module install puppetlabs/openstacklib
+
+Usage
+-----
+
+### Classes and Defined Types
+
+#### Defined type: openstacklib::db::mysql
+
+The db::mysql resource is a library resource that can be used by nova, cinder,
+ceilometer, etc., to create a mysql database with configurable privileges for
+a user connecting from defined hosts.
+
+Typically this resource will be declared with a notify parameter to configure
+the sync command to execute when the database resource is changed.
+
+For example, in heat::db::mysql you might declare:
+
+```
+::openstacklib::db::mysql { 'heat':
+    password_hash => mysql_password($password),
+    dbname        => $dbname,
+    user          => $user,
+    host          => $host,
+    charset       => $charset,
+    collate       => $collate,
+    allowed_hosts => $allowed_hosts,
+    notify        => Exec['heat-dbsync'],
+  }
+```
+
+Some modules should ensure that the database is created before the service is
+set up. For example, in keystone::db::mysql you would have:
+
+```
+::openstacklib::db::mysql { 'keystone':
+    password_hash => mysql_password($password),
+    dbname        => $dbname,
+    user          => $user,
+    host          => $host,
+    charset       => $charset,
+    collate       => $collate,
+    allowed_hosts => $allowed_hosts,
+    notify        => Exec['keystone-manage db_sync'],
+    before        => Service['keystone'],
+  }
+```
+
+** Parameters for openstacklib::db::mysql: **
+
+#####`password_hash`
+Password hash to use for the database user for this service;
+string; required
+
+#####`dbname`
+The name of the database
+string; optional; default to the $title of the resource, i.e. 'nova'
+
+#####`user`
+The database user to create;
+string; optional; default to the $title of the resource, i.e. 'nova'
+
+#####`host`
+The IP address or hostname of the user in mysql_grant;
+string; optional; default to '127.0.0.1'
+
+#####`charset`
+The charset to use for the database;
+string; optional; default to 'utf8'
+
+#####`collate`
+The collate to use for the database;
+string; optional; default to 'utf8_general_ci'
+
+#####`allowed_hosts`
+Additional hosts that are allowed to access this database;
+array or string; optional; default to undef
+
+#####`privileges`
+Privileges given to the database user;
+string or array of strings; optional; default to 'ALL'
+
+
+#### Defined type: openstacklib::service_validation
+
+The service_validation resource is a library resource that can be used by nova, cinder,
+ceilometer, etc., to validate that a resource is actually up and running.
+
+For example, in nova::api you might declare:
+
+```
+::openstacklib::service_validation { 'nova-api':
+    command => 'nova list',
+  }
+```
+This defined resource creates an exec-anchor pair where the anchor depends upon
+the successful exec run.
+
+** Parameters for openstacklib::service_validation: **
+
+#####`command`
+Command to run for validating the service;
+string; required
+
+#####`service_name`
+The name of the service to validate;
+string; optional; default to the $title of the resource, i.e. 'nova-api'
+
+#####`path`
+The path of the command to validate the service;
+string; optional; default to '/usr/bin:/bin:/usr/sbin:/sbin'
+
+#####`provider`
+The provider to use for the exec command;
+string; optional; default to 'shell'
+
+#####`tries`
+Number of times to retry validation;
+string; optional; default to '10'
+
+#####`try_sleep`
+Number of seconds between validation attempts;
+string; optional; default to '2'
+
+### Types and Providers
+
+#### Aviator
+
+#####`Puppet::add_aviator_params`
+
+The aviator type is not a real type, but it serves to simulate a mixin model,
+whereby other types can call out to the Puppet::add\_aviator\_params method in
+order to add aviator-specific parameters to themselves. Currently this adds the
+auth parameter to the given type. The method must be called after the type is
+declared, e.g.:
+
+```puppet
+require 'puppet/type/aviator'
+Puppet::Type.newtype(:my_type) do
+# ...
+end
+Puppet::add_aviator_params(:my_type)
+```
+
+#####`Puppet::Provider::Aviator`
+
+The aviator provider is a parent provider intended to serve as a base for other
+providers that need to authenticate against keystone in order to accomplish a
+task.
+
+**`Puppet::Provider::Aviator#authenticate`**
+
+Either creates an authenticated session or sets up an unauthenticated session
+with instance variables initialized with a token to inject into the next request.
+It takes as arguments a set of authentication parameters as a hash and a path
+to a log file. Puppet::Provider::Aviator#authencate looks for five different
+possible methods of authenticating, in the following order:
+
+1) Username and password credentials in the auth parameters
+2) The path to an openrc file containing credentials to read in the auth
+   parameters
+3) A service token in the auth parameters
+4) Environment variables set for the environment in which Puppet is running
+5) A service token in /etc/keystone/keystone.conf. This option provides
+   backwards compatibility with earlier keystone providers.
+
+If the provider has password credentials, it can create an authenticated
+session. If it only has a service token, it initializes an unauthenciated
+session and a hash of session data that can be injected into a future request.
+
+**`Puppet::Provider::Aviator#make_request`**
+
+After creating a session, the make\_request method provides an interface that
+providers can use to make requests without worrying about whether they have an
+authenticated or unauthenticated session. It takes as arguments the
+Aviator::Service it is making a request at (for example, keystone), a symbol for
+the request (for example, :list\_tenants), and optionally a block to execute
+that will set parameters for an update request.
+
+Implementation
+--------------
+
+### openstacklib
+
+openstacklib is a combination of Puppet manifest and ruby code to delivery
+configuration and extra functionality through types and providers.
+
+Limitations
+-----------
+
+* Limitations will be added as they are discovered.
+
+Development
+-----------
+
+Developer documentation for the entire puppet-openstack project.
+
+* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation
+
+Contributors
+------------
+
+* https://github.com/stackforge/puppet-openstacklib/graphs/contributors
+
+Versioning
+----------
+
+This module has been given version 5 to track the puppet-openstack modules. The
+versioning for the puppet-openstack modules are as follows:
+
+```
+Puppet Module :: OpenStack Version :: OpenStack Codename
+2.0.0         -> 2013.1.0          -> Grizzly
+3.0.0         -> 2013.2.0          -> Havana
+4.0.0         -> 2014.1.0          -> Icehouse
+5.0.0         -> 2014.2.0          -> Juno
+```
+
+Release Notes
+-------------
+
+**5.1.0**
+
+* Update .gitreview file for project rename
+* Adding augeas insertion check
+* MySQL: change default MySQL collate to utf8_general_ci
+* spec: pin rspec-puppet to 1.0.1
+
+**5.0.0**
+
+* This is the initial release of this module.
diff --git a/3rdparty/modules/openstacklib/Rakefile b/3rdparty/modules/openstacklib/Rakefile
new file mode 100644 (file)
index 0000000..67e846c
--- /dev/null
@@ -0,0 +1,7 @@
+require 'rubygems'
+require 'puppetlabs_spec_helper/rake_tasks'
+require 'puppet-lint/tasks/puppet-lint'
+
+PuppetLint.configuration.fail_on_warnings = true
+PuppetLint.configuration.send('disable_80chars')
+PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
diff --git a/3rdparty/modules/openstacklib/checksums.json b/3rdparty/modules/openstacklib/checksums.json
new file mode 100644 (file)
index 0000000..c808945
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "Gemfile": "2c4e4ae399db74816aafb47dbc3951a5",
+  "LICENSE": "53173ea25085d832ebb1e9d131dc645d",
+  "README.md": "023e14103588e6eb16aee599338f0798",
+  "Rakefile": "a61c67fc9275174b6d502c7a97d58fba",
+  "lib/puppet/parser/functions/os_database_connection.rb": "f50c5c418a4745f67b863351aa421371",
+  "lib/puppet/provider/aviator.rb": "dfec34e1929a1bb260d26b5382d596a2",
+  "lib/puppet/util/aviator.rb": "6a2f5145b59f2011f04b9598db4d66d6",
+  "manifests/db/mysql/host_access.pp": "0d4b41a44213cd2cae0febe63032b74e",
+  "manifests/db/mysql.pp": "4b2ac1ae2ef9c32c2bdcf5330faa2c85",
+  "manifests/messaging/rabbitmq.pp": "4f2a699c774c57aa645ef7300c87eb9c",
+  "manifests/policy/base.pp": "9fcbf53d8442a2e258cbe1260ac6dc6b",
+  "manifests/policy.pp": "843e98d897e3df8d8d70f8017f7b6e6e",
+  "manifests/service_validation.pp": "7b0ed110553298231d947a131e2570f5",
+  "metadata.json": "a1e6434b728214cb8a0f235468260e86",
+  "spec/classes/init_spec.rb": "62493b66358f3c7acf24b0cfe8a98391",
+  "spec/classes/openstacklib_policy_spec.rb": "806f398cc4a8a9cf11c005608879374c",
+  "spec/defines/openstacklib_db_mysql_host_access_spec.rb": "4e498ba905f57bebc98480207f73e253",
+  "spec/defines/openstacklib_db_mysql_spec.rb": "edac2c0018bb0baaf4b55920b39564e6",
+  "spec/defines/openstacklib_messaging_rabbitmq_spec.rb": "7551d7034f07951fff7cd28ca05adf42",
+  "spec/defines/openstacklib_policy_spec.rb": "6fc8d604b44f2c559bcd2222210031b3",
+  "spec/defines/openstacklib_service_validation_spec.rb": "cbb6e09a2c2bca9b04d699e3509b4827",
+  "spec/fixtures/vcr/aviator/request/with_session.yml": "36b855c8d25e2652a711b4d76ab16b20",
+  "spec/fixtures/vcr/aviator/request/without_session.yml": "ab811807ab346574e7cab61bf111be20",
+  "spec/fixtures/vcr/aviator/session/with_password.yml": "4ceea78a734539233b9de4fe60cb856c",
+  "spec/fixtures/vcr/aviator/session/with_token.yml": "ab811807ab346574e7cab61bf111be20",
+  "spec/functions/os_database_connection_spec.rb": "0cfa88f055785516f56672b1f773a461",
+  "spec/spec_helper.rb": "93f9c20dc020eba3bc244c347b8e5d34",
+  "spec/unit/provider/aviator_spec.rb": "2d736d88dbcd3bb2b4960067df71d51f"
+}
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb b/3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb
new file mode 100644 (file)
index 0000000..8764f1b
--- /dev/null
@@ -0,0 +1,72 @@
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:os_database_connection,
+                                      :type => :rvalue,
+                                      :doc => <<-EOS
+This function builds a os_database_connection string from various parameters.
+EOS
+) do |arguments|
+
+  require 'uri'
+
+  if (arguments.size != 1) then
+    raise(Puppet::ParseError, "os_database_connection(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)")
+  end
+
+  v = arguments[0]
+  klass = v.class
+
+  unless klass == Hash
+    raise(Puppet::ParseError, "os_database_connection(): Requires an hash, got #{klass}")
+  end
+
+  v.keys.each do |key|
+    unless (v[key].class == String) or (v[key] == :undef)
+      raise(Puppet::ParseError, "os_database_connection(): #{key} should be a String")
+    end
+  end
+
+  parts = {}
+
+  unless v.include?('dialect')
+    raise(Puppet::ParseError, 'os_database_connection(): dialect is required')
+  end
+
+  if v.include?('host')
+    parts[:host] = v['host']
+  end
+
+  unless v.include?('database')
+    raise(Puppet::ParseError, 'os_database_connection(): database is required')
+  end
+
+  if v.include?('port')
+    if v.include?('host')
+      parts[:port] = v['port'].to_i
+    else
+      raise(Puppet::ParseError, 'os_database_connection(): host is required with port')
+    end
+  end
+
+  if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '')
+    parts[:userinfo] = URI.escape(v['username'])
+    if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '')
+      parts[:userinfo] += ":#{URI.escape(v['password'])}"
+    end
+  end
+
+  if v.include?('charset')
+    parts[:query] = "charset=#{v['charset']}"
+  end
+
+  parts[:scheme] = v['dialect']
+
+  if v.include?('host')
+    parts[:path] = "/#{v['database']}"
+  else
+    parts[:path] = "///#{v['database']}"
+  end
+
+  URI::Generic.build(parts).to_s
+end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb
new file mode 100644 (file)
index 0000000..8de1bf2
--- /dev/null
@@ -0,0 +1,297 @@
+require 'puppet'
+require 'puppet/feature/aviator'
+require 'puppet/util/inifile'
+
+class Puppet::Provider::Aviator < Puppet::Provider
+
+  def session
+    @session ||= authenticate(resource[:auth], resource[:log_file])
+  end
+
+  def self.session
+    @session ||= authenticate(nil, nil)
+  end
+
+  def request(service, request, &block)
+    self.class.make_request(service, request, session_data, &block)
+  end
+
+  def self.request(service, request, &block)
+    self.make_request(service, request, session_data, &block)
+  end
+
+  # needed for tests
+  def session_data
+    @session_data
+  end
+
+  def self.session_data
+    @session_data
+  end
+
+  def session_data=(data)
+    @session_data=data
+  end
+
+  def self.session_data=(data)
+    @session_data=data
+  end
+
+  private
+
+  # Attempt to find credentials in this order:
+  # 1. username,password,tenant,host set in type parameters
+  # 2. openrc file path set in type parameters
+  # 3. service token and host set in type parameters
+  # 4. username,password,tenant,host set in environment variables
+  # 5. service token and host set in keystone.conf (backwards compatible version)
+  def authenticate(auth_params, log_file)
+    auth_params ||= {}
+    if password_credentials_set?(auth_params)
+      @session = get_authenticated_session(auth_params, log_file)
+
+    elsif openrc_set?(auth_params)
+      credentials = get_credentials_from_openrc(auth_params['openrc'])
+      @session = get_authenticated_session(credentials, log_file)
+
+    elsif service_credentials_set?(auth_params)
+      session_hash = get_unauthenticated_session(auth_params, log_file)
+      @session_data = session_hash[:data]
+      @session = session_hash[:session]
+
+    elsif env_vars_set?
+      credentials = get_credentials_from_env
+      @session = get_authenticated_session(credentials, log_file)
+
+    else  # Last effort: try to get the token from keystone.conf
+      session_hash = self.class.try_auth_with_token(keystone_file, log_file)
+      @session_data = session_hash[:data]
+      @session = session_hash[:session]
+    end
+  end
+
+  def self.authenticate(auth_params, log_file)
+    auth_params = {} unless auth_params
+    if env_vars_set?
+      credentials = get_credentials_from_env
+      @session = get_authenticated_session(credentials, log_file)
+
+    else  # Last effort: try to get the token from keystone.conf
+      session_hash = try_auth_with_token(keystone_file, log_file)
+      @session_data = session_hash[:data]
+      @session = session_hash[:session]
+    end
+  end
+
+
+  def self.try_auth_with_token(conf_file, log_file)
+    service_token = get_admin_token_from_keystone_file(conf_file)
+    auth_url = get_auth_url_from_keystone_file(conf_file)
+    session_hash = {}
+    if service_token
+      credentials = {
+        'service_token' => service_token,
+        'host_uri'      => auth_url,
+      }
+      session_hash = get_unauthenticated_session(credentials, log_file)
+    else  # All authentication efforts failed
+      raise(Puppet::Error, 'No credentials provided.')
+    end
+  end
+
+
+  def self.make_request(service, request, session_data, &block)
+    response = nil
+    if service && service.default_session_data
+      response = service.request(request, :endpoint_type => 'admin') do |params|
+        yield(params) if block
+      end
+    elsif session_data
+      response = service.request(request, :endpoint_type => 'admin',
+                                 :session_data => session_data) do |params|
+        yield(params) if block
+      end
+    else
+      raise(Puppet::Error, 'Cannot make a request with no session data.')
+    end
+    if response.body.hash['error']
+      raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}")
+    end
+    response
+  end
+
+
+  def password_credentials_set?(auth_params)
+    auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri']
+  end
+
+
+  def openrc_set?(auth_params)
+    auth_params['openrc']
+  end
+
+
+  def service_credentials_set?(auth_params)
+    auth_params['service_token'] && auth_params['host_uri']
+  end
+
+
+  def self.env_vars_set?
+    ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
+  end
+
+
+  def env_vars_set?
+    self.class.env_vars_set?
+  end
+
+
+  def get_credentials_from_openrc(file)
+    creds = {}
+    begin
+      File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
+        key, value = line.split('=')
+        key = key.split(' ').last
+        value = value.chomp.gsub(/'/, '')
+        creds[key] = value
+      end
+      return creds
+    rescue Exception => error
+      return {}
+    end
+  end
+
+
+  def self.get_credentials_from_env
+    ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7
+  end
+
+  def get_credentials_from_env
+    self.class.get_credentials_from_env
+  end
+
+
+  def self.keystone_file
+    keystone_file = Puppet::Util::IniConfig::File.new
+    keystone_file.read('/etc/keystone/keystone.conf')
+    keystone_file
+  end
+
+  def keystone_file
+    return @keystone_file if @keystone_file
+    @keystone_file = Puppet::Util::IniConfig::File.new
+    @keystone_file.read('/etc/keystone/keystone.conf')
+    @keystone_file
+  end
+
+
+  def self.get_admin_token_from_keystone_file(conf_file)
+    if conf_file and conf_file['DEFAULT'] and conf_file['DEFAULT']['admin_token']
+      return "#{conf_file['DEFAULT']['admin_token'].strip}"
+    else
+      return nil
+    end
+  end
+
+  def get_admin_token_from_keystone_file
+    conf_file = keystone_file
+    self.class.get_admin_token_from_keystone_file(conf_file)
+  end
+
+
+  def self.get_auth_url_from_keystone_file(conf_file)
+    if conf_file
+      if conf_file['DEFAULT']
+        if conf_file['DEFAULT']['admin_endpoint']
+          auth_url = conf_file['DEFAULT']['admin_endpoint'].strip
+          return versioned_endpoint(auth_url)
+        end
+
+        if conf_file['DEFAULT']['admin_port']
+          admin_port = conf_file['DEFAULT']['admin_port'].strip
+        else
+          admin_port = '35357'
+        end
+
+        if conf_file['DEFAULT']['admin_bind_host']
+          host = conf_file['DEFAULT']['admin_bind_host'].strip
+          if host == "0.0.0.0"
+            host = "127.0.0.1"
+          end
+        else
+          host = "127.0.0.1"
+        end
+      end
+
+      if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true'
+        protocol = 'https'
+      else
+        protocol = 'http'
+      end
+    end
+
+    "#{protocol}://#{host}:#{admin_port}/v2.0/"
+  end
+
+  def get_auth_url_from_keystone_file
+    self.class.get_auth_url_from_keystone_file(keystone_file)
+  end
+
+
+  def self.make_configuration(credentials)
+    host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version'])
+    {
+      :provider => 'openstack',
+      :auth_service => {
+        :name        => 'identity',
+        :host_uri    => host_uri,
+        :request     => 'create_token',
+        :validator   => 'list_tenants',
+      },
+      :auth_credentials => {
+        :username    => credentials['username'] || credentials['OS_USERNAME'],
+        :password    => credentials['password'] || credentials['OS_PASSWORD'],
+        :tenant_name => credentials['tenant_name'] || credentials['OS_TENANT_NAME']
+      }
+    }
+  end
+
+
+  def self.get_authenticated_session(credentials, log_file)
+    configuration = make_configuration(credentials)
+    session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
+    session.authenticate
+    session
+  end
+
+  def get_authenticated_session(credentials, log_file)
+    self.class.get_authenticated_session(credentials, log_file)
+  end
+
+
+  def self.get_unauthenticated_session(credentials, log_file)
+    configuration = {
+      :provider => 'openstack',
+    }
+    session_data = {
+      :base_url      => credentials['host_uri'],
+      :service_token => credentials['service_token']
+    }
+    session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
+    { :session => session, :data => session_data }
+  end
+
+  def get_unauthenticated_session(credentials, log_file)
+    self.class.get_unauthenticated_session(credentials, log_file)
+  end
+
+
+  def self.versioned_endpoint(endpoint, version = 'v2.0')
+    version = 'v2.0' if version.nil?
+    if endpoint =~ /\/#{version}\/?$/ || endpoint =~ /\/v2.0\/?$/ || endpoint =~ /\/v3\/?$/
+      endpoint
+    else
+      "#{endpoint.chomp('/')}/#{version}"
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb
new file mode 100644 (file)
index 0000000..bc24b02
--- /dev/null
@@ -0,0 +1,46 @@
+# Add the auth parameter to whatever type is given
+module Puppet::Util::Aviator
+  def self.add_aviator_params(type)
+
+    type.newparam(:auth) do
+
+      desc <<EOT
+Hash of authentication credentials. Credentials can be specified as
+password credentials, e.g.:
+
+auth => {
+  'username'    => 'test',
+  'password'    => 'passw0rd',
+  'tenant_name' => 'test',
+  'host_uri'    => 'http://localhost:35357/v2.0',
+}
+
+or a path to an openrc file containing these credentials, e.g.:
+
+auth => {
+  'openrc' => '/root/openrc',
+}
+
+or a service token and host, e.g.:
+
+auth => {
+  'service_token' => 'ADMIN',
+  'host_uri'    => 'http://localhost:35357/v2.0',
+}
+
+If not present, the provider will first look for environment variables
+for password credentials and then to /etc/keystone/keystone.conf for a
+service token.
+EOT
+
+      validate do |value|
+        raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash)
+      end
+    end
+
+    type.newparam(:log_file) do
+      desc 'Log file. Defaults to no logging.'
+      defaultto('/dev/null')
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/manifests/db/mysql.pp b/3rdparty/modules/openstacklib/manifests/db/mysql.pp
new file mode 100644 (file)
index 0000000..7cf1010
--- /dev/null
@@ -0,0 +1,68 @@
+# == Definition: openstacklib::db::mysql
+#
+# This resource configures a mysql database for an OpenStack service
+#
+# == Parameters:
+#
+#  [*password_hash*]
+#    Password hash to use for the database user for this service;
+#    string; required
+#
+#  [*dbname*]
+#    The name of the database
+#    string; optional; default to the $title of the resource, i.e. 'nova'
+#
+#  [*user*]
+#    The database user to create;
+#    string; optional; default to the $title of the resource, i.e. 'nova'
+#
+#  [*host*]
+#    The IP address or hostname of the user in mysql_grant;
+#    string; optional; default to '127.0.0.1'
+#
+#  [*charset*]
+#    The charset to use for the database;
+#    string; optional; default to 'utf8'
+#
+#  [*collate*]
+#    The collate to use for the database;
+#    string; optional; default to 'utf8_general_ci'
+#
+#  [*allowed_hosts*]
+#    Additional hosts that are allowed to access this database;
+#    array or string; optional; default to undef
+#
+#  [*privileges*]
+#    Privileges given to the database user;
+#    string or array of strings; optional; default to 'ALL'
+
+define openstacklib::db::mysql (
+  $password_hash,
+  $dbname         = $title,
+  $user           = $title,
+  $host           = '127.0.0.1',
+  $charset        = 'utf8',
+  $collate        = 'utf8_general_ci',
+  $allowed_hosts  = [],
+  $privileges     = 'ALL',
+) {
+
+  include ::mysql::client
+
+  mysql_database { $dbname:
+    ensure  => present,
+    charset => $charset,
+    collate => $collate,
+    require => [ Class['mysql::server'], Class['mysql::client'] ],
+  }
+
+  $allowed_hosts_list = unique(concat(any2array($allowed_hosts), [$host]))
+  $real_allowed_hosts = prefix($allowed_hosts_list, "${dbname}_")
+
+  openstacklib::db::mysql::host_access { $real_allowed_hosts:
+    user          => $user,
+    password_hash => $password_hash,
+    database      => $dbname,
+    privileges    => $privileges,
+  }
+}
diff --git a/3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp b/3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp
new file mode 100644 (file)
index 0000000..4909f63
--- /dev/null
@@ -0,0 +1,41 @@
+# Allow a user to access the database for the service
+#
+# == Namevar
+#  String with the form dbname_host. The host part of the string is the host
+#  to allow
+#
+# == Parameters
+#  [*user*]
+#    username to allow
+#
+#  [*password_hash*]
+#    user password hash
+#
+#  [*database*]
+#    the database name
+#
+#  [*privileges*]
+#    the privileges to grant to this user
+#
+define openstacklib::db::mysql::host_access (
+  $user,
+  $password_hash,
+  $database,
+  $privileges,
+) {
+  validate_re($title, '_', 'Title must be $dbname_$host')
+
+  $host = inline_template('<%= @title.split("_").last %>')
+
+  mysql_user { "${user}@${host}":
+    password_hash => $password_hash,
+    require       => Mysql_database[$database],
+  }
+
+  mysql_grant { "${user}@${host}/${database}.*":
+    privileges => $privileges,
+    table      => "${database}.*",
+    require    => Mysql_user["${user}@${host}"],
+    user       => "${user}@${host}",
+  }
+}
diff --git a/3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp b/3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp
new file mode 100644 (file)
index 0000000..16f6c62
--- /dev/null
@@ -0,0 +1,105 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# 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.
+#
+# == Definition: openstacklib::messaging::rabbitmq
+#
+# This resource creates RabbitMQ resources for an OpenStack service.
+#
+# == Parameters:
+#
+# [*userid*]
+#   (optional) The username to use when connecting to Rabbit
+#   Defaults to 'guest'
+#
+# [*password*]
+#   (optional) The password to use when connecting to Rabbit
+#   Defaults to 'guest'
+#
+# [*virtual_host*]
+#   (optional) The virtual host to use when connecting to Rabbit
+#   Defaults to '/'
+#
+# [*is_admin*]
+#   (optional) If the user should be admin or not
+#   Defaults to false
+#
+# [*configure_permission*]
+#   (optional) Define configure permission
+#   Defaults to '.*'
+#
+# [*write_permission*]
+#   (optional) Define write permission
+#   Defaults to '.*'
+#
+# [*read_permission*]
+#   (optional) Define read permission
+#   Defaults to '.*'
+#
+# [*manage_user*]
+#   (optional) Manage or not the user
+#   Defaults to true
+#
+# [*manage_user_permissions*]
+#   (optional) Manage or not user permissions
+#   Defaults to true
+#
+# [*manage_vhost*]
+#   (optional) Manage or not the vhost
+#   Defaults to true
+#
+define openstacklib::messaging::rabbitmq(
+  $userid                  = 'guest',
+  $password                = 'guest',
+  $virtual_host            = '/',
+  $is_admin                = false,
+  $configure_permission    = '.*',
+  $write_permission        = '.*',
+  $read_permission         = '.*',
+  $manage_user             = true,
+  $manage_user_permissions = true,
+  $manage_vhost            = true,
+) {
+
+  if $manage_user {
+    if $userid == 'guest' {
+      $is_admin_real = false
+    } else {
+      $is_admin_real = $is_admin
+    }
+    ensure_resource('rabbitmq_user', $userid, {
+      'admin'    => $is_admin_real,
+      'password' => $password,
+      'provider' => 'rabbitmqctl',
+    })
+  }
+
+  if $manage_user_permissions {
+    ensure_resource('rabbitmq_user_permissions', "${userid}@${virtual_host}", {
+      'configure_permission' => $configure_permission,
+      'write_permission'     => $write_permission,
+      'read_permission'      => $read_permission,
+      'provider'             => 'rabbitmqctl',
+    })
+  }
+
+  if $manage_vhost {
+    ensure_resource('rabbitmq_vhost', $virtual_host, {
+      'provider' => 'rabbitmqctl',
+    })
+  }
+
+}
diff --git a/3rdparty/modules/openstacklib/manifests/policy.pp b/3rdparty/modules/openstacklib/manifests/policy.pp
new file mode 100644 (file)
index 0000000..b111427
--- /dev/null
@@ -0,0 +1,19 @@
+# == Class: openstacklib::policies
+#
+# This resource is an helper to call the policy definition
+#
+# == Parameters:
+#
+#  [*policies*]
+#    Hash of policies one would like to set to specific values
+#    hash; optional
+#
+class openstacklib::policy (
+  $policies = {},
+) {
+
+  validate_hash($policies)
+
+  create_resources('openstacklib::policy::base', $policies)
+
+}
diff --git a/3rdparty/modules/openstacklib/manifests/policy/base.pp b/3rdparty/modules/openstacklib/manifests/policy/base.pp
new file mode 100644 (file)
index 0000000..01919fe
--- /dev/null
@@ -0,0 +1,45 @@
+# == Definition: openstacklib::policy::base
+#
+# This resource configures the policy.json file for an OpenStack service
+#
+# == Parameters:
+#
+#  [*file_path*]
+#    Path to the policy.json file
+#    string; required
+#
+#  [*key*]
+#    The key to replace the value for
+#    string; required; the key to replace the value for
+#
+#  [*value*]
+#    The value to set
+#    string; optional; the value to set
+#
+define openstacklib::policy::base (
+  $file_path,
+  $key,
+  $value = '',
+) {
+
+  # Add entry if it doesn't exists
+  augeas { "${file_path}-${key}-${value}-add":
+    lens    => 'Json.lns',
+    incl    => $file_path,
+    changes => [
+      "set dict/entry[last()+1] \"${key}\"",
+      "set dict/entry[last()]/string \"${value}\""
+    ],
+    onlyif  => "match dict/entry[*][.=\"${key}\"] size == 0"
+  }
+
+  # Requires that the entry is added before this call or it will fail.
+  augeas { "${file_path}-${key}-${value}" :
+    lens    => 'Json.lns',
+    incl    => $file_path,
+    changes => "set dict/entry[*][.=\"${key}\"]/string ${value}",
+    require => Augeas["${file_path}-${key}-${value}-add"]
+  }
+
+}
+
diff --git a/3rdparty/modules/openstacklib/manifests/service_validation.pp b/3rdparty/modules/openstacklib/manifests/service_validation.pp
new file mode 100644 (file)
index 0000000..8a9ccd0
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# 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.
+#
+# == Definition: openstacklib::service_validation
+#
+# This resource does service validation for an OpenStack service.
+#
+# == Parameters:
+#
+# [*command*]
+# Command to run for validating the service;
+# string; required
+#
+# [*service_name*]
+# The name of the service to validate;
+# string; optional; default to the $title of the resource, i.e. 'nova-api'
+#
+# [*path*]
+# The path of the command to validate the service;
+# string; optional; default to '/usr/bin:/bin:/usr/sbin:/sbin'
+#
+# [*provider*]
+# The provider to use for the exec command;
+# string; optional; default to 'shell'
+#
+# [*tries*]
+# Number of times to retry validation;
+# string; optional; default to '10'
+#
+# [*try_sleep*]
+# Number of seconds between validation attempts;
+# string; optional; default to '2'
+#
+define openstacklib::service_validation(
+  $command,
+  $service_name = $name,
+  $path         = '/usr/bin:/bin:/usr/sbin:/sbin',
+  $provider     = shell,
+  $tries        = '10',
+  $try_sleep    = '2',
+) {
+
+  exec { "execute ${service_name} validation":
+    path      => $path,
+    provider  => $provider,
+    command   => $command,
+    tries     => $tries,
+    try_sleep => $try_sleep,
+  }
+
+  anchor { "create ${service_name} anchor":
+    require => Exec["execute ${service_name} validation"],
+  }
+
+}
diff --git a/3rdparty/modules/openstacklib/metadata.json b/3rdparty/modules/openstacklib/metadata.json
new file mode 100644 (file)
index 0000000..e941bfd
--- /dev/null
@@ -0,0 +1,55 @@
+{
+  "name": "stackforge-openstacklib",
+  "version": "5.1.0",
+  "author": "Puppet Labs and OpenStack Contributors",
+  "summary": "Puppet OpenStack Libraries",
+  "license": "Apache-2.0",
+  "source": "git://github.com/openstack/puppet-openstacklib.git",
+  "project_page": "https://launchpad.net/puppet-openstacklib",
+  "issues_url": "https://bugs.launchpad.net/puppet-openstacklib",
+  "dependencies": [
+    {"name":"aimonb/aviator","version_requirement":">=0.4.2 <1.0.0"},
+    {"name":"puppetlabs/mysql","version_requirement":">=2.2.0 <3.0.0"},
+    {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"},
+    {"name":"puppetlabs/rabbitmq","version_requirement":">=2.0.2 <4.0.0"}
+  ],
+  "requirements": [
+    {
+      "name": "pe",
+      "version_requirement": "3.x"
+    },
+    {
+      "name": "puppet",
+      "version_requirement": "3.x"
+    }
+  ],
+  "operatingsystem_support": [
+    {
+      "operatingsystem": "Debian",
+      "operatingsystemrelease": [
+        "7"
+      ]
+    },
+    {
+      "operatingsystem": "Fedora",
+      "operatingsystemrelease": [
+        "20"
+      ]
+    },
+    {
+      "operatingsystem": "RedHat",
+      "operatingsystemrelease": [
+        "6.5",
+        "7"
+      ]
+    },
+    {
+      "operatingsystem": "Ubuntu",
+      "operatingsystemrelease": [
+        "12.04",
+        "14.04"
+      ]
+    }
+  ],
+  "description": "Puppet module library to expose common functionality between OpenStack modules."
+}
diff --git a/3rdparty/modules/openstacklib/spec/classes/init_spec.rb b/3rdparty/modules/openstacklib/spec/classes/init_spec.rb
new file mode 100644 (file)
index 0000000..f8ec369
--- /dev/null
@@ -0,0 +1 @@
+require 'spec_helper'
diff --git a/3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb b/3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb
new file mode 100644 (file)
index 0000000..9d6927c
--- /dev/null
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe 'openstacklib::policy' do
+
+  let :params do
+    {
+      :policies => {
+        'foo' => {
+          'file_path' => '/etc/nova/policy.json',
+          'key'       => 'context_is_admin',
+          'value'     => 'foo:bar'
+        }
+      }
+    }
+  end
+
+  it 'configures the proper policy' do
+    should contain_openstacklib__policy__base('foo').with(
+      :file_path => '/etc/nova/policy.json',
+      :key       => 'context_is_admin',
+      :value     => 'foo:bar'
+    )
+  end
+
+end
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb
new file mode 100644 (file)
index 0000000..8f47bfa
--- /dev/null
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe 'openstacklib::db::mysql::host_access' do
+
+  let :pre_condition do
+    "include mysql::server\n" +
+    "openstacklib::db::mysql { 'nova':\n" +
+    "  password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601'}"
+  end
+
+  shared_examples 'openstacklib::db::mysql::host_access examples' do
+
+    context 'with required parameters' do
+      let (:title) { 'nova_10.0.0.1' }
+      let :params do
+        { :user          => 'foobar',
+          :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601',
+          :database      => 'nova',
+          :privileges    => 'ALL' }
+      end
+
+      it { should contain_mysql_user("#{params[:user]}@10.0.0.1").with(
+        :password_hash => params[:password_hash]
+      )}
+
+      it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with(
+        :user       => "#{params[:user]}@10.0.0.1",
+        :privileges => 'ALL',
+        :table      => "#{params[:database]}.*"
+      )}
+    end
+
+  end
+
+  context 'on a Debian osfamily' do
+    let :facts do
+      { :osfamily => "Debian" }
+    end
+
+    include_examples 'openstacklib::db::mysql::host_access examples'
+  end
+
+  context 'on a RedHat osfamily' do
+    let :facts do
+      { :osfamily => 'RedHat' }
+    end
+
+    include_examples 'openstacklib::db::mysql::host_access examples'
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb
new file mode 100644 (file)
index 0000000..fc9b54e
--- /dev/null
@@ -0,0 +1,163 @@
+require 'spec_helper'
+
+describe 'openstacklib::db::mysql' do
+
+  let :pre_condition do
+    'include mysql::server'
+  end
+
+  let (:title) { 'nova' }
+
+  let :required_params do
+    { :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601' }
+  end
+
+  shared_examples 'openstacklib::db::mysql examples' do
+
+    context 'with only required parameters' do
+      let :params do
+        required_params
+      end
+
+      it { should contain_mysql_database(title).with(
+        :charset => 'utf8',
+        :collate => 'utf8_general_ci'
+      )}
+      it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+        :user       => title,
+        :database   => title,
+        :privileges => 'ALL'
+      )}
+    end
+
+    context 'with overriding dbname parameter' do
+      let :params do
+        { :dbname => 'foobar' }.merge(required_params)
+      end
+
+      it { should contain_mysql_database(params[:dbname]).with(
+        :charset => 'utf8',
+        :collate => 'utf8_general_ci'
+      )}
+      it { should contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with(
+        :user       => title,
+        :database   => params[:dbname],
+        :privileges => 'ALL'
+      )}
+    end
+
+    context 'with overriding user parameter' do
+      let :params do
+        { :user => 'foobar' }.merge(required_params)
+      end
+
+      it { should contain_mysql_database(title).with(
+        :charset => 'utf8',
+        :collate => 'utf8_general_ci'
+      )}
+      it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+        :user       => params[:user],
+        :database   => title,
+        :privileges => 'ALL',
+      )}
+    end
+
+    context 'when overriding charset parameter' do
+      let :params do
+        { :charset => 'latin1' }.merge(required_params)
+      end
+
+      it { should contain_mysql_database(title).with_charset(params[:charset]) }
+    end
+
+    context 'when omitting the required parameter password_hash' do
+      let :params do
+        required_params.delete(:password_hash)
+      end
+      it { expect { should raise_error(Puppet::Error) } }
+    end
+
+    context 'when notifying other resources' do
+      let :pre_condition do
+        'exec {"nova-db-sync":}'
+      end
+      let :params do
+        { :notify => 'Exec[nova-db-sync]'}.merge(required_params)
+      end
+
+      it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") }
+    end
+
+    context 'when required for other openstack services' do
+      let :pre_condition do
+        'service {"keystone":}'
+      end
+      let :title do
+        'keystone'
+      end
+      let :params do
+        { :before => 'Service[keystone]'}.merge(required_params)
+      end
+
+      it { should contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") }
+    end
+
+    context "overriding allowed_hosts parameter with array value" do
+      let :params do
+        { :allowed_hosts  => ['127.0.0.1','%'] }.merge(required_params)
+      end
+
+      it {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+        :user          => title,
+        :password_hash => params[:password_hash],
+        :database      => title
+      )}
+      it {should contain_openstacklib__db__mysql__host_access("#{title}_%").with(
+        :user          => title,
+        :password_hash => params[:password_hash],
+        :database      => title
+      )}
+    end
+
+    context "overriding allowed_hosts parameter with string value" do
+      let :params do
+        { :allowed_hosts => '192.168.1.1' }.merge(required_params)
+      end
+
+      it {should contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with(
+        :user          => title,
+        :password_hash => params[:password_hash],
+        :database      => title
+      )}
+    end
+
+    context "overriding allowed_hosts parameter equals to host param " do
+      let :params do
+        { :allowed_hosts => '127.0.0.1' }.merge(required_params)
+      end
+
+      it {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+        :user          => title,
+        :password_hash => params[:password_hash],
+        :database      => title
+      )}
+    end
+
+  end
+
+  context 'on a Debian osfamily' do
+    let :facts do
+      { :osfamily => "Debian" }
+    end
+
+    include_examples 'openstacklib::db::mysql examples'
+  end
+
+  context 'on a RedHat osfamily' do
+    let :facts do
+      { :osfamily => 'RedHat' }
+    end
+
+    include_examples 'openstacklib::db::mysql examples'
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb
new file mode 100644 (file)
index 0000000..953c53b
--- /dev/null
@@ -0,0 +1,101 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# 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.
+
+require 'spec_helper'
+
+describe 'openstacklib::messaging::rabbitmq' do
+
+  let (:title) { 'nova' }
+
+  shared_examples 'openstacklib::messaging::rabbitmq examples' do
+
+    let :params do
+      {}
+    end
+
+    context 'with default parameters' do
+      it { should contain_rabbitmq_user('guest').with(
+        :admin    => false,
+        :password => 'guest',
+        :provider => 'rabbitmqctl',
+      )}
+      it { should contain_rabbitmq_user_permissions('guest@/').with(
+        :configure_permission => '.*',
+        :write_permission     => '.*',
+        :read_permission      => '.*',
+        :provider             => 'rabbitmqctl',
+      )}
+      it { should contain_rabbitmq_vhost('/').with(
+        :provider => 'rabbitmqctl',
+      )}
+    end
+
+    context 'with custom parameters' do
+      before :each do
+        params.merge!(
+          :userid               => 'nova',
+          :password             => 'secrete',
+          :virtual_host         => '/nova',
+          :is_admin             => true,
+          :configure_permission => '.nova',
+          :write_permission     => '.nova',
+          :read_permission      => '.nova'
+        )
+      end
+
+      it { should contain_rabbitmq_user('nova').with(
+        :admin    => true,
+        :password => 'secrete',
+        :provider => 'rabbitmqctl',
+      )}
+      it { should contain_rabbitmq_user_permissions('nova@/nova').with(
+        :configure_permission => '.nova',
+        :write_permission     => '.nova',
+        :read_permission      => '.nova',
+        :provider             => 'rabbitmqctl',
+      )}
+      it { should contain_rabbitmq_vhost('/nova').with(
+        :provider => 'rabbitmqctl',
+      )}
+    end
+
+    context 'when disabling vhost management' do
+      before :each do
+        params.merge!( :manage_vhost => false )
+      end
+
+      it { should_not contain_rabbitmq_vhost }
+    end
+
+  end
+
+  context 'on a Debian osfamily' do
+    let :facts do
+      { :osfamily => "Debian" }
+    end
+
+    include_examples 'openstacklib::messaging::rabbitmq examples'
+  end
+
+  context 'on a RedHat osfamily' do
+    let :facts do
+      { :osfamily => 'RedHat' }
+    end
+
+    include_examples 'openstacklib::messaging::rabbitmq examples'
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb
new file mode 100644 (file)
index 0000000..89be58c
--- /dev/null
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe 'openstacklib::policy::base' do
+
+  let :title do
+    'nova-contest_is_admin'
+  end
+
+  let :params do
+    {:file_path => '/etc/nova/policy.json',
+    :key       => 'context_is_admin',
+    :value     => 'foo:bar'}
+  end
+
+  it 'configures the proper policy' do
+    should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar').with(
+      'lens'    => 'Json.lns',
+      'incl'    => '/etc/nova/policy.json',
+      'changes' => 'set dict/entry[*][.="context_is_admin"]/string foo:bar',
+      'require' => 'Augeas[/etc/nova/policy.json-context_is_admin-foo:bar-add]'
+    )
+  end
+
+  it 'configures the proper policy' do
+    should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar-add').with(
+      'lens'    => 'Json.lns',
+      'incl'    => '/etc/nova/policy.json',
+      'changes' => [
+          'set dict/entry[last()+1] "context_is_admin"',
+          'set dict/entry[last()]/string "foo:bar"'
+      ],
+      'onlyif' => 'match dict/entry[*][.="context_is_admin"] size == 0'
+    )
+  end
+
+end
+
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb
new file mode 100644 (file)
index 0000000..17e4389
--- /dev/null
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# 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.
+
+require 'spec_helper'
+
+describe 'openstacklib::service_validation' do
+
+  let (:title) { 'nova-api' }
+
+  let :required_params do
+    { :command => 'nova list' }
+  end
+
+  shared_examples 'openstacklib::service_validation examples' do
+
+    context 'with only required parameters' do
+      let :params do
+        required_params
+      end
+
+      it { should contain_exec("execute #{title} validation").with(
+        :path      => '/usr/bin:/bin:/usr/sbin:/sbin',
+        :provider  => 'shell',
+        :command   => 'nova list',
+        :tries     => '10',
+        :try_sleep => '2',
+      )}
+
+      it { should contain_anchor("create #{title} anchor").with(
+        :require => "Exec[execute #{title} validation]",
+      )}
+
+    end
+
+    context 'when omitting a required parameter command' do
+      let :params do
+        required_params.delete(:command)
+      end
+      it { expect { should raise_error(Puppet::Error) } }
+    end
+
+  end
+
+  context 'on a Debian osfamily' do
+    let :facts do
+      { :osfamily => "Debian" }
+    end
+
+    include_examples 'openstacklib::service_validation examples'
+  end
+
+  context 'on a RedHat osfamily' do
+    let :facts do
+      { :osfamily => 'RedHat' }
+    end
+
+    include_examples 'openstacklib::service_validation examples'
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml
new file mode 100644 (file)
index 0000000..2d052df
--- /dev/null
@@ -0,0 +1,67 @@
+--- 
+  http_interactions: 
+    - request: 
+        method: post
+        uri: "http://192.168.11.4:35357/v2.0/tokens"
+        body: 
+          encoding: UTF-8
+          string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}"
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "9780"
+          date: 
+            - "Tue, 30 Sep 2014 06:59:48 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T06:59:48.338940\x22, \x22expires\x22: \x222014-09-30T07:59:48Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
+    - request: 
+        method: get
+        uri: "http://172.16.33.4:35357/v2.0/tenants"
+        body: 
+          encoding: US-ASCII
+          string: ""
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+          X-Auth-Token: 
+            - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k="
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "491"
+          date: 
+            - "Tue, 30 Sep 2014 06:59:48 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
+  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml
new file mode 100644 (file)
index 0000000..784fb2f
--- /dev/null
@@ -0,0 +1,36 @@
+--- 
+  http_interactions: 
+    - request: 
+        method: get
+        uri: "http://192.168.11.4:35357/v2.0/tenants"
+        body: 
+          encoding: US-ASCII
+          string: ""
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+          X-Auth-Token: 
+            - sosp-kyl
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "491"
+          date: 
+            - "Tue, 30 Sep 2014 06:59:48 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
+  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml
new file mode 100644 (file)
index 0000000..3faa474
--- /dev/null
@@ -0,0 +1,67 @@
+--- 
+  http_interactions: 
+    - request: 
+        method: post
+        uri: "http://192.168.11.4:35357/v2.0/tokens"
+        body: 
+          encoding: UTF-8
+          string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}"
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "9780"
+          date: 
+            - "Tue, 30 Sep 2014 07:16:15 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T07:16:15.042778\x22, \x22expires\x22: \x222014-09-30T08:16:15Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT"
+    - request: 
+        method: get
+        uri: "http://192.168.11.4:5000/v2.0/tenants"
+        body: 
+          encoding: US-ASCII
+          string: ""
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+          X-Auth-Token: 
+            - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls="
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "143"
+          date: 
+            - "Tue, 30 Sep 2014 07:16:15 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT"
+  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml
new file mode 100644 (file)
index 0000000..784fb2f
--- /dev/null
@@ -0,0 +1,36 @@
+--- 
+  http_interactions: 
+    - request: 
+        method: get
+        uri: "http://192.168.11.4:35357/v2.0/tenants"
+        body: 
+          encoding: US-ASCII
+          string: ""
+        headers: 
+          Content-Type: 
+            - application/json
+          User-Agent: 
+            - "Faraday v0.8.8"
+          X-Auth-Token: 
+            - sosp-kyl
+      response: 
+        status: 
+          code: 200
+          message: 
+        headers: 
+          vary: 
+            - X-Auth-Token
+          content-type: 
+            - application/json
+          content-length: 
+            - "491"
+          date: 
+            - "Tue, 30 Sep 2014 06:59:48 GMT"
+          connection: 
+            - close
+        body: 
+          encoding: UTF-8
+          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
+        http_version: 
+      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
+  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb b/3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb
new file mode 100644 (file)
index 0000000..6819e7e
--- /dev/null
@@ -0,0 +1,134 @@
+require 'spec_helper'
+
+describe 'os_database_connection' do
+
+  it 'refuses String' do
+    should run.with_params('foo').\
+      and_raise_error(Puppet::ParseError, /Requires an hash/)
+  end
+
+  it 'refuses Array' do
+    should run.with_params(['foo']).\
+      and_raise_error(Puppet::ParseError, /Requires an hash/)
+  end
+
+  it 'refuses without at least one argument' do
+    should run.with_params().\
+      and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
+  end
+
+  it 'refuses too many arguments' do
+    should run.with_params('foo', 'bar').\
+      and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
+  end
+
+  it 'fails if port is provided with missing host' do
+    should run.with_params({
+        'dialect'  => 'sqlite',
+        'database' => '/var/lib/keystone/keystone.db',
+        'port'     => '3306',
+        'charset'  => 'utf-8'
+      }).and_raise_error(Puppet::ParseError, /host is required with port/)
+  end
+
+  context 'creates the correct connection URI' do
+
+    it 'with all parameters' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => 'guest',
+          'password' => 's3cr3t',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'without port' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'database' => 'test',
+          'username' => 'guest',
+          'password' => 's3cr3t',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://guest:s3cr3t@127.0.0.1/test?charset=utf-8')
+    end
+
+    it 'without host and port' do
+      should run.with_params({
+          'dialect'  => 'sqlite',
+          'database' => '/var/lib/keystone/keystone.db',
+          'charset'  => 'utf-8'
+        }).and_return('sqlite:////var/lib/keystone/keystone.db?charset=utf-8')
+    end
+
+    it 'without username and password' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'with username set to undef' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => :undef,
+          'charset'  => 'utf-8'
+        }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'with username set to an empty string' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => '',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'without password' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => 'guest',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'with password set to undef' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => 'guest',
+          'password' => :undef,
+          'charset'  => 'utf-8'
+        }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
+    end
+
+    it 'with password set to an empty string' do
+      should run.with_params({
+          'dialect'  => 'mysql',
+          'host'     => '127.0.0.1',
+          'port'     => '3306',
+          'database' => 'test',
+          'username' => 'guest',
+          'password' => '',
+          'charset'  => 'utf-8'
+        }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/spec_helper.rb b/3rdparty/modules/openstacklib/spec/spec_helper.rb
new file mode 100644 (file)
index 0000000..ecd609a
--- /dev/null
@@ -0,0 +1,7 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
+require 'vcr'
+
+VCR.configure do |c|
+  c.cassette_library_dir = 'spec/fixtures/vcr'
+  c.hook_into :faraday
+end
diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb
new file mode 100644 (file)
index 0000000..35564e6
--- /dev/null
@@ -0,0 +1,320 @@
+# Load libraries from aviator here to simulate how they live together in a real puppet run
+$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
+require 'puppet'
+require 'vcr'
+require 'spec_helper'
+require 'puppet/provider/aviator'
+
+
+describe Puppet::Provider::Aviator do
+
+  before(:each) do
+    ENV['OS_USERNAME']    = nil
+    ENV['OS_PASSWORD']    = nil
+    ENV['OS_TENANT_NAME'] = nil
+    ENV['OS_AUTH_URL']    = nil
+  end
+
+  let(:log_file) { '/tmp/aviator_spec.log' }
+
+  let(:type) do
+    Puppet::Type.newtype(:test_resource) do
+      newparam(:name, :namevar => true)
+      newparam(:auth)
+      newparam(:log_file)
+    end
+  end
+
+
+  shared_examples 'creating a session using environment variables' do
+    it 'creates an authenticated session' do
+      ENV['OS_USERNAME']    = 'admin'
+      ENV['OS_PASSWORD']    = 'fyby-tet'
+      ENV['OS_TENANT_NAME'] = 'admin'
+      ENV['OS_AUTH_URL']    = 'http://192.168.11.4:35357/v2.0'
+      response = nil
+      VCR.use_cassette('aviator/session/with_password') do
+        session = provider.session
+        response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
+      end
+      expect(response.status).to eq(200)
+    end
+  end
+
+  shared_examples 'creating a session using a service token from keystone.conf' do
+    it 'creates an unauthenticated session' do
+      data = "[DEFAULT]\nadmin_token=sosp-kyl\nadmin_endpoint=http://192.168.11.4:35357/v2.0"
+      response = nil
+      VCR.use_cassette('aviator/session/with_token') do
+        # Stubbing File.read produces inconsistent results because of how IniConfig
+        # overrides the File class in some versions of Puppet.
+        # Stubbing FileType.filetype(:flat) simplifies working with IniConfig
+        Puppet::Util::FileType.filetype(:flat).any_instance.expects(:read).returns(StringIO.new(data).read)
+        session = provider.session
+        Puppet::Util::FileType.filetype(:flat).any_instance.unstub(:read)
+        response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
+      end
+
+      expect(response.status).to eq(200)
+    end
+  end
+
+  shared_examples 'it has no credentials' do
+    it 'fails to authenticate' do
+      expect{ provider.session }.to raise_error(Puppet::Error, /No credentials provided/)
+    end
+  end
+
+  shared_examples 'making request with an existing session' do
+   it 'makes a successful request' do
+     VCR.use_cassette('aviator/request/with_session') do
+       session = provider.session
+       response = provider.request(session.identity_service, :list_tenants)
+       expect(response.status).to eq(200)
+     end
+   end
+  end
+
+  shared_examples 'making request with injected session data' do
+    it 'makes a successful request' do
+      VCR.use_cassette('aviator/request/without_session') do
+        session = provider.session
+        response = provider.request(session.identity_service, :list_tenants)
+        expect(response.status).to eq(200)
+      end
+    end
+  end
+
+  shared_examples 'making request with no session or session data' do
+    it 'fails to make a request' do
+      expect{ provider.request(nil, :list_tenants) }.to raise_error(Puppet::Error, /Cannot make a request/)
+    end
+  end
+
+  describe '#session' do
+
+    context 'with valid password credentials in parameters' do
+      let(:resource_attrs) do
+        {
+          :name         => 'stubresource',
+          :auth         => {
+            'username'    => 'admin',
+            'password'    => 'fyby-tet',
+            'tenant_name' => 'admin',
+            'host_uri'    => 'http://192.168.11.4:35357/v2.0',
+          }
+        }
+      end
+
+      it 'creates a session' do
+        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        response = nil
+        VCR.use_cassette('aviator/session/with_password') do
+          session = provider.session
+          response = session.identity_service.request(:list_tenants)
+        end
+        expect(response.status).to eq(200)
+      end
+    end
+
+    context 'with valid openrc file in parameters' do
+      data = "export OS_USERNAME='admin'\nexport OS_PASSWORD='fyby-tet'\nexport OS_TENANT_NAME='admin'\nexport OS_AUTH_URL='http://192.168.11.4:35357/v2.0'"
+      let(:resource_attrs) do
+        {
+          :name         => 'stubresource',
+          :auth         => {
+            'openrc' => '/root/openrc'
+          }
+        }
+      end
+
+      it 'creates a session' do
+        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        response = nil
+        VCR.use_cassette('aviator/session/with_password') do
+          File.expects(:open).with('/root/openrc').returns(StringIO.new(data))
+          session = provider.session
+          File.unstub(:open)  # Ignore File.open calls to cassette file
+          response = session.identity_service.request(:list_tenants)
+        end
+        expect(response.status).to eq(200)
+      end
+    end
+
+    context 'with valid service token in parameters' do
+      let(:resource_attrs) do
+        {
+          :name         => 'stubresource',
+          :auth         => {
+            'service_token' => 'sosp-kyl',
+            'host_uri'      => 'http://192.168.11.4:35357/v2.0'
+          }
+        }
+      end
+
+      subject(:session) do
+        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        VCR.use_cassette('aviator/session/with_token') do
+          session = provider.session
+          response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
+        end
+      end
+
+      it 'creates a session' do
+        expect(session.status).to eq(200)
+      end
+
+    end
+
+    context 'with valid password credentials in environment variables' do
+      it_behaves_like 'creating a session using environment variables' do
+        let(:resource_attrs) do
+          {
+            :name => 'stubresource',
+          }
+        end
+        let(:provider) do
+          Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        end
+      end
+    end
+
+    context 'with valid service token in keystone.conf' do
+      it_behaves_like 'creating a session using a service token from keystone.conf' do
+        let(:resource_attrs) do
+          {
+            :name => 'stubresource',
+          }
+        end
+        let(:provider) do
+          Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        end
+      end
+
+    end
+
+    context 'with no valid credentials' do
+      it_behaves_like 'it has no credentials' do
+        let(:resource_attrs) do
+          {
+            :name => 'stubresource',
+          }
+        end
+        let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
+      end
+    end
+
+  end
+
+
+  describe '::session' do
+
+    context 'with valid password credentials in environment variables' do
+      it_behaves_like 'creating a session using environment variables' do
+        let(:provider) { Puppet::Provider::Aviator.dup }
+      end
+    end
+
+    context 'with valid service token in keystone.conf' do
+      it_behaves_like 'creating a session using a service token from keystone.conf' do
+        let(:provider) { Puppet::Provider::Aviator.dup }
+      end
+    end
+
+    context 'with no valid credentials' do
+      it_behaves_like 'it has no credentials' do
+        let(:provider) { Puppet::Provider::Aviator.dup }
+      end
+    end
+  end
+
+  describe '#request' do
+    context 'when a session exists' do
+      it_behaves_like 'making request with an existing session' do
+        let(:resource_attrs) do
+          {
+            :name         => 'stubresource',
+            :auth         => {
+              'username'    => 'admin',
+              'password'    => 'fyby-tet',
+              'tenant_name' => 'admin',
+              'host_uri'    => 'http://192.168.11.4:35357/v2.0',
+            }
+          }
+        end
+        let (:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
+      end
+    end
+
+    context 'when injecting session data' do
+      let(:resource_attrs) do
+        {
+          :name         => 'stubresource',
+          :auth         => {
+            'service_token' => 'sosp-kyl',
+            'host_uri'      => 'http://192.168.11.4:35357/v2.0'
+          }
+        }
+      end
+      let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
+      it 'makes a successful request' do
+        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
+        VCR.use_cassette('aviator/request/without_session') do
+          session = provider.session
+          response = provider.request(session.identity_service, :list_tenants)
+          expect(response.status).to eq(200)
+        end
+      end
+    end
+
+    context 'when there is no session or session data' do
+      it_behaves_like 'making request with no session or session data' do
+        let(:resource_attrs) do
+          {
+            :name => 'stubresource',
+          }
+        end
+        let(:provider) {Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
+      end
+    end
+  end
+
+  describe '::request' do
+    context 'when a session exists' do
+
+      it_behaves_like 'making request with an existing session' do
+        let(:provider) { provider = Puppet::Provider::Aviator.dup }
+        before(:each) do
+          ENV['OS_USERNAME']    = 'admin'
+          ENV['OS_PASSWORD']    = 'fyby-tet'
+          ENV['OS_TENANT_NAME'] = 'admin'
+          ENV['OS_AUTH_URL']    = 'http://192.168.11.4:35357/v2.0'
+        end
+      end
+    end
+
+    context 'when injecting session data' do
+      let(:session_data) do
+        {
+          :base_url      => 'http://192.168.11.4:35357/v2.0',
+          :service_token => 'sosp-kyl'
+        }
+      end
+      it 'makes a successful request' do
+        provider = Puppet::Provider::Aviator.dup
+        VCR.use_cassette('aviator/request/without_session') do
+          session = ::Aviator::Session.new(:config => { :provider => 'openstack' }, :log_file => log_file)
+          provider.session_data = session_data
+          response = provider.request(session.identity_service, :list_tenants)
+          expect(response.status).to eq(200)
+        end
+      end
+    end
+
+    context 'when there is no session or session data' do
+      it_behaves_like 'making request with no session or session data' do
+        let(:provider) { Puppet::Provider::Aviator.dup }
+      end
+    end
+  end
+end