diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 6026383..0eaf511 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -6,4 +6,4 @@ name: 'Test' jobs: lint-unit: - uses: test-kitchen/.github/.github/workflows/lint-unit.yml@main \ No newline at end of file + uses: test-kitchen/.github/.github/workflows/lint-unit.yml@v0.1.2 diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..b7332e5 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,35 @@ +--- +name: release-please + +"on": + push: + branches: [main] + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v3 + id: release + with: + release-type: ruby + package-name: kitchen-rackspace + version-file: lib/kitchen/driver/rackspace_version.rb + token: ${{ secrets.PORTER_GITHUB_TOKEN }} + + - name: Checkout + uses: actions/checkout@v4 + if: ${{ steps.release.outputs.release_created }} + + - name: Build and publish to GitHub Package + uses: actionshub/publish-gem-to-github@main + if: ${{ steps.release.outputs.release_created }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + owner: ${{ secrets.OWNER }} + + - name: Build and publish to RubyGems + uses: actionshub/publish-gem-to-rubygems@main + if: ${{ steps.release.outputs.release_created }} + with: + token: ${{ secrets.RUBYGEMS_API_KEY }} diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 989316b..b5908fb 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -1,6 +1,9 @@ - --- - MD012: false - MD013: false - MD024: false - MD036: false - +--- +default: true +MD013: false +MD024: false +MD026: false +MD036: false +MD012: false +MD029: false +MD004: false diff --git a/.mdlrc b/.mdlrc deleted file mode 100644 index 508f328..0000000 --- a/.mdlrc +++ /dev/null @@ -1,2 +0,0 @@ -rules "~MD036", "~MD013", "~MD024", "~MD029" - diff --git a/.rubocop.yml b/.rubocop.yml index 4fd1a6e..8fd406e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,13 +1,11 @@ -# Allow additional lines until main driver class can be split -# into smaller classes. +--- +require: + - chefstyle -ClassLength: - Max: 131 -AbcSize: - Max: 20 -MethodLength: - Max: 15 -Metrics/BlockLength: - Max: 600 -Metrics/LineLength: - Max: 100 +AllCops: + TargetRubyVersion: 3.1 + Include: + - "**/*.rb" + Exclude: + - "vendor/**/*" + - "spec/**/*" diff --git a/CHANGELOG.md b/CHANGELOG.md index f5cd325..f7fd86b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,142 +1,142 @@ -# Unreleased +# Kitchen-rackspace Changelog -# 0.21.0 / 2016-05-31 +## 0.21.0 / 2016-05-31 -* PR [#67][] - Update image IDS; via [@martinb3][] -* PR [#65][] - Add Ubuntu 16.04; via [@coderanger][] +* PR [#67] - Update image IDS; via [@martinb3] +* PR [#65] - Add Ubuntu 16.04; via [@coderanger] -# 0.20.0 / 2016-01-15 +## 0.20.0 / 2016-01-15 -* PR [#63][] - Update image IDs, add Ubuntu 15.10, drop Ubuntu 15.04; via -[@martinb3][] +* PR [#63] - Update image IDs, add Ubuntu 15.10, drop Ubuntu 15.04; via +[@martinb3] -# 0.19.0 / 2015-10-06 +## 0.19.0 / 2015-10-06 -* PR [#60][] - Update to latest image IDs -* PR [#57][] - Add `servicelevel_wait` option; via [@martinb3][] -* PR [#56][] - Add `no_passwd_lock` option; via [@martinb3][] +* PR [#60] - Update to latest image IDs +* PR [#57] - Add `servicelevel_wait` option; via [@martinb3] +* PR [#56] - Add `no_passwd_lock` option; via [@martinb3] -# 0.18.0 / 2015-08-28 +## 0.18.0 / 2015-08-28 -* PR [#53][] - Update image IDs, update Arch to 2015.7, drop Fedora 20, add -Fedora 22, update Gentoo to 15.3, update Vyatta to 6.7R9; via [@martinb3][] +* PR [#53] - Update image IDs, update Arch to 2015.7, drop Fedora 20, add +Fedora 22, update Gentoo to 15.3, update Vyatta to 6.7R9; via [@martinb3] -# 0.17.0 / 2015-05-15 +## 0.17.0 / 2015-05-15 -* PR [#51][] - Update image IDS--add Debian 8, drop Debian 6, add Ubuntu 15.04, +* PR [#51] - Update image IDS--add Debian 8, drop Debian 6, add Ubuntu 15.04, drop Ubuntu 14.10 -# 0.16.0 / 2015-04-15 +## 0.16.0 / 2015-04-15 -* PR [#50][] - Update image IDs, support 'centos-7.0' in addition to -'centos-7'; via [@martinb3][] +* PR [#50] - Update image IDs, support 'centos-7.0' in addition to +'centos-7'; via [@martinb3] -# 0.15.1 / 2015-04-03 +## 0.15.1 / 2015-04-03 -* PR [#49][] - Update image IDs, re-add CentOS point release numbers; via -[@martinb3][] +* PR [#49] - Update image IDs, re-add CentOS point release numbers; via +[@martinb3] -# 0.15.0 / 2015-04-02 +## 0.15.0 / 2015-04-02 -* PR [#48][] - Drop references to retired Ubuntu 10.04 image -* PR [#46][] - Update all image IDs, add Scientific 7, remove references to -point releases that Rackspace no longer uses in image names; via [@martinb3][] +* PR [#48] - Drop references to retired Ubuntu 10.04 image +* PR [#46] - Update all image IDs, add Scientific 7, remove references to +point releases that Rackspace no longer uses in image names; via [@martinb3] -# 0.14.0 / 2014-12-09 +## 0.14.0 / 2014-12-09 -* PR [#45][] - Add Ubuntu 14.10 and Fedora 21 -* PR [#44][] - Update all image IDs, add CentOS/Red Hat 5.11 and Red Hat 6.6, -update Vyatta to 6.7R4; via [@martinb3][] +* PR [#45] - Add Ubuntu 14.10 and Fedora 21 +* PR [#44] - Update all image IDs, add CentOS/Red Hat 5.11 and Red Hat 6.6, +update Vyatta to 6.7R4; via [@martinb3] -# 0.13.0 / 2014-10-08 +## 0.13.0 / 2014-10-08 ### Improvements -* PR [#43][] - Update all image IDs, bump Arch to 2014.10, Gentoo to 14.4, +* PR [#43] - Update all image IDs, bump Arch to 2014.10, Gentoo to 14.4, Vyatta to 6.7 -* PR [#42][] - Update CentOS 7 image ID; via [@marcoamorales][] +* PR [#42] - Update CentOS 7 image ID; via [@marcoamorales] -# 0.12.0 / 2014-09-10 +## 0.12.0 / 2014-09-10 ### New Features -* PR [#41][] - Support optionally using ServiceNet for SSH access, via -[@steve-jansen][] +* PR [#41] - Support optionally using ServiceNet for SSH access, via +[@steve-jansen] -# 0.11.0 / 2014-09-04 +## 0.11.0 / 2014-09-04 ### Improvements -* PR [#40][] - Port the server name generator from the OpenStack/DigitalOcean +* PR [#40] - Port the server name generator from the OpenStack/DigitalOcean drivers, with all its bug fixes; update image IDs -# 0.10.0 / 2014-08-28 +## 0.10.0 / 2014-08-28 ### Improvements -* PR [#39][] - Update image ID list -* PR [#38][] - Recognize `debian-7.6` image name, via [@martinb3][] +* PR [#39] - Update image ID list +* PR [#38] - Recognize `debian-7.6` image name, via [@martinb3] -# 0.9.0 / 2014-08-25 +## 0.9.0 / 2014-08-25 ### Improvements -* PR [#37][] - Update image ID list -* PR [#36][] - Add CentOS 7 to the recognized images, via [@hhoover][] +* PR [#37] - Update image ID list +* PR [#36] - Add CentOS 7 to the recognized images, via [@hhoover] -# 0.8.0 / 2014-08-20 +## 0.8.0 / 2014-08-20 ### New Features -* PR [#35][] - Add option to wait on RackConnect, via [@martinb3][] +* PR [#35] - Add option to wait on RackConnect, via [@martinb3] -# 0.7.0 / 2014-07-09 +## 0.7.0 / 2014-07-09 ### New Features -* PR [#31][] - Support attaching to custom networks, via [@kanerogers][] -* PR [#29][] - Support using a sleep instead of TCP check in cases where new -servers might fail the TCP; via [@martinb3][] +* PR [#31] - Support attaching to custom networks, via [@kanerogers] +* PR [#29] - Support using a sleep instead of TCP check in cases where new +servers might fail the TCP; via [@martinb3] -# 0.6.1 / 2014-06-03 +## 0.6.1 / 2014-06-03 ### Bug Fixes -* PR [#26][] - Fix issue with builds failing due to a timeout set at 0 +* PR [#26] - Fix issue with builds failing due to a timeout set at 0 -# 0.6.0 / 2014-05-13 +## 0.6.0 / 2014-05-13 ### New Features -* PR [#25][] - Allow overridding of Fog's default timeout; via [@pezholio][] +* PR [#25] - Allow overridding of Fog's default timeout; via [@pezholio] ### Improvements -* PR [#24][] - Error out immediately when trying to install in Ruby 1.8 +* PR [#24] - Error out immediately when trying to install in Ruby 1.8 -# 0.5.0 / 2014-05-01 +## 0.5.0 / 2014-05-01 ### Improvements -* PR [#23][] - Switch to PVHVM images, where available -* PR [#22][] - Update all the images with new IDs -* PR [#21][] - Add Ubuntu 14.04 to the list of known images; via [@pezholio][] +* PR [#23] - Switch to PVHVM images, where available +* PR [#22] - Update all the images with new IDs +* PR [#21] - Add Ubuntu 14.04 to the list of known images; via [@pezholio] -# 0.4.0 / 2014-01-27 +## 0.4.0 / 2014-01-27 ### New Features -* PR [#17][] - Support the common TK platform name style, e.g. `centos-6`, -via [@coderanger][] -* PR [#17][] - Support environment variables for username and API key, via -[@coderanger][] +* PR [#17] - Support the common TK platform name style, e.g. `centos-6`, +via [@coderanger] +* PR [#17] - Support environment variables for username and API key, via +[@coderanger] ### Improvements -* PR [#17][] - Change default flavor to lowest performance flavor for faster -boot times, via [@coderanger][] +* PR [#17] - Change default flavor to lowest performance flavor for faster +boot times, via [@coderanger] -# 0.3.0 / 2013-12-07 +## 0.3.0 / 2013-12-07 ### Improvements @@ -144,21 +144,21 @@ boot times, via [@coderanger][] ### Bug Fixes -* PR [#15][] - Update default `image_id` to a current one -* PR [#15][] - Fix collision with TK 1.x; change `name` option to `server_name` +* PR [#15] - Update default `image_id` to a current one +* PR [#15] - Fix collision with TK 1.x; change `name` option to `server_name` -# 0.2.0 / 2013-05-11 +## 0.2.0 / 2013-05-11 ### New Features -* PR [#8][] - Support `rackspace_region:` option; at request of [@claco][] +* PR [#8] - Support `rackspace_region:` option; at request of [@claco] ### Improvements -* PR [#7][] - Clean up/refactor to pass style checks -* PR [#9][] - Add some (probably overkill) RSpec tests +* PR [#7] - Clean up/refactor to pass style checks +* PR [#9] - Add some (probably overkill) RSpec tests -# 0.1.0 / 2013-03-12 +## 0.1.0 / 2013-03-12 * Initial release! Woo! diff --git a/Gemfile b/Gemfile index e148137..c488ba4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,13 @@ -source 'https://rubygems.org' +source "https://rubygems.org" -# Specify your gem's dependencies in kitchen-rackspace.gemspec gemspec + +group :test do + gem "bundler" + gem "rake" + gem "rspec", "~> 3.2" +end + +group :chefstyle do + gem "chefstyle", "~> 2.2", ">= 2.2.3" +end diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index cb5ecd2..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,15 +0,0 @@ -Author:: Jonathan Hartman () - -Copyright (c) 2013-2015 Jonathan Hartman - -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/README.md b/README.md index c6156c2..be1d531 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ +# Kitchen::Rackspace + [![Gem Version](https://img.shields.io/gem/v/kitchen-rackspace.svg)][gem] [gem]: https://rubygems.org/gems/kitchen-rackspace -Kitchen::Rackspace -================== - A Rackspace Cloud Servers driver for Test Kitchen! Shamelessly copied from [Fletcher Nichol](https://github.com/fnichol)'s @@ -14,68 +13,78 @@ awesome work on an [EC2 driver](https://github.com/opscode/kitchen-ec2). This software project is no longer under active development as it has no active maintainers. The software may continue to work for some or all use cases, but issues filed in GitHub will most likely not be triaged. If a new maintainer is interested in working on this project please come chat with us in #test-kitchen on Chef Community Slack. -Installation ------------- +## Installation Add this line to your application's Gemfile: - gem 'kitchen-rackspace' +```ruby +gem 'kitchen-rackspace' +``` And then execute: - $ bundle +```shell +bundle +``` Or install it yourself as: - $ gem install kitchen-rackspace +```shell +gem install kitchen-rackspace +``` -Usage ------ +## Usage Provide, at a minimum, the required driver options in your `.kitchen.yml` file: - driver: - name: rackspace - rackspace_username: [YOUR RACKSPACE CLOUD USERNAME] - rackspace_api_key: [YOUR RACKSPACE CLOUD API KEY] - require_chef_omnibus: [e.g. 'true' or a version number if you need Chef] - platforms: - - name: [A PLATFORM NAME, e.g. 'centos-6'] +```yaml +driver: + name: rackspace + rackspace_username: [YOUR RACKSPACE CLOUD USERNAME] + rackspace_api_key: [YOUR RACKSPACE CLOUD API KEY] + require_chef_omnibus: [e.g. 'true' or a version number if you need Chef] +platforms: + - name: [A PLATFORM NAME, e.g. 'centos-6'] +``` By default, the driver will spawn a 1GB Performance server on the base image for your specified platform. Additional, optional overrides can be provided: - image_id: [SERVER IMAGE ID] - flavor_id: [SERVER FLAVOR ID] - server_name: [A FRIENDLY SERVER NAME] - public_key_path: [PATH TO YOUR PUBLIC SSH KEY] - rackspace_region: [A VALID RACKSPACE DC/REGION] - wait_for: [NUM OF SECONDS TO WAIT BEFORE TIMING OUT, DEFAULT 600] - no_ssh_tcp_check: [DEFAULTS TO false, SKIPS TCP CHECK WHEN true] - no_ssh_tcp_check_sleep: [NUM OF SECONDS TO SLEEP IF no_ssh_tcp_check IS SET] - networks: [LIST OF RACKSPACE NETWORK UUIDS, DEFAULT PUBLICNET AND SERVICE NET] - rackconnect_wait: ['true' IF USING RACKCONNECT TO WAIT FOR IT TO COMPLETE] - servicelevel_wait: ['true' IF USING MANAGED SERVICE LEVEL AUTOMATION TO WAIT FOR IT TO COMPLETE] - no_passwd_lock: ['true' IF FOG LIBRARY SHOULD NOT LOCK ROOT ACCOUNT] - servicenet: ['true' IF USING THE SERVICENET IP ADDRESS TO CONNECT] - config_drive: [DEFAULTS TO true, ENABLES READ-ONLY METADATA DRIVE] - user_data: [EXTRA CONFIGURATION DATA FOR THE SERVER] +```yaml +image_id: [SERVER IMAGE ID] +flavor_id: [SERVER FLAVOR ID] +server_name: [A FRIENDLY SERVER NAME] +public_key_path: [PATH TO YOUR PUBLIC SSH KEY] +rackspace_region: [A VALID RACKSPACE DC/REGION] +wait_for: [NUM OF SECONDS TO WAIT BEFORE TIMING OUT, DEFAULT 600] +no_ssh_tcp_check: [DEFAULTS TO false, SKIPS TCP CHECK WHEN true] +no_ssh_tcp_check_sleep: [NUM OF SECONDS TO SLEEP IF no_ssh_tcp_check IS SET] +networks: [LIST OF RACKSPACE NETWORK UUIDS, DEFAULT PUBLICNET AND SERVICE NET] +rackconnect_wait: ['true' IF USING RACKCONNECT TO WAIT FOR IT TO COMPLETE] +servicelevel_wait: ['true' IF USING MANAGED SERVICE LEVEL AUTOMATION TO WAIT FOR IT TO COMPLETE] +no_passwd_lock: ['true' IF FOG LIBRARY SHOULD NOT LOCK ROOT ACCOUNT] +servicenet: ['true' IF USING THE SERVICENET IP ADDRESS TO CONNECT] +config_drive: [DEFAULTS TO true, ENABLES READ-ONLY METADATA DRIVE] +user_data: [EXTRA CONFIGURATION DATA FOR THE SERVER] +``` You also have the option of providing some configs via environment variables: +```shell export RACKSPACE_USERNAME="user" # (or OS_USERNAME) export RACKSPACE_API_KEY="api_key" # (or OS_PASSWORD) export RACKSPACE_REGION="dfw" # (or OS_REGION_NAME) +``` Some configs are also derived based on your .ssh directory, specifically the `public_key_path` setting is derived by searching for: + - `~/.ssh/id_rsa.pub` - `~/.ssh/id_dsa.pub` - `~/.ssh/identity.pub` - `~/.ssh/id_ecdsa.pub` -Contributing ------------- +## Contributing 1. Fork it 2. `bundle install` diff --git a/Rakefile b/Rakefile index 722d6a0..8962295 100644 --- a/Rakefile +++ b/Rakefile @@ -1,9 +1,15 @@ -require 'bundler/setup' -require 'rubocop/rake_task' -require 'rspec/core/rake_task' +require "bundler/gem_tasks" -RuboCop::RakeTask.new - -RSpec::Core::RakeTask.new(:spec) - -task default: %i[rubocop spec] +# Create the spec task. +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new(:test, :tag) do |t, args| + t.rspec_opts = [].tap do |a| + a << "--color" + a << "--format #{ENV["CI"] ? "documentation" : "progress"}" + a << "--backtrace" if ENV["VERBOSE"] || ENV["DEBUG"] + a << "--seed #{ENV["SEED"]}" if ENV["SEED"] + a << "--tag #{args[:tag]}" if args[:tag] + a << "--default-path test" + a << "-I test/spec" + end.join(" ") +end diff --git a/helpers/dump_image_list.rb b/helpers/dump_image_list.rb index 5809a24..8ad46f0 100755 --- a/helpers/dump_image_list.rb +++ b/helpers/dump_image_list.rb @@ -1,55 +1,55 @@ -#!/usr/bin/env ruby -require 'fog/rackspace' -require 'json' unless defined?(JSON) +require "fog/rackspace" +require "json" unless defined?(JSON) def whole?(x) # rubocop:disable Naming/UncommunicativeMethodParamName (x - x.floor) < 1e-6 end i_care_about = { - 'Arch Linux (PVHVM)' => %w[arch arch-2016 arch-2016.8], - 'CentOS 7 (PVHVM)' => %w[centos centos-7], - 'CentOS 6 (PVHVM)' => %w[centos-6], - 'CoreOS (Stable)' => %w[coreos coreos-stable], - 'CoreOS (Beta)' => %w[coreos-beta], - 'CoreOS (Alpha)' => %w[coreos-alpha], - 'Debian 8 (Jessie) (PVHVM)' => %w[debian debian-8], - 'Debian 7 (Wheezy) (PVHVM)' => %w[debian-7], - 'Debian Testing (Stretch) (PVHVM)' => %w[debian-testing], - 'Debian Unstable (Sid) (PVHVM)' => %w[debian-unstable], - 'Fedora 25 (PVHVM)' => %w[fedora fedora-25], - 'Fedora 24 (PVHVM)' => %w[fedora-24], - 'FreeBSD 11 (PVHVM)' => %w[freebsd freebsd-11], - 'FreeBSD 10 (PVHVM)' => %w[freebsd-10], - 'Gentoo 15.3 (PVHVM)' => %w[gentoo gentoo-15 gentoo-15.3], - 'OpenSUSE Leap 42 (PVHVM)' => %w[opensuse opensuse-42], - 'Scientific Linux 7 (PVHVM)' => %w[scientific scientific-7], - 'Scientific Linux 6 (PVHVM)' => %w[scientific-6], - 'Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)' => %w[ubuntu ubuntu-16 ubuntu-16.04], - 'Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)' => %w[ubuntu-14 ubuntu-14.04], - 'Ubuntu 12.04 LTS (Precise Pangolin) (PVHVM)' => %w[ubuntu-12 ubuntu-12.04], - 'Vyatta Network OS 6.7R12' => %w[vyatta vyatta-6 vyatta-6.7 vyatta-6.7R12], - 'Windows Server 2012 R2' => %w[windows windows-2012 windows-2012R2], - 'Windows Server 2008 R2 SP1' => %w[windows-2008 + "Arch Linux (PVHVM)" => %w{arch arch-2016 arch-2016.8}, + "CentOS 7 (PVHVM)" => %w{centos centos-7}, + "CentOS 6 (PVHVM)" => %w{centos-6}, + "CoreOS (Stable)" => %w{coreos coreos-stable}, + "CoreOS (Beta)" => %w{coreos-beta}, + "CoreOS (Alpha)" => %w{coreos-alpha}, + "Debian 8 (Jessie) (PVHVM)" => %w{debian debian-8}, + "Debian 7 (Wheezy) (PVHVM)" => %w{debian-7}, + "Debian Testing (Stretch) (PVHVM)" => %w{debian-testing}, + "Debian Unstable (Sid) (PVHVM)" => %w{debian-unstable}, + "Fedora 25 (PVHVM)" => %w{fedora fedora-25}, + "Fedora 24 (PVHVM)" => %w{fedora-24}, + "FreeBSD 11 (PVHVM)" => %w{freebsd freebsd-11}, + "FreeBSD 10 (PVHVM)" => %w{freebsd-10}, + "Gentoo 15.3 (PVHVM)" => %w{gentoo gentoo-15 gentoo-15.3}, + "OpenSUSE Leap 42 (PVHVM)" => %w{opensuse opensuse-42}, + "Scientific Linux 7 (PVHVM)" => %w{scientific scientific-7}, + "Scientific Linux 6 (PVHVM)" => %w{scientific-6}, + "Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)" => %w{ubuntu ubuntu-16 ubuntu-16.04}, + "Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)" => %w{ubuntu-14 ubuntu-14.04}, + "Ubuntu 12.04 LTS (Precise Pangolin) (PVHVM)" => %w{ubuntu-12 ubuntu-12.04}, + "Vyatta Network OS 6.7R12" => %w{vyatta vyatta-6 vyatta-6.7 vyatta-6.7R12}, + "Windows Server 2012 R2" => %w{windows windows-2012 windows-2012R2}, + "Windows Server 2008 R2 SP1" => %w{windows-2008 windows-2008R2 - windows-2008R2SP1] + windows-2008R2SP1}, } names_to_clean = { - 'com.microsoft.server' => 'windows', - 'org.fedoraproject' => 'fedora', - 'org.archlinux' => 'arch', - 'org.scientificlinux' => 'scientific' + "com.microsoft.server" => "windows", + "org.fedoraproject" => "fedora", + "org.archlinux" => "arch", + "org.scientificlinux" => "scientific", } -compute = Fog::Compute.new(provider: 'Rackspace', - rackspace_username: ENV['RACKSPACE_USERNAME'], - rackspace_api_key: ENV['RACKSPACE_API_KEY'], - rackspace_region: 'ORD') +compute = Fog::Compute.new(provider: "Rackspace", + rackspace_username: ENV["RACKSPACE_USERNAME"], + rackspace_api_key: ENV["RACKSPACE_API_KEY"], + rackspace_region: "ORD") aliases = i_care_about.values.flatten res = aliases.each_with_object({}) do |a, hsh| raise "Alias '#{a}' was listed twice" if hsh.include?(a) + hsh[a] = nil hsh end @@ -57,23 +57,23 @@ def whole?(x) # rubocop:disable Naming/UncommunicativeMethodParamName compute.images.select { |i| i_care_about.key?(i.name) }.each do |img| image_metadata = img.metadata - if image_metadata['org.openstack__1__os_distro'] && - image_metadata['org.openstack__1__os_version'] + if image_metadata["org.openstack__1__os_distro"] && + image_metadata["org.openstack__1__os_version"] - distro_id = image_metadata['org.openstack__1__os_distro'] - version = image_metadata['org.openstack__1__os_version'] + distro_id = image_metadata["org.openstack__1__os_distro"] + version = image_metadata["org.openstack__1__os_version"] distro = if names_to_clean.include?(distro_id) names_to_clean[distro_id] else - distro_id.split('.').last + distro_id.split(".").last end res["#{distro}-#{version}"] = img.id # if it's a whole number non-zero version, also add # a dot-zero (centos-7 vs centos-7.0) - res["#{distro}-#{version}.0"] = img.id if version != '0' && version =~ /^\s*\d+\s*$/ + res["#{distro}-#{version}.0"] = img.id if version != "0" && version =~ /^\s*\d+\s*$/ end i_care_about[img.name].each { |a| res[a] = img.id } diff --git a/kitchen-rackspace.gemspec b/kitchen-rackspace.gemspec index 36eaa02..c348d93 100644 --- a/kitchen-rackspace.gemspec +++ b/kitchen-rackspace.gemspec @@ -1,31 +1,24 @@ -lib = File.expand_path('lib', __dir__) +lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'kitchen/driver/rackspace_version' +require "kitchen/driver/rackspace_version" Gem::Specification.new do |spec| - spec.name = 'kitchen-rackspace' + spec.name = "kitchen-rackspace" spec.version = Kitchen::Driver::RACKSPACE_VERSION - spec.authors = ['Jonathan Hartman'] - spec.email = %w[j@p4nt5.com] - spec.description = 'A Test Kitchen Rackspace driver' - spec.summary = 'A Test Kitchen Rackspace driver built on Fog' - spec.homepage = 'https://github.com/test-kitchen/kitchen-rackspace' - spec.license = 'Apache' + spec.authors = ["Jonathan Hartman"] + spec.email = %w{j@p4nt5.com} + spec.description = "A Test Kitchen Rackspace driver" + spec.summary = "A Test Kitchen Rackspace driver built on Fog" + spec.homepage = "https://github.com/test-kitchen/kitchen-rackspace" + spec.license = "Apache" spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = %w[lib] + spec.require_paths = %w{lib} - spec.required_ruby_version = '>= 2.5' + spec.required_ruby_version = ">= 3.1" - spec.add_dependency 'fog-rackspace', '~> 0.1' - spec.add_dependency 'test-kitchen', '>= 1.1', '< 4.0' - - spec.add_development_dependency 'coveralls', '~> 0.8' - spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rubocop', '~> 1.28.2' - spec.add_development_dependency 'simplecov', '~> 0.9' - spec.add_development_dependency 'simplecov-console', '~> 0.2' + spec.add_dependency "fog-rackspace", "~> 0.1.6" + spec.add_dependency "test-kitchen", ">= 1.1", "< 4.0" end diff --git a/lib/kitchen/driver/rackspace.rb b/lib/kitchen/driver/rackspace.rb index 5b7c553..c986a35 100644 --- a/lib/kitchen/driver/rackspace.rb +++ b/lib/kitchen/driver/rackspace.rb @@ -1,36 +1,16 @@ -# -# Author:: Jonathan Hartman () -# -# Copyright (C) 2013-2015, Jonathan Hartman -# -# 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 'benchmark' unless defined?(Benchmark) -require 'fog/rackspace' -require 'kitchen' -require 'etc' unless defined?(Etc) -require 'socket' unless defined?(Socket) +require "benchmark" unless defined?(Benchmark) +require "fog/rackspace" +require "kitchen" +require "etc" unless defined?(Etc) +require "socket" unless defined?(Socket) module Kitchen module Driver - # Rackspace driver for Kitchen. - # - # @author Jonathan Hartman class Rackspace < Kitchen::Driver::SSHBase - default_config :version, 'v2' - default_config :flavor_id, 'performance1-1' - default_config :username, 'root' - default_config :port, '22' + default_config :version, "v2" + default_config :flavor_id, "performance1-1" + default_config :username, "root" + default_config :port, "22" default_config :wait_for, 600 default_config :no_ssh_tcp_check, false default_config :no_ssh_tcp_check_sleep, 120 @@ -46,23 +26,23 @@ class Rackspace < Kitchen::Driver::SSHBase default_config :public_key_path do [ - File.expand_path('~/.ssh/id_rsa.pub'), - File.expand_path('~/.ssh/id_dsa.pub'), - File.expand_path('~/.ssh/identity.pub'), - File.expand_path('~/.ssh/id_ecdsa.pub') + File.expand_path("~/.ssh/id_rsa.pub"), + File.expand_path("~/.ssh/id_dsa.pub"), + File.expand_path("~/.ssh/identity.pub"), + File.expand_path("~/.ssh/id_ecdsa.pub"), ].find { |path| File.exist?(path) } end default_config :rackspace_username do - ENV['RACKSPACE_USERNAME'] || ENV['OS_USERNAME'] + ENV["RACKSPACE_USERNAME"] || ENV["OS_USERNAME"] end default_config :rackspace_api_key do - ENV['RACKSPACE_API_KEY'] || ENV['OS_PASSWORD'] + ENV["RACKSPACE_API_KEY"] || ENV["OS_PASSWORD"] end default_config :rackspace_region do - ENV['RACKSPACE_REGION'] || ENV['OS_REGION_NAME'] || 'dfw' + ENV["RACKSPACE_REGION"] || ENV["OS_REGION_NAME"] || "dfw" end required_config :rackspace_username @@ -80,7 +60,7 @@ def create(state) state[:server_id] = server.id info("Rackspace instance <#{state[:server_id]}> created.") server.wait_for { ready? } - puts '(server ready)' + puts "(server ready)" rackconnect_check(server) if config[:rackconnect_wait] servicelevel_check(server) if config[:servicelevel_wait] state[:hostname] = hostname(server) @@ -113,19 +93,19 @@ def default_image # Total: 63 def default_name [ - instance.name.gsub(/\W/, '')[0..14], - (Etc.getlogin || 'nologin').gsub(/\W/, '')[0..14], - Socket.gethostname.gsub(/\W/, '')[0..22], - Array.new(7) { rand(36).to_s(36) }.join - ].join('-') + instance.name.gsub(/\W/, "")[0..14], + (Etc.getlogin || "nologin").gsub(/\W/, "")[0..14], + Socket.gethostname.gsub(/\W/, "")[0..22], + Array.new(7) { rand(36).to_s(36) }.join, + ].join("-") end private def compute - server_def = { provider: 'Rackspace' } - opts = %i[version rackspace_username rackspace_api_key - rackspace_region] + server_def = { provider: "Rackspace" } + opts = %i{version rackspace_username rackspace_api_key + rackspace_region} opts.each do |opt| server_def[opt] = config[opt] end @@ -133,8 +113,8 @@ def compute end def create_server - server_def = { name: config[:server_name], networks: networks } - %i[image_id flavor_id public_key_path no_passwd_lock user_data config_drive].each do |opt| + server_def = { name: config[:server_name], networks: } + %i{image_id flavor_id public_key_path no_passwd_lock user_data config_drive}.each do |opt| server_def[opt] = config[opt] end # see @note on bootstrap def about rackconnect @@ -145,7 +125,7 @@ def create_server def images @images ||= begin - json_file = File.expand_path('../../../data/images.json', __dir__) + json_file = File.expand_path("../../../data/images.json", __dir__) JSON.parse(IO.read(json_file)) end end @@ -155,20 +135,20 @@ def tcp_check(state) # it doesn't respect ssh_config values that might be required wait_for_sshd(state[:hostname]) unless config[:no_ssh_tcp_check] sleep(config[:no_ssh_tcp_check_sleep]) if config[:no_ssh_tcp_check] - puts '(ssh ready)' + puts "(ssh ready)" end def rackconnect_check(server) server.wait_for \ - { metadata.all['rackconnect_automation_status'] == 'DEPLOYED' } - puts '(rackconnect automation complete)' + { metadata.all["rackconnect_automation_status"] == "DEPLOYED" } + puts "(rackconnect automation complete)" server.update # refresh accessIPv4 with new IP end def servicelevel_check(server) server.wait_for \ - { metadata.all['rax_service_level_automation'] == 'Complete' } - puts '(service level automation complete)' + { metadata.all["rax_service_level_automation"] == "Complete" } + puts "(service level automation complete)" end def hostname(server) @@ -180,10 +160,10 @@ def hostname(server) end def networks - base_nets = %w[ + base_nets = %w{ 00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111 - ] + } config[:networks] ? base_nets + config[:networks] : nil end end diff --git a/lib/kitchen/driver/rackspace_version.rb b/lib/kitchen/driver/rackspace_version.rb index 8cf5589..97f10f2 100644 --- a/lib/kitchen/driver/rackspace_version.rb +++ b/lib/kitchen/driver/rackspace_version.rb @@ -1,27 +1,6 @@ # frozen_string_literal: true - -# -# Author:: Jonathan Hartman () -# -# Copyright (C) 2013-2015, Jonathan Hartman -# -# 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. - module Kitchen - # Version string for Rackspace Kitchen driver - # - # @author Jonathan Hartman module Driver - RACKSPACE_VERSION = '0.21.1.dev'.freeze + RACKSPACE_VERSION = "0.21.1.dev" end end diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..b65764b --- /dev/null +++ b/renovate.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":disableDependencyDashboard", + "schedule:automergeEarlyMondays" + ] +} diff --git a/spec/kitchen/driver/rackspace_spec.rb b/spec/kitchen/driver/rackspace_spec.rb index c8c06a7..2b5fe97 100644 --- a/spec/kitchen/driver/rackspace_spec.rb +++ b/spec/kitchen/driver/rackspace_spec.rb @@ -1,25 +1,19 @@ -require_relative '../../spec_helper' -require_relative '../../../lib/kitchen/driver/rackspace' - -require 'logger' -require 'stringio' unless defined?(StringIO) -require 'rspec' -require 'kitchen' +require_relative "../../spec_helper" describe Kitchen::Driver::Rackspace do let(:logged_output) { StringIO.new } let(:logger) { Logger.new(logged_output) } let(:config) { {} } let(:state) { {} } - let(:platform_name) { 'ubuntu' } + let(:platform_name) { "ubuntu" } let(:default_networks) { nil } - let(:instance_name) { 'potatoes' } + let(:instance_name) { "potatoes" } let(:instance) do double( name: instance_name, - logger: logger, - to_str: 'instance', + logger:, + to_str: "instance", platform: double(name: platform_name) ) end @@ -29,117 +23,117 @@ before(:each) do allow_any_instance_of(described_class).to receive(:instance) .and_return(instance) - ENV['RACKSPACE_USERNAME'] = 'user' - ENV['RACKSPACE_API_KEY'] = 'key' + ENV["RACKSPACE_USERNAME"] = "user" + ENV["RACKSPACE_API_KEY"] = "key" end - describe '#initialize' do + describe "#initialize" do before(:each) do allow(Fog).to receive(:timeout=) end - context 'default options' do - it 'defaults to v2 cloud' do - expect(driver[:version]).to eq('v2') + context "default options" do + it "defaults to v2 cloud" do + expect(driver[:version]).to eq("v2") end - it 'defaults to the smallest flavor size' do - expect(driver[:flavor_id]).to eq('performance1-1') + it "defaults to the smallest flavor size" do + expect(driver[:flavor_id]).to eq("performance1-1") end it "defaults to local user's SSH public key" do - path = File.expand_path('~/.ssh/id_rsa.pub') + path = File.expand_path("~/.ssh/id_rsa.pub") expect(File).to receive(:exist?).with(path).and_return(true) expect(driver[:public_key_path]).to eq(path) end - it 'defaults to SSH with root user on port 22' do - expect(driver[:username]).to eq('root') - expect(driver[:port]).to eq('22') + it "defaults to SSH with root user on port 22" do + expect(driver[:username]).to eq("root") + expect(driver[:port]).to eq("22") end - it 'defaults to a random server name' do + it "defaults to a random server name" do expect(driver[:server_name]).to be_a(String) end - it 'defaults to the DFW region' do - expect(driver[:rackspace_region]).to eq('dfw') + it "defaults to the DFW region" do + expect(driver[:rackspace_region]).to eq("dfw") end - it 'defaults to username from $RACKSPACE_USERNAME' do - expect(driver[:rackspace_username]).to eq('user') + it "defaults to username from $RACKSPACE_USERNAME" do + expect(driver[:rackspace_username]).to eq("user") end - it 'defaults to API key from $RACKSPACE_API_KEY' do - expect(driver[:rackspace_api_key]).to eq('key') + it "defaults to API key from $RACKSPACE_API_KEY" do + expect(driver[:rackspace_api_key]).to eq("key") end - it 'defaults to wait_for timeout of 600 seconds' do + it "defaults to wait_for timeout of 600 seconds" do expect(driver[:wait_for]).to eq(600) expect(Fog).to have_received(:timeout=).with(600) end - it 'defaults the SSH TCP bypassing to false' do + it "defaults the SSH TCP bypassing to false" do expect(driver[:no_ssh_tcp_check]).to eq(false) end - it 'defaults the TCP bypass sleep time to 120 seconds' do + it "defaults the TCP bypass sleep time to 120 seconds" do expect(driver[:no_ssh_tcp_check_sleep]).to eq(120) end - it 'defaults to the standard Rackspace networks' do + it "defaults to the standard Rackspace networks" do expect(driver[:networks]).to eq(default_networks) end - it 'defaults to not waiting for rackconnect' do + it "defaults to not waiting for rackconnect" do expect(driver[:rackconnect_wait]).to eq(false) end - it 'defaults to not waiting for managed service level' do + it "defaults to not waiting for managed service level" do expect(driver[:servicelevel_wait]).to eq(false) end - it 'defaults to the public ip address' do + it "defaults to the public ip address" do expect(driver[:servicenet]).to eq(false) end - it 'defaults to no_passwd_lock as false' do + it "defaults to no_passwd_lock as false" do expect(driver[:no_passwd_lock]).to eq(false) end end platforms = { - 'ubuntu-12.04' => 'f2d30a56-bc2b-4906-8027-92f8a45bbb10', - 'ubuntu-12' => 'f2d30a56-bc2b-4906-8027-92f8a45bbb10', - 'ubuntu-14.04' => 'e6baca58-c5f4-48d3-901a-abdeb0cfe907', - 'ubuntu-14' => 'e6baca58-c5f4-48d3-901a-abdeb0cfe907', - 'ubuntu' => '9b3ae961-0ba0-4d5a-973f-2e79043f0ddd', - 'centos-6' => '7d791876-4c8f-44a2-8d4b-e84bfb0b1c8c', - 'centos' => '1a79f262-33d2-428c-924b-9852a6c15ea8' + "ubuntu-12.04" => "f2d30a56-bc2b-4906-8027-92f8a45bbb10", + "ubuntu-12" => "f2d30a56-bc2b-4906-8027-92f8a45bbb10", + "ubuntu-14.04" => "e6baca58-c5f4-48d3-901a-abdeb0cfe907", + "ubuntu-14" => "e6baca58-c5f4-48d3-901a-abdeb0cfe907", + "ubuntu" => "9b3ae961-0ba0-4d5a-973f-2e79043f0ddd", + "centos-6" => "7d791876-4c8f-44a2-8d4b-e84bfb0b1c8c", + "centos" => "1a79f262-33d2-428c-924b-9852a6c15ea8", } platforms.each do |platform, id| context "name is #{platform}" do let(:platform_name) { platform } - it 'defaults to the correct image ID' do + it "defaults to the correct image ID" do expect(driver[:image_id]).to eq(id) end end end - context 'overridden options' do + context "overridden options" do config = { - image_id: '22', - flavor_id: '33', - public_key_path: '/tmp', - username: 'admin', - port: '2222', - server_name: 'puppy', - rackspace_region: 'ord', + image_id: "22", + flavor_id: "33", + public_key_path: "/tmp", + username: "admin", + port: "2222", + server_name: "puppy", + rackspace_region: "ord", wait_for: 1200, rackconnect_wait: true, servicelevel_wait: true, - use_private_ip_address: true + use_private_ip_address: true, } let(:config) { config } @@ -150,289 +144,289 @@ end end - it 'sets the new wait_for variable' do + it "sets the new wait_for variable" do expect(driver[:wait_for]).to eq(1200) expect(Fog).to have_received(:timeout=).with(1200) end end - context 'OpenStack environment variables' do + context "OpenStack environment variables" do before(:each) do - ENV.delete('RACKSPACE_USERNAME') - ENV.delete('RACKSPACE_API_KEY') - ENV.delete('RACKSPACE_REGION') - ENV['OS_USERNAME'] = 'os_user' - ENV['OS_PASSWORD'] = 'os_pass' - ENV['OS_REGION_NAME'] = 'os_region' + ENV.delete("RACKSPACE_USERNAME") + ENV.delete("RACKSPACE_API_KEY") + ENV.delete("RACKSPACE_REGION") + ENV["OS_USERNAME"] = "os_user" + ENV["OS_PASSWORD"] = "os_pass" + ENV["OS_REGION_NAME"] = "os_region" end - it 'gets to username from $OS_USERNAME' do - expect(driver[:rackspace_username]).to eq('os_user') + it "gets to username from $OS_USERNAME" do + expect(driver[:rackspace_username]).to eq("os_user") end - it 'gets to API key from $OS_PASSWORD' do - expect(driver[:rackspace_api_key]).to eq('os_pass') + it "gets to API key from $OS_PASSWORD" do + expect(driver[:rackspace_api_key]).to eq("os_pass") end - it 'gets to region from $OS_REGION_NAME' do - expect(driver[:rackspace_region]).to eq('os_region') + it "gets to region from $OS_REGION_NAME" do + expect(driver[:rackspace_region]).to eq("os_region") end end end - describe '#create' do - let(:config) { super().merge(wait_for: '1200') } + describe "#create" do + let(:config) { super().merge(wait_for: "1200") } let(:server) do - double(id: 'test123', + double(id: "test123", wait_for: true, - public_ip_address: '1.2.3.4') + public_ip_address: "1.2.3.4") end before(:each) do { - default_name: 'a_monkey!', + default_name: "a_monkey!", create_server: server, - tcp_check: true + tcp_check: true, }.each do |k, v| allow_any_instance_of(described_class).to receive(k).and_return(v) end end - context 'username and API key only provided' do + context "username and API key only provided" do let(:config) do { - rackspace_username: 'hello', - rackspace_api_key: 'world', - wait_for: 1200 + rackspace_username: "hello", + rackspace_api_key: "world", + wait_for: 1200, } end - it 'generates a server name in the absence of one' do + it "generates a server name in the absence of one" do driver.create(state) - expect(driver[:server_name]).to eq('a_monkey!') + expect(driver[:server_name]).to eq("a_monkey!") end - it 'gets a proper server ID' do + it "gets a proper server ID" do driver.create(state) - expect(state[:server_id]).to eq('test123') + expect(state[:server_id]).to eq("test123") end - it 'gets a proper hostname (IP)' do + it "gets a proper hostname (IP)" do driver.create(state) - expect(state[:hostname]).to eq('1.2.3.4') + expect(state[:hostname]).to eq("1.2.3.4") end - it 'calls tcp_check' do + it "calls tcp_check" do expect(driver).to receive(:tcp_check) driver.create(state) end end - context 'a Fog error' do + context "a Fog error" do before(:each) do allow_any_instance_of(described_class).to receive(:create_server) - .and_raise(Fog::Errors::Error, 'Uhoh') + .and_raise(Fog::Errors::Error, "Uhoh") end - it 're-raises the error' do + it "re-raises the error" do expect { driver.create(state) }.to raise_error(Kitchen::ActionFailed, - 'Uhoh') + "Uhoh") end end end - describe '#create and rackconnect_wait' do + describe "#create and rackconnect_wait" do let(:server) do - double(id: 'test123', + double(id: "test123", wait_for: true, - public_ip_address: '1.2.3.4', - private_ip_address: '10.9.8.7', + public_ip_address: "1.2.3.4", + private_ip_address: "10.9.8.7", update: nil) end before(:each) do { - default_name: 'a_monkey!', + default_name: "a_monkey!", create_server: server, - tcp_check: true + tcp_check: true, }.each do |k, v| allow_any_instance_of(described_class).to receive(k).and_return(v) end end - context 'username and API key only provided' do + context "username and API key only provided" do let(:config) do { - rackspace_username: 'hello', - rackspace_api_key: 'world', + rackspace_username: "hello", + rackspace_api_key: "world", wait_for: 1200, - rackconnect_wait: true + rackconnect_wait: true, } end - it 'generates a server name in the absence of one' do + it "generates a server name in the absence of one" do driver.create(state) - expect(driver[:server_name]).to eq('a_monkey!') + expect(driver[:server_name]).to eq("a_monkey!") end - it 'gets a proper server ID' do + it "gets a proper server ID" do driver.create(state) - expect(state[:server_id]).to eq('test123') + expect(state[:server_id]).to eq("test123") end - it 'gets a proper hostname (IP)' do + it "gets a proper hostname (IP)" do driver.create(state) - expect(state[:hostname]).to eq('1.2.3.4') + expect(state[:hostname]).to eq("1.2.3.4") end - it 'calls tcp_check' do + it "calls tcp_check" do expect(driver).to receive(:tcp_check) driver.create(state) end - it 'calls rackconnect_check ' do + it "calls rackconnect_check " do expect(driver).to receive(:rackconnect_check) driver.create(state) end - it 'rackconnect_check waits for rackconnect_automation' do + it "rackconnect_check waits for rackconnect_automation" do expect(server).to receive(:wait_for) driver.send(:rackconnect_check, server) end end end - describe '#create and servicelevel_wait' do + describe "#create and servicelevel_wait" do let(:server) do - double(id: 'test123', + double(id: "test123", wait_for: true, - public_ip_address: '1.2.3.4', - private_ip_address: '10.9.8.7', + public_ip_address: "1.2.3.4", + private_ip_address: "10.9.8.7", update: nil) end before(:each) do { - default_name: 'a_monkey!', + default_name: "a_monkey!", create_server: server, - tcp_check: true + tcp_check: true, }.each do |k, v| allow_any_instance_of(described_class).to receive(k).and_return(v) end end - context 'username and API key only provided' do + context "username and API key only provided" do let(:config) do { - rackspace_username: 'hello', - rackspace_api_key: 'world', + rackspace_username: "hello", + rackspace_api_key: "world", wait_for: 1200, - servicelevel_wait: true + servicelevel_wait: true, } end - it 'generates a server name in the absence of one' do + it "generates a server name in the absence of one" do driver.create(state) - expect(driver[:server_name]).to eq('a_monkey!') + expect(driver[:server_name]).to eq("a_monkey!") end - it 'gets a proper server ID' do + it "gets a proper server ID" do driver.create(state) - expect(state[:server_id]).to eq('test123') + expect(state[:server_id]).to eq("test123") end - it 'gets a proper hostname (IP)' do + it "gets a proper hostname (IP)" do driver.create(state) - expect(state[:hostname]).to eq('1.2.3.4') + expect(state[:hostname]).to eq("1.2.3.4") end - it 'calls tcp_check' do + it "calls tcp_check" do expect(driver).to receive(:tcp_check) driver.create(state) end - it 'calls servicelevel_check ' do + it "calls servicelevel_check " do expect(driver).to receive(:servicelevel_check) driver.create(state) end - it 'servicelevel_check waits for managed service level automation' do + it "servicelevel_check waits for managed service level automation" do expect(server).to receive(:wait_for) driver.send(:servicelevel_check, server) end end end - describe '#create and use_private_ip_address' do + describe "#create and use_private_ip_address" do let(:server) do - double(id: 'test123', + double(id: "test123", wait_for: true, - public_ip_address: '1.2.3.4', - private_ip_address: '10.9.8.7') + public_ip_address: "1.2.3.4", + private_ip_address: "10.9.8.7") end before(:each) do { - default_name: 'a_monkey!', + default_name: "a_monkey!", create_server: server, - tcp_check: true + tcp_check: true, }.each do |k, v| allow_any_instance_of(described_class).to receive(k).and_return(v) end end - context 'username and API key only provided' do + context "username and API key only provided" do let(:config) do { - rackspace_username: 'hello', - rackspace_api_key: 'world', + rackspace_username: "hello", + rackspace_api_key: "world", wait_for: 1200, - servicenet: true + servicenet: true, } end - it 'generates a server name in the absence of one' do + it "generates a server name in the absence of one" do driver.create(state) - expect(driver[:server_name]).to eq('a_monkey!') + expect(driver[:server_name]).to eq("a_monkey!") end - it 'gets a proper server ID' do + it "gets a proper server ID" do driver.create(state) - expect(state[:server_id]).to eq('test123') + expect(state[:server_id]).to eq("test123") end - it 'gets a private ip as the hostname' do + it "gets a private ip as the hostname" do driver.create(state) - expect(state[:hostname]).to eq('10.9.8.7') + expect(state[:hostname]).to eq("10.9.8.7") end end end - describe '#destroy' do - let(:server_id) { '12345' } - let(:hostname) { 'example.com' } - let(:state) { { server_id: server_id, hostname: hostname } } + describe "#destroy" do + let(:server_id) { "12345" } + let(:hostname) { "example.com" } + let(:state) { { server_id:, hostname: } } let(:server) { double(nil?: false, destroy: true) } let(:servers) { double(get: server) } - let(:compute) { double(servers: servers) } + let(:compute) { double(servers:) } before(:each) do allow_any_instance_of(described_class).to receive(:compute) .and_return(compute) end - context 'a live server that needs to be destroyed' do - it 'destroys the server' do + context "a live server that needs to be destroyed" do + it "destroys the server" do expect(state).to receive(:delete).with(:server_id) expect(state).to receive(:delete).with(:hostname) driver.destroy(state) end end - context 'no server ID present' do + context "no server ID present" do let(:state) { {} } - it 'does nothing' do + it "does nothing" do allow(driver).to receive(:compute) expect(driver).to_not receive(:compute) expect(state).to_not receive(:delete) @@ -440,75 +434,75 @@ end end - context 'a server that was already destroyed' do + context "a server that was already destroyed" do let(:servers) do - s = double('servers') - allow(s).to receive(:get).with('12345').and_return(nil) + s = double("servers") + allow(s).to receive(:get).with("12345").and_return(nil) s end - let(:compute) { double(servers: servers) } + let(:compute) { double(servers:) } before(:each) do allow_any_instance_of(described_class).to receive(:compute) .and_return(compute) end - it 'does not try to destroy the server again' do + it "does not try to destroy the server again" do allow_message_expectations_on_nil driver.destroy(state) end end end - describe '#compute' do + describe "#compute" do let(:config) do { - rackspace_username: 'monkey', - rackspace_api_key: 'potato', - rackspace_region: 'ord' + rackspace_username: "monkey", + rackspace_api_key: "potato", + rackspace_region: "ord", } end - context 'all requirements provided' do - it 'creates a new compute connection' do + context "all requirements provided" do + it "creates a new compute connection" do allow(Fog::Compute).to receive(:new) { |arg| arg } - res = config.merge(provider: 'Rackspace', version: 'v2') + res = config.merge(provider: "Rackspace", version: "v2") expect(driver.send(:compute)).to eq(res) end end - context 'no username provided' do + context "no username provided" do let(:config) do - { rackspace_username: nil, rackspace_api_key: '1234' } + { rackspace_username: nil, rackspace_api_key: "1234" } end - it 'raises an error' do + it "raises an error" do expect { driver.send(:compute) }.to raise_error(ArgumentError) end end - context 'no API key provided' do + context "no API key provided" do let(:config) do - { rackspace_username: 'monkey', rackspace_api_key: nil } + { rackspace_username: "monkey", rackspace_api_key: nil } end - it 'raises an error' do + it "raises an error" do expect { driver.send(:compute) }.to raise_error(ArgumentError) end end end - describe '#create_server' do + describe "#create_server" do let(:config) do { - server_name: 'hello', - image_id: 'there', - flavor_id: 'captain', - public_key_path: 'tarpals', + server_name: "hello", + image_id: "there", + flavor_id: "captain", + public_key_path: "tarpals", no_passwd_lock: false, networks: default_networks, user_data: nil, - config_drive: false + config_drive: false, } end before(:each) do @@ -518,48 +512,48 @@ end end let(:servers) do - s = double('servers') + s = double("servers") allow(s).to receive(:bootstrap) { |arg| arg } s end - let(:compute) { double(servers: servers) } + let(:compute) { double(servers:) } before(:each) do allow_any_instance_of(described_class).to receive(:compute) .and_return(compute) end - it 'creates the server using a compute connection' do + it "creates the server using a compute connection" do expect(driver.send(:create_server)).to eq(@expected) end - context 'additional networks specified' do - let(:server_id) { '12345' } + context "additional networks specified" do + let(:server_id) { "12345" } let(:server) do - double(id: 'test123', wait_for: true, - public_ip_address: '1.2.3.4') - end - let(:hostname) { 'example.com' } - let(:servers) { double('servers', bootstrap: server) } - let(:compute) { double(Fog::Compute, servers: servers) } - let(:state) { { server_id: server_id, hostname: hostname } } - let(:user_specified_network) { 'bob_dole' } + double(id: "test123", wait_for: true, + public_ip_address: "1.2.3.4") + end + let(:hostname) { "example.com" } + let(:servers) { double("servers", bootstrap: server) } + let(:compute) { double(Fog::Compute, servers:) } + let(:state) { { server_id:, hostname: } } + let(:user_specified_network) { "bob_dole" } let(:config) do { - rackspace_username: 'monkey', - rackspace_api_key: 'potato', - rackspace_region: 'ord', - networks: [user_specified_network] + rackspace_username: "monkey", + rackspace_api_key: "potato", + rackspace_region: "ord", + networks: [user_specified_network], } end before(:each) do - { wait_for_sshd: true, compute: compute }.each do |k, v| + { wait_for_sshd: true, compute: }.each do |k, v| allow_any_instance_of(described_class).to receive(k).and_return(v) end end - it 'has the user specified network, plus default Rackspace networks' do + it "has the user specified network, plus default Rackspace networks" do driver.send(:create_server) expect(servers).to have_received(:bootstrap) do |arg| expect(arg[:networks][2]).to eq user_specified_network @@ -568,67 +562,67 @@ end end - describe '#default_name' do - let(:login) { 'user' } - let(:hostname) { 'host' } + describe "#default_name" do + let(:login) { "user" } + let(:hostname) { "host" } before(:each) do allow(Etc).to receive(:getlogin).and_return(login) allow(Socket).to receive(:gethostname).and_return(hostname) end - it 'generates a name' do + it "generates a name" do expect(driver.send(:default_name)).to match(/^potatoes-user-host-(\S*)/) end - context 'local node with a long hostname' do - let(:hostname) { 'ab.c' * 20 } + context "local node with a long hostname" do + let(:hostname) { "ab.c" * 20 } - it 'limits the generated name to 63 characters' do + it "limits the generated name to 63 characters" do expect(driver.send(:default_name).length).to be <= 63 end end - context 'node with a long hostname, username, and base name' do - let(:login) { 'abcd' * 20 } - let(:hostname) { 'efgh' * 20 } - let(:instance_name) { 'ijkl' * 20 } + context "node with a long hostname, username, and base name" do + let(:login) { "abcd" * 20 } + let(:hostname) { "efgh" * 20 } + let(:instance_name) { "ijkl" * 20 } - it 'limits the generated name to 63 characters' do + it "limits the generated name to 63 characters" do expect(driver.send(:default_name).length).to eq(63) end end - context 'a login and hostname with punctuation in them' do - let(:login) { 'some.u-se-r' } - let(:hostname) { 'a.host-name' } - let(:instance_name) { 'a.instance-name' } + context "a login and hostname with punctuation in them" do + let(:login) { "some.u-se-r" } + let(:hostname) { "a.host-name" } + let(:instance_name) { "a.instance-name" } - it 'strips out the dots to prevent bad server names' do - expect(driver.send(:default_name)).to_not include('.') + it "strips out the dots to prevent bad server names" do + expect(driver.send(:default_name)).to_not include(".") end - it 'strips out all but the three hyphen separators' do - expect(driver.send(:default_name).count('-')).to eq(3) + it "strips out all but the three hyphen separators" do + expect(driver.send(:default_name).count("-")).to eq(3) end end - context 'a non-login shell' do + context "a non-login shell" do let(:login) { nil } - it 'subs in a placeholder login string' do + it "subs in a placeholder login string" do expect(driver.send(:default_name)).to match(/^potatoes-nologin-/) end end end - describe '#tcp_check' do + describe "#tcp_check" do before(:each) do allow_any_instance_of(described_class).to receive(:wait_for_sshd) allow_any_instance_of(described_class).to receive(:sleep) end - context 'the default non-skipping behavior' do + context "the default non-skipping behavior" do it "uses Kitchen's own SSH check" do expect(driver).to receive(:wait_for_sshd) expect(driver).to_not receive(:sleep) @@ -636,10 +630,10 @@ end end - context 'a config set to wait instead of TCP check' do + context "a config set to wait instead of TCP check" do let(:config) { { no_ssh_tcp_check: true } } - it 'uses a sleep instead of a port check' do + it "uses a sleep instead of a port check" do expect(driver).to_not receive(:wait_for_sshd) expect(driver).to receive(:sleep) driver.send(:tcp_check, state) @@ -647,22 +641,22 @@ end end - describe '#networks' do - context 'the default Rackspace networks' do - it 'returns nil so Fog will use the defaults' do + describe "#networks" do + context "the default Rackspace networks" do + it "returns nil so Fog will use the defaults" do expect(driver.send(:networks)).to eq(nil) end end - context 'a custom Rackspace network' do - let(:config) { { networks: %w[abcdefg] } } + context "a custom Rackspace network" do + let(:config) { { networks: %w{abcdefg} } } - it 'returns the base networks plus the custom one' do - expected = %w[ + it "returns the base networks plus the custom one" do + expected = %w{ 00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111 abcdefg - ] + } expect(driver.send(:networks)).to eq(expected) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2b470eb..4feada5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,16 +1,12 @@ -require 'rspec' -require 'simplecov' -require 'simplecov-console' -require 'coveralls' +require "rake" +require "rspec" +require "logger" +require "stringio" unless defined?(StringIO) +require "kitchen" -SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new( - [ - Coveralls::SimpleCov::Formatter, - SimpleCov::Formatter::HTMLFormatter, - SimpleCov::Formatter::Console - ] -) -SimpleCov.minimum_coverage(90) -SimpleCov.start do - add_filter '/vendor/' +require_relative "../lib/kitchen/driver/rackspace" +RSpec.configure do |config| + config.run_all_when_everything_filtered = true + config.filter_run(:focus) + config.order = "random" end