Compare commits

..

No commits in common. "main" and "v1.3.0" have entirely different histories.
main ... v1.3.0

42 changed files with 662 additions and 1627 deletions

1
.coveralls.yml Normal file
View file

@ -0,0 +1 @@
service_name: travis-pro

View file

@ -3,7 +3,10 @@
**/*.md **/*.md
**/*example **/*example
**/Dockerfile* **/Dockerfile*
Gemfile.lock
Rakefile
coverage coverage
spec
examples examples
scripts scripts
vendor vendor

View file

@ -15,3 +15,8 @@ FIXME
- [ ] Tests - [ ] Tests
- [ ] Documentation - [ ] Documentation
## Reviewers
@puppetlabs/dio
@highb
@briancain

View file

@ -3,17 +3,6 @@ updates:
- package-ecosystem: bundler - package-ecosystem: bundler
directory: "/" directory: "/"
schedule: schedule:
interval: weekly interval: daily
open-pull-requests-limit: 10 time: "13:00"
- package-ecosystem: docker
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10 open-pull-requests-limit: 10

View file

@ -1,12 +0,0 @@
name: Automated release prep
on:
workflow_dispatch:
jobs:
auto_release_prep:
uses: puppetlabs/release-engineering-repo-standards/.github/workflows/auto_release_prep.yml@v1
secrets: inherit
with:
project-type: ruby
version-file-path: lib/vmfloaty/version.rb

View file

@ -1,8 +0,0 @@
name: Dependabot auto-merge
on: pull_request
jobs:
dependabot_merge:
uses: puppetlabs/release-engineering-repo-standards/.github/workflows/dependabot_merge.yml@v1
secrets: inherit

View file

@ -1,8 +0,0 @@
name: Ensure label
on: pull_request
jobs:
ensure_label:
uses: puppetlabs/release-engineering-repo-standards/.github/workflows/ensure_label.yml@v1
secrets: inherit

29
.github/workflows/gempush.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Ruby Gem
on:
push:
tags:
- 'v*.*.*'
jobs:
build:
name: Build + Publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
version: 2.6.x
- name: Publish to RubyGems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build *.gemspec
gem push *.gem
env:
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}

View file

@ -1,118 +0,0 @@
name: Tag Release & Push Gem & Docker
on: workflow_dispatch
permissions:
contents: write
issues: read
pull-requests: read
packages: write
jobs:
release:
name: Validate Docs, Tag, and Docker Push
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
clean: true
fetch-depth: 0
- name: Get New Version
id: nv
run: |
version=$(grep VERSION lib/vmfloaty/version.rb |rev |cut -d "'" -f2 |rev)
echo "version=$version" >> $GITHUB_OUTPUT
echo "Found version $version from lib/vmfloaty/version.rb"
- name: Get Current Version
uses: actions/github-script@v7
id: cv
with:
script: |
const { data: response } = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo,
})
console.log(`The latest release is ${response.tag_name}`)
return response.tag_name
result-encoding: string
- name: Generate Changelog
uses: docker://githubchangeloggenerator/github-changelog-generator:1.16.2
with:
args: >-
--future-release ${{ steps.nv.outputs.version }}
env:
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Validate Changelog
run : |
set -e
if output=$(git status --porcelain) && [ ! -z "$output" ]; then
echo "Here is the current git status:"
git status
echo
echo "The following changes were detected:"
git --no-pager diff
echo "Uncommitted PRs found in the changelog. Please submit a release prep PR of changes after running './release-prep ${{ steps.nv.outputs.version }}'"
exit 1
fi
- name: Generate Release Notes
uses: docker://githubchangeloggenerator/github-changelog-generator:1.16.2
with:
args: >-
--since-tag ${{ steps.cv.outputs.result }}
--future-release ${{ steps.nv.outputs.version }}
--output release-notes.md
env:
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Tag Release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.nv.outputs.version }}
token: ${{ secrets.GITHUB_TOKEN }}
bodyfile: release-notes.md
draft: false
prerelease: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.nv.outputs.version }}
ghcr.io/${{ github.repository }}:latest
- name: Set up Ruby 3.2
uses: actions/setup-ruby@v1
with:
version: 3.2.x
- name: Build gem
run: gem build *.gemspec
- name: Publish gem
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem push *.gem
env:
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}

View file

@ -1,39 +0,0 @@
name: Security
on:
workflow_dispatch:
push:
branches:
- main
jobs:
scan:
name: Mend Scanning
runs-on: ubuntu-latest
steps:
- name: checkout repo content
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
# setup a package lock if one doesn't exist, otherwise do nothing
- name: check lock
run: '[ -f "Gemfile.lock" ] && echo "package lock file exists, skipping" || bundle lock'
# install java
- uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
# download mend
- name: download_mend
run: curl -o wss-unified-agent.jar https://unified-agent.s3.amazonaws.com/wss-unified-agent.jar
- name: run mend
run: java -jar wss-unified-agent.jar
env:
WS_APIKEY: ${{ secrets.MEND_API_KEY }}
WS_WSS_URL: https://saas-eu.whitesourcesoftware.com/agent
WS_USERKEY: ${{ secrets.MEND_TOKEN }}
WS_PRODUCTNAME: RE
WS_PROJECTNAME: ${{ github.event.repository.name }}

View file

@ -1,54 +0,0 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
name: Test
on:
pull_request:
branches:
- main
jobs:
spec:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version:
- '2.7'
- '3.0'
- '3.1'
- '3.2'
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
# change this to (see https://github.com/ruby/setup-ruby#versioning):
# uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Run tests
run: bundle exec rake spec
- name: Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: run-${{ matrix.ruby-version }}
parallel: true
finish:
needs: spec
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true

View file

@ -1,3 +0,0 @@
project=vmfloaty
user=puppetlabs
exclude_labels=maintenance

3
.gitignore vendored
View file

@ -25,10 +25,9 @@ build/
/vendor/ /vendor/
/lib/bundler/man/ /lib/bundler/man/
.dccache
# for a library or gem, you might want to ignore these files since the code is # for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in: # intended to run in multiple environments; otherwise, check them in:
Gemfile.lock
.ruby-version .ruby-version
.ruby-gemset .ruby-gemset

7
.travis.yml Normal file
View file

@ -0,0 +1,7 @@
language: ruby
dist: xenial
os:
- linux
rvm:
- 2.6.5
script: bundle exec rake spec

View file

@ -1,340 +0,0 @@
# Changelog
## [1.8.1](https://github.com/puppetlabs/vmfloaty/tree/1.8.1) (2023-08-07)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/1.8.0...1.8.1)
**Fixed bugs:**
- status and summary broken for pooler service after v3 [\#185](https://github.com/puppetlabs/vmfloaty/issues/185)
- \(RE-15687\) Use relative path for pooler status and summary [\#186](https://github.com/puppetlabs/vmfloaty/pull/186) ([yachub](https://github.com/yachub))
**Merged pull requests:**
- Bump rubocop from 1.54.2 to 1.55.1 [\#183](https://github.com/puppetlabs/vmfloaty/pull/183) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump rubocop from 1.52.0 to 1.54.2 [\#182](https://github.com/puppetlabs/vmfloaty/pull/182) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump rubocop from 1.51.0 to 1.52.0 [\#177](https://github.com/puppetlabs/vmfloaty/pull/177) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump rubocop from 1.50.2 to 1.51.0 [\#176](https://github.com/puppetlabs/vmfloaty/pull/176) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump rubocop from 1.49.0 to 1.50.2 [\#174](https://github.com/puppetlabs/vmfloaty/pull/174) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump rubocop from 1.48.1 to 1.49.0 [\#173](https://github.com/puppetlabs/vmfloaty/pull/173) ([dependabot[bot]](https://github.com/apps/dependabot))
- Update simplecov requirement from ~\> 0.21.2 to ~\> 0.22.0 [\#167](https://github.com/puppetlabs/vmfloaty/pull/167) ([dependabot[bot]](https://github.com/apps/dependabot))
- Update rspec requirement from ~\> 3.11.0 to ~\> 3.12.0 [\#166](https://github.com/puppetlabs/vmfloaty/pull/166) ([dependabot[bot]](https://github.com/apps/dependabot))
## [1.8.0](https://github.com/puppetlabs/vmfloaty/tree/1.8.0) (2023-03-21)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/1.7.0...1.8.0)
**Implemented enhancements:**
- Docker, Actions, and Docs Updates [\#170](https://github.com/puppetlabs/vmfloaty/pull/170) ([yachub](https://github.com/yachub))
**Fixed bugs:**
- Fix `floaty list --active` for vmpooler api v2 [\#169](https://github.com/puppetlabs/vmfloaty/pull/169) ([yachub](https://github.com/yachub))
**Merged pull requests:**
- \(RE-15111\) Migrate Synk to Mend [\#168](https://github.com/puppetlabs/vmfloaty/pull/168) ([yachub](https://github.com/yachub))
- \(RE-14811\) Move codeowners from DIO to RE [\#165](https://github.com/puppetlabs/vmfloaty/pull/165) ([yachub](https://github.com/yachub))
- Add Snyk action and Move to RE org [\#164](https://github.com/puppetlabs/vmfloaty/pull/164) ([yachub](https://github.com/yachub))
- Add release-engineering to codeowners [\#163](https://github.com/puppetlabs/vmfloaty/pull/163) ([yachub](https://github.com/yachub))
## [1.7.0](https://github.com/puppetlabs/vmfloaty/tree/1.7.0) (2022-04-05)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.6.0...1.7.0)
**Implemented enhancements:**
- \(maint\) Add Ruby 3.1 to test matrix + dockerfile and drop EOL Ruby 2.6 [\#159](https://github.com/puppetlabs/vmfloaty/pull/159) ([yachub](https://github.com/yachub))
- \(DIO-3101\) Add VMPooler API v2 Support [\#158](https://github.com/puppetlabs/vmfloaty/pull/158) ([yachub](https://github.com/yachub))
**Fixed bugs:**
- \(maint\) Remove colorize usage from `floaty status` [\#160](https://github.com/puppetlabs/vmfloaty/pull/160) ([yachub](https://github.com/yachub))
**Merged pull requests:**
- v1.7.0 release prep [\#162](https://github.com/puppetlabs/vmfloaty/pull/162) ([yachub](https://github.com/yachub))
- \(maint\) removing previous maintainers [\#157](https://github.com/puppetlabs/vmfloaty/pull/157) ([binford2k](https://github.com/binford2k))
- Update rspec requirement from ~\> 3.10.0 to ~\> 3.11.0 [\#155](https://github.com/puppetlabs/vmfloaty/pull/155) ([dependabot[bot]](https://github.com/apps/dependabot))
- Docs on contributing and releasing [\#152](https://github.com/puppetlabs/vmfloaty/pull/152) ([genebean](https://github.com/genebean))
## [v1.6.0](https://github.com/puppetlabs/vmfloaty/tree/v1.6.0) (2022-02-16)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.5.0...v1.6.0)
**Merged pull requests:**
- \(DIO-2700\) Vmfloaty should not use the Colorize gem [\#156](https://github.com/puppetlabs/vmfloaty/pull/156) ([sbeaulie](https://github.com/sbeaulie))
- \(maint\) Fix up nspooler list active bug [\#154](https://github.com/puppetlabs/vmfloaty/pull/154) ([cthorn42](https://github.com/cthorn42))
- Minor cleanup to the readme [\#151](https://github.com/puppetlabs/vmfloaty/pull/151) ([genebean](https://github.com/genebean))
- Release prep for 1.5.0 [\#150](https://github.com/puppetlabs/vmfloaty/pull/150) ([genebean](https://github.com/genebean))
## [v1.5.0](https://github.com/puppetlabs/vmfloaty/tree/v1.5.0) (2021-10-12)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.4.0...v1.5.0)
**Merged pull requests:**
- DIO 2412- Ondemand and Priority flag added to SSH command [\#149](https://github.com/puppetlabs/vmfloaty/pull/149) ([tanisha-payne](https://github.com/tanisha-payne))
- \(DIO-2135\) Update docker FROM image to ruby 3.0.2 [\#148](https://github.com/puppetlabs/vmfloaty/pull/148) ([sbeaulie](https://github.com/sbeaulie))
- Migrate CI to GitHub Actions [\#147](https://github.com/puppetlabs/vmfloaty/pull/147) ([genebean](https://github.com/genebean))
- v1.4.0 release prep [\#146](https://github.com/puppetlabs/vmfloaty/pull/146) ([genebean](https://github.com/genebean))
## [v1.4.0](https://github.com/puppetlabs/vmfloaty/tree/v1.4.0) (2021-07-16)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.3.0...v1.4.0)
**Merged pull requests:**
- \(maint\) Use latest Faraday/webmock, update specs [\#145](https://github.com/puppetlabs/vmfloaty/pull/145) ([nmburgan](https://github.com/nmburgan))
- Update commander requirement from \>= 4.4.3, \< 4.6.0 to \>= 4.4.3, \< 4.7.0 [\#140](https://github.com/puppetlabs/vmfloaty/pull/140) ([dependabot[bot]](https://github.com/apps/dependabot))
- Release prep for v1.3.0 [\#137](https://github.com/puppetlabs/vmfloaty/pull/137) ([sbeaulie](https://github.com/sbeaulie))
- Run the rubocop auto\_correct [\#135](https://github.com/puppetlabs/vmfloaty/pull/135) ([sbeaulie](https://github.com/sbeaulie))
## [v1.3.0](https://github.com/puppetlabs/vmfloaty/tree/v1.3.0) (2021-03-03)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.2.0...v1.3.0)
**Merged pull requests:**
- \(DIO-1522\) Show the VM state \(running, destroyed\) and colorize in red… [\#134](https://github.com/puppetlabs/vmfloaty/pull/134) ([sbeaulie](https://github.com/sbeaulie))
- Release prep for 1.2.0 [\#132](https://github.com/puppetlabs/vmfloaty/pull/132) ([genebean](https://github.com/genebean))
- Update rubocop requirement from ~\> 0.52 to ~\> 1.6 [\#124](https://github.com/puppetlabs/vmfloaty/pull/124) ([dependabot[bot]](https://github.com/apps/dependabot))
## [v1.2.0](https://github.com/puppetlabs/vmfloaty/tree/v1.2.0) (2021-02-11)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.1.1...v1.2.0)
**Merged pull requests:**
- \(DIO-908\) Floaty can now report the status of ABS requests [\#131](https://github.com/puppetlabs/vmfloaty/pull/131) ([sbeaulie](https://github.com/sbeaulie))
- Update rspec requirement from ~\> 3.9.0 to ~\> 3.10.0 [\#116](https://github.com/puppetlabs/vmfloaty/pull/116) ([dependabot[bot]](https://github.com/apps/dependabot))
## [v1.1.1](https://github.com/puppetlabs/vmfloaty/tree/v1.1.1) (2020-10-16)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.1.0...v1.1.1)
**Merged pull requests:**
- V1.1.1 [\#112](https://github.com/puppetlabs/vmfloaty/pull/112) ([sbeaulie](https://github.com/sbeaulie))
## [v1.1.0](https://github.com/puppetlabs/vmfloaty/tree/v1.1.0) (2020-10-09)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v1.0.0...v1.1.0)
**Merged pull requests:**
- \(maint\) Add more uniqueness to jobid and useful termination message [\#107](https://github.com/puppetlabs/vmfloaty/pull/107) ([sbeaulie](https://github.com/sbeaulie))
- \(maint\) Fix bug with detecting ABS service [\#106](https://github.com/puppetlabs/vmfloaty/pull/106) ([sbeaulie](https://github.com/sbeaulie))
- \(maint\) Don't require config file for list --active [\#105](https://github.com/puppetlabs/vmfloaty/pull/105) ([sbeaulie](https://github.com/sbeaulie))
- \(maint\) Don't require configuration file for get [\#104](https://github.com/puppetlabs/vmfloaty/pull/104) ([nwolfe](https://github.com/nwolfe))
- \(maint\) Add vmpooler\_fallback to the get service check [\#103](https://github.com/puppetlabs/vmfloaty/pull/103) ([cthorn42](https://github.com/cthorn42))
- Update completion scripts for `service` subcommands [\#102](https://github.com/puppetlabs/vmfloaty/pull/102) ([scotje](https://github.com/scotje))
- Bump to version 1.0.0 [\#100](https://github.com/puppetlabs/vmfloaty/pull/100) ([genebean](https://github.com/genebean))
## [v1.0.0](https://github.com/puppetlabs/vmfloaty/tree/v1.0.0) (2020-09-22)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/0.11.1...v1.0.0)
**Merged pull requests:**
- \(maint\) Fix for ABS PR\#306 that includes json responses [\#99](https://github.com/puppetlabs/vmfloaty/pull/99) ([sbeaulie](https://github.com/sbeaulie))
- \(maint\) Support any vmpooler for ABS via vmpooler\_fallback [\#98](https://github.com/puppetlabs/vmfloaty/pull/98) ([sbeaulie](https://github.com/sbeaulie))
- \(DIO-991\) Add service command [\#97](https://github.com/puppetlabs/vmfloaty/pull/97) ([genebean](https://github.com/genebean))
- \( DIO-911\) Include job\_id in ABS --json output [\#96](https://github.com/puppetlabs/vmfloaty/pull/96) ([sbeaulie](https://github.com/sbeaulie))
- ABS enables fallback to vmpooler for some scenarios [\#94](https://github.com/puppetlabs/vmfloaty/pull/94) ([sbeaulie](https://github.com/sbeaulie))
- WIP \(DIO-911\) Include job\_id in ABS --json output [\#92](https://github.com/puppetlabs/vmfloaty/pull/92) ([nwolfe](https://github.com/nwolfe))
- \(maint\) Remove warning about missing configuration file [\#91](https://github.com/puppetlabs/vmfloaty/pull/91) ([nwolfe](https://github.com/nwolfe))
- Add tab completion script for zsh and fix bash completion for ABS services [\#90](https://github.com/puppetlabs/vmfloaty/pull/90) ([scotje](https://github.com/scotje))
## [0.11.1](https://github.com/puppetlabs/vmfloaty/tree/0.11.1) (2020-08-20)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/0.10.0...0.11.1)
**Merged pull requests:**
- Update version for 0.11.1 release [\#89](https://github.com/puppetlabs/vmfloaty/pull/89) ([mattkirby](https://github.com/mattkirby))
- \(maint\) Fix using ABS service without a .vmfloaty.yml file [\#88](https://github.com/puppetlabs/vmfloaty/pull/88) ([cthorn42](https://github.com/cthorn42))
- Fix the argument list for nonstandardpooler [\#87](https://github.com/puppetlabs/vmfloaty/pull/87) ([jarretlavallee](https://github.com/jarretlavallee))
- Json output for delete/list + better ABS error handling [\#86](https://github.com/puppetlabs/vmfloaty/pull/86) ([mcdonaldseanp](https://github.com/mcdonaldseanp))
- Bump version for 0.11.0 release [\#85](https://github.com/puppetlabs/vmfloaty/pull/85) ([mattkirby](https://github.com/mattkirby))
- Print all non-success output to STDERR [\#84](https://github.com/puppetlabs/vmfloaty/pull/84) ([austb](https://github.com/austb))
- Update travis.yml [\#83](https://github.com/puppetlabs/vmfloaty/pull/83) ([rooneyshuman](https://github.com/rooneyshuman))
- Bump version to 0.10.0 for release [\#82](https://github.com/puppetlabs/vmfloaty/pull/82) ([mattkirby](https://github.com/mattkirby))
## [0.10.0](https://github.com/puppetlabs/vmfloaty/tree/0.10.0) (2020-08-04)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.9.2-retag-for-gh-actions-for-real...0.10.0)
**Merged pull requests:**
- Update Dependabot config file [\#78](https://github.com/puppetlabs/vmfloaty/pull/78) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Update rspec requirement from ~\> 3.5.0 to ~\> 3.9.0 [\#75](https://github.com/puppetlabs/vmfloaty/pull/75) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Update commander requirement from ~\> 4.4.3 to \>= 4.4.3, \< 4.6.0 [\#73](https://github.com/puppetlabs/vmfloaty/pull/73) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Fix formatting of CODEOWNERS [\#71](https://github.com/puppetlabs/vmfloaty/pull/71) ([genebean](https://github.com/genebean))
- Add Dependabot and Coveralls [\#70](https://github.com/puppetlabs/vmfloaty/pull/70) ([genebean](https://github.com/genebean))
- Update docs [\#69](https://github.com/puppetlabs/vmfloaty/pull/69) ([genebean](https://github.com/genebean))
- Remove old maintainer note [\#68](https://github.com/puppetlabs/vmfloaty/pull/68) ([briancain](https://github.com/briancain))
- Add support for vmpooler on demand provisioning [\#67](https://github.com/puppetlabs/vmfloaty/pull/67) ([mattkirby](https://github.com/mattkirby))
## [v0.9.2-retag-for-gh-actions-for-real](https://github.com/puppetlabs/vmfloaty/tree/v0.9.2-retag-for-gh-actions-for-real) (2020-02-05)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.9.2...v0.9.2-retag-for-gh-actions-for-real)
**Merged pull requests:**
- Update gempush action to remove GPR publish [\#66](https://github.com/puppetlabs/vmfloaty/pull/66) ([highb](https://github.com/highb))
## [v0.9.2](https://github.com/puppetlabs/vmfloaty/tree/v0.9.2) (2020-02-05)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.9.2-retag-for-gh-actions...v0.9.2)
## [v0.9.2-retag-for-gh-actions](https://github.com/puppetlabs/vmfloaty/tree/v0.9.2-retag-for-gh-actions) (2020-02-05)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.9.0...v0.9.2-retag-for-gh-actions)
**Merged pull requests:**
- Bump version.rb to 0.9.2 for release [\#65](https://github.com/puppetlabs/vmfloaty/pull/65) ([highb](https://github.com/highb))
- Create gempush.yml Github Action [\#64](https://github.com/puppetlabs/vmfloaty/pull/64) ([highb](https://github.com/highb))
- Bump faraday dependency for Ruby 2.7 compatibility [\#62](https://github.com/puppetlabs/vmfloaty/pull/62) ([nicklewis](https://github.com/nicklewis))
- SSH Command respects ABS now and tests should fail if the API changes… [\#61](https://github.com/puppetlabs/vmfloaty/pull/61) ([mikkergimenez](https://github.com/mikkergimenez))
- \(QENG-7604\) Add support for Job IDs to ABS delete [\#60](https://github.com/puppetlabs/vmfloaty/pull/60) ([highb](https://github.com/highb))
- Bump version.rb to 0.9.1 [\#59](https://github.com/puppetlabs/vmfloaty/pull/59) ([highb](https://github.com/highb))
- Fix error with delete command for vmpooler and nspooler [\#58](https://github.com/puppetlabs/vmfloaty/pull/58) ([mikkergimenez](https://github.com/mikkergimenez))
## [v0.9.0](https://github.com/puppetlabs/vmfloaty/tree/v0.9.0) (2019-12-17)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.8.2...v0.9.0)
**Implemented enhancements:**
- Add abs vm get [\#53](https://github.com/puppetlabs/vmfloaty/pull/53) ([mikkergimenez](https://github.com/mikkergimenez))
**Fixed bugs:**
- vmfloaty reports an error on latest API version output [\#48](https://github.com/puppetlabs/vmfloaty/issues/48)
**Merged pull requests:**
- ABS will sometimes return null values in the /status/queue endpoint [\#57](https://github.com/puppetlabs/vmfloaty/pull/57) ([mikkergimenez](https://github.com/mikkergimenez))
- Minor version bump to 0.9.0 [\#56](https://github.com/puppetlabs/vmfloaty/pull/56) ([highb](https://github.com/highb))
- Update pooler provider to throw an exception if the API returns non-OK [\#55](https://github.com/puppetlabs/vmfloaty/pull/55) ([highb](https://github.com/highb))
- Update Faraday to 0.15, remove unnecessary headers [\#54](https://github.com/puppetlabs/vmfloaty/pull/54) ([highb](https://github.com/highb))
- change urls in docs to use example.net/.com [\#50](https://github.com/puppetlabs/vmfloaty/pull/50) ([steveax](https://github.com/steveax))
- Rubocop cleanup [\#49](https://github.com/puppetlabs/vmfloaty/pull/49) ([rodjek](https://github.com/rodjek))
## [v0.8.2](https://github.com/puppetlabs/vmfloaty/tree/v0.8.2) (2018-01-05)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.8.1...v0.8.2)
**Merged pull requests:**
- 🎂🎂🎂 Add --json option for `floaty get` [\#47](https://github.com/puppetlabs/vmfloaty/pull/47) ([nicklewis](https://github.com/nicklewis))
## [v0.8.1](https://github.com/puppetlabs/vmfloaty/tree/v0.8.1) (2017-10-24)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.8.0...v0.8.1)
**Merged pull requests:**
- Bump commander version to clear up deprecation warnings [\#46](https://github.com/puppetlabs/vmfloaty/pull/46) ([highb](https://github.com/highb))
## [v0.8.0](https://github.com/puppetlabs/vmfloaty/tree/v0.8.0) (2017-10-13)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.7.9...v0.8.0)
**Closed issues:**
- don't automatically call system pager for help screens [\#20](https://github.com/puppetlabs/vmfloaty/issues/20)
**Merged pull requests:**
- Add configuration for multiple pooler services and integration with nspooler [\#45](https://github.com/puppetlabs/vmfloaty/pull/45) ([caseywilliams](https://github.com/caseywilliams))
## [v0.7.9](https://github.com/puppetlabs/vmfloaty/tree/v0.7.9) (2017-07-31)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.7.8...v0.7.9)
**Closed issues:**
- Handle when vmfloaty cannot reach vmpooler [\#39](https://github.com/puppetlabs/vmfloaty/issues/39)
**Merged pull requests:**
- Add basic bash completion script and framework for others [\#44](https://github.com/puppetlabs/vmfloaty/pull/44) ([scotje](https://github.com/scotje))
- Developersdevelopersdevelopers [\#43](https://github.com/puppetlabs/vmfloaty/pull/43) ([mckern](https://github.com/mckern))
## [v0.7.8](https://github.com/puppetlabs/vmfloaty/tree/v0.7.8) (2016-12-20)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.7.7...v0.7.8)
## [v0.7.7](https://github.com/puppetlabs/vmfloaty/tree/v0.7.7) (2016-12-14)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.7.6...v0.7.7)
## [v0.7.6](https://github.com/puppetlabs/vmfloaty/tree/v0.7.6) (2016-12-09)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/v0.7.5...v0.7.6)
**Closed issues:**
- Improve the help text for floaty commands [\#41](https://github.com/puppetlabs/vmfloaty/issues/41)
- Require force flag for pool requests larger than 5? [\#40](https://github.com/puppetlabs/vmfloaty/issues/40)
## [v0.7.5](https://github.com/puppetlabs/vmfloaty/tree/v0.7.5) (2016-12-06)
[Full Changelog](https://github.com/puppetlabs/vmfloaty/compare/1f86113243eb2e898b21c29892c05477e3487d2d...v0.7.5)
**Implemented enhancements:**
- Improve how to specify number of vms in get request [\#8](https://github.com/puppetlabs/vmfloaty/issues/8)
- Improve output from commands [\#3](https://github.com/puppetlabs/vmfloaty/issues/3)
**Fixed bugs:**
- floaty snapshot fails to authenticate [\#4](https://github.com/puppetlabs/vmfloaty/issues/4)
**Closed issues:**
- floaty snapshot should warn users about how long it takes to get snapshot [\#37](https://github.com/puppetlabs/vmfloaty/issues/37)
- floaty modify should allow to make changes on more than one machine [\#36](https://github.com/puppetlabs/vmfloaty/issues/36)
- Pooler.modify raises exception if Token is nil [\#34](https://github.com/puppetlabs/vmfloaty/issues/34)
- Improve error handling in Pooler and Auth classes [\#33](https://github.com/puppetlabs/vmfloaty/issues/33)
- Handle vmpooler responses when token is invalid in Pooler class [\#32](https://github.com/puppetlabs/vmfloaty/issues/32)
- Misuse of 'floaty revert ...' seems to create a new snapshot [\#31](https://github.com/puppetlabs/vmfloaty/issues/31)
- Test [\#30](https://github.com/puppetlabs/vmfloaty/issues/30)
- Don't system exit in Auth class [\#29](https://github.com/puppetlabs/vmfloaty/issues/29)
- Add flag to auto-ssh into a newly created \(single\) VM [\#28](https://github.com/puppetlabs/vmfloaty/issues/28)
- Handle vmpooler URL key that doesn't have 'https' [\#27](https://github.com/puppetlabs/vmfloaty/issues/27)
- Abstract vmfloaty cli related errors to command class rather than pooler class [\#26](https://github.com/puppetlabs/vmfloaty/issues/26)
- Don't puts results in `delete` method in Pooler library [\#25](https://github.com/puppetlabs/vmfloaty/issues/25)
- Improve `get` output [\#24](https://github.com/puppetlabs/vmfloaty/issues/24)
- specs don't work [\#22](https://github.com/puppetlabs/vmfloaty/issues/22)
- Add ability to get additional disk space for a running vm [\#19](https://github.com/puppetlabs/vmfloaty/issues/19)
- Have a force option for `delete --all` [\#17](https://github.com/puppetlabs/vmfloaty/issues/17)
- Stop printing json response in library methods [\#14](https://github.com/puppetlabs/vmfloaty/issues/14)
- Stop system exiting in library methods [\#13](https://github.com/puppetlabs/vmfloaty/issues/13)
- List active vms for a given token [\#12](https://github.com/puppetlabs/vmfloaty/issues/12)
- Provide a way to clean up vms obtained by a token [\#11](https://github.com/puppetlabs/vmfloaty/issues/11)
- Allow spaces when passing in vms for commands [\#10](https://github.com/puppetlabs/vmfloaty/issues/10)
- Write Tests for Pooler class [\#9](https://github.com/puppetlabs/vmfloaty/issues/9)
- Document all valid config file keys [\#7](https://github.com/puppetlabs/vmfloaty/issues/7)
- Write up simple "introduction" to using the tool [\#6](https://github.com/puppetlabs/vmfloaty/issues/6)
- Document how to use Pooler class for ruby scripts [\#5](https://github.com/puppetlabs/vmfloaty/issues/5)
- Convert vmfloaty to use latest pooler API [\#1](https://github.com/puppetlabs/vmfloaty/issues/1)
**Merged pull requests:**
- Show the status of pools with `floaty status` [\#38](https://github.com/puppetlabs/vmfloaty/pull/38) ([nicklewis](https://github.com/nicklewis))
- Show tag values in `list --active` [\#23](https://github.com/puppetlabs/vmfloaty/pull/23) ([justinstoller](https://github.com/justinstoller))
- \(\#19\) Update vmfloaty to expect /api/v1 in URL for disk endpoint [\#21](https://github.com/puppetlabs/vmfloaty/pull/21) ([briancain](https://github.com/briancain))
- \(\#17\) Add a force option for delete --all [\#18](https://github.com/puppetlabs/vmfloaty/pull/18) ([briancain](https://github.com/briancain))
- \(\#12\) List active vms for a given token [\#16](https://github.com/puppetlabs/vmfloaty/pull/16) ([briancain](https://github.com/briancain))
- Cleanup vmfloaty library and command processor [\#15](https://github.com/puppetlabs/vmfloaty/pull/15) ([briancain](https://github.com/briancain))
- \(\#1\) Update with commander [\#2](https://github.com/puppetlabs/vmfloaty/pull/2) ([briancain](https://github.com/briancain))
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*

View file

@ -1,3 +1,3 @@
# Set the default code owners # Set the default code owners
* @puppetlabs/release-engineering * @puppetlabs/dio @briancain @highb

View file

@ -1,23 +1,6 @@
FROM ruby:3.3.5-slim-bullseye FROM ruby:2.7
LABEL org.opencontainers.image.authors="@puppetlabs/release-engineering" COPY ./ ./
LABEL org.opencontainers.image.title="vmfloaty"
LABEL org.opencontainers.image.source=https://github.com/puppetlabs/vmfloaty
LABEL org.opencontainers.image.description="A CLI helper tool for VMPooler"
RUN apt-get update -qq && apt-get install -y build-essential less make openssh-client RUN apt-get update && apt-get install -y less
RUN gem install bundler && bundle install && gem build vmfloaty.gemspec && gem install vmfloaty*.gem
RUN groupadd --gid 1000 floatygroup \
&& useradd --uid 1000 --gid 1000 -m floatyuser
USER floatyuser
WORKDIR /home/floatyuser/app
COPY --chown=floatyuser:floatygroup . .
RUN gem install bundler \
&& bundle install \
&& gem build vmfloaty.gemspec \
&& gem install vmfloaty*.gem
ENTRYPOINT [ "floaty" ]

12
Gemfile
View file

@ -4,15 +4,13 @@ source 'https://rubygems.org'
gemspec gemspec
gem 'rake', require: false gem 'rake', :require => false
group :test do group :test do
gem 'simplecov', '~> 0.22.0' gem 'coveralls', '~> 0.8.23'
gem 'simplecov-html', '~> 0.13.1'
gem 'simplecov-lcov', '~> 0.8.0'
gem 'pry' gem 'pry'
gem 'rb-readline' gem 'rb-readline'
gem 'rspec', '~> 3.13.0' gem 'rspec', '~> 3.10.0'
gem 'rubocop', '~> 1.66' gem 'rubocop', '~> 1.6'
gem 'webmock', '~> 3.23' gem 'webmock', '1.21.0'
end end

View file

@ -1,125 +0,0 @@
PATH
remote: .
specs:
vmfloaty (1.8.1)
commander (>= 4.4.3, < 4.7.0)
faraday (~> 1.5, >= 1.5.1)
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
bigdecimal (3.1.8)
coderay (1.1.3)
commander (4.6.0)
highline (~> 2.0.0)
crack (1.0.0)
bigdecimal
rexml
diff-lcs (1.5.1)
docile (1.4.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
hashdiff (1.1.0)
highline (2.0.3)
json (2.7.2)
language_server-protocol (3.17.0.3)
method_source (1.0.0)
multipart-post (2.3.0)
parallel (1.26.3)
parser (3.3.5.0)
ast (~> 2.4.1)
racc
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (5.0.5)
racc (1.8.1)
rainbow (3.1.1)
rake (13.2.1)
rb-readline (0.5.5)
regexp_parser (2.9.2)
rexml (3.3.6)
strscan
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.0)
rubocop (1.66.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.3)
parser (>= 3.3.1.0)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.1)
simplecov-lcov (0.8.0)
simplecov_json_formatter (0.1.4)
strscan (3.1.0)
unicode-display_width (2.5.0)
webmock (3.23.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
PLATFORMS
aarch64-linux
x86_64-linux
DEPENDENCIES
pry
rake
rb-readline
rspec (~> 3.13.0)
rubocop (~> 1.66)
simplecov (~> 0.22.0)
simplecov-html (~> 0.13.1)
simplecov-lcov (~> 0.8.0)
vmfloaty!
webmock (~> 3.23)
BUNDLED WITH
2.4.8

View file

@ -1,48 +1,36 @@
# vmfloaty # vmfloaty
[![Gem Version](https://badge.fury.io/rb/vmfloaty.svg)](https://badge.fury.io/rb/vmfloaty) [![Gem Version](https://badge.fury.io/rb/vmfloaty.svg)](https://badge.fury.io/rb/vmfloaty)
[![Test](https://github.com/puppetlabs/vmfloaty/actions/workflows/test.yml/badge.svg)](https://github.com/puppetlabs/vmfloaty/actions/workflows/test.yml) [![Build Status](https://travis-ci.com/puppetlabs/vmfloaty.svg?branch=master)](https://travis-ci.com/puppetlabs/vmfloaty)
[![Coverage Status](https://coveralls.io/repos/github/puppetlabs/vmfloaty/badge.svg?branch=master)](https://coveralls.io/github/puppetlabs/vmfloaty?branch=master)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=puppetlabs/vmfloaty)](https://dependabot.com)
A CLI helper tool for [Puppet's VMPooler](https://github.com/puppetlabs/vmpooler) to help you stay afloat. A CLI helper tool for [Puppet's vmpooler](https://github.com/puppetlabs/vmpooler) to help you stay afloat.
![float image](float.jpg) ![float image](float.jpg)
- [vmfloaty](#vmfloaty) - [Install](#install)
- [Install](#install) - [Usage](#usage)
- [Ruby](#ruby) - [Example workflow](#example-workflow)
- [Docker](#docker) - [vmfloaty dotfile](#vmfloaty-dotfile)
- [Usage](#usage) - [Basic configuration](#basic-configuration)
- [Example workflow](#example-workflow) - [Using multiple services](#using-multiple-services)
- [vmfloaty dotfile](#vmfloaty-dotfile) - [Using backends besides VMPooler](#using-backends-besides-vmpooler)
- [Basic configuration](#basic-configuration) - [Valid config keys](#valid-config-keys)
- [Using multiple services](#using-multiple-services) - [Tab Completion](#tab-completion)
- [Using backends besides VMPooler](#using-backends-besides-vmpooler) - [vmpooler API](#vmpooler-api)
- [Valid config keys](#valid-config-keys) - [Using the Pooler class](#using-the-pooler-class)
- [Tab Completion](#tab-completion) - [Example Projects](#example-projects)
- [VMPooler API](#vmpooler-api) - [Special thanks](#special-thanks)
- [Using the Pooler class](#using-the-pooler-class)
- [Example Projects](#example-projects)
- [Contributing](#contributing)
- [Code Reviews](#code-reviews)
- [Releasing](#releasing)
- [Special thanks](#special-thanks)
## Install ## Install
### Ruby
Grab the latest from ruby gems... Grab the latest from ruby gems...
```bash ```bash
gem install vmfloaty gem install vmfloaty
``` ```
### Docker
Run the docker image:
`docker run -it --rm -v ~/.vmfloaty.yml:/home/floatyuser/.vmfloaty.yml ghcr.io/puppetlabs/vmfloaty --help`
## Usage ## Usage
```plain ```plain
@ -53,7 +41,7 @@ $ floaty --help
DESCRIPTION: DESCRIPTION:
A CLI helper tool for Puppet's VMPooler to help you stay afloat A CLI helper tool for Puppet's vmpooler to help you stay afloat
COMMANDS: COMMANDS:
@ -163,13 +151,13 @@ There is also tab completion for zsh:
source $(floaty completion --shell zsh) source $(floaty completion --shell zsh)
``` ```
## VMPooler API ## vmpooler API
This cli tool uses the [VMPooler API](https://github.com/puppetlabs/vmpooler/blob/master/API.md). This cli tool uses the [vmpooler API](https://github.com/puppetlabs/vmpooler/blob/master/API.md).
## Using the Pooler class ## Using the Pooler class
vmfloaty providers a `Pooler` class that gives users the ability to make requests to VMPooler without having to write their own requests. It also provides an `Auth` class for managing VMPooler tokens within your application. vmfloaty providers a `Pooler` class that gives users the ability to make requests to vmpooler without having to write their own requests. It also provides an `Auth` class for managing vmpooler tokens within your application.
### Example Projects ### Example Projects
@ -178,23 +166,6 @@ vmfloaty providers a `Pooler` class that gives users the ability to make request
- [Brian Cain: vagrant-vmpooler](https://github.com/briancain/vagrant-vmpooler) - [Brian Cain: vagrant-vmpooler](https://github.com/briancain/vagrant-vmpooler)
- Use Vagrant to manage your vmpooler instances - Use Vagrant to manage your vmpooler instances
## Contributing
PR's are welcome! We always love to see how others think this tool can be made better.
### Code Reviews
Please wait for multiple code owners to sign off on any notable change.
## Releasing
Follow these steps to publish a new GitHub release, build and push the gem to <https://rubygems.org>, and build and push a Docker Image to GitHub Container Registry:
1. Bump the "VERSION" in `lib/vmfloaty/version.rb` appropriately based on changes in `CHANGELOG.md` since the last release.
2. Run `./release-prep` to update `Gemfile.lock` and `CHANGELOG.md`.
3. Commit and push changes to a new branch, then open a pull request against `main` and be sure to add the "maintenance" label.
4. After the pull request is approved and merged, then navigate to <https://github.com/puppetlabs/vmfloaty/actions/workflows/release.yml> --> Run workflow --> select "main" branch --> Run workflow. This will publish a GitHub release, build and push the gem to RubyGems, and build and push a Docker Image to GitHub Container Registry.
## Special thanks ## Special thanks
Special thanks to [Brian Cain](https://github.com/briancain) as he is the original author of vmfloaty! Vast amounts of this code exist thanks to his efforts. Special thanks to [Brian Cain](https://github.com/briancain) as he is the original author of vmfloaty! Vast amounts of this code exist thanks to his efforts.

View file

@ -28,4 +28,4 @@ RuboCop::RakeTask.new(:rubocop) do |task|
end end
# Default task is to run the unit tests # Default task is to run the unit tests
task default: :spec task :default => :spec

View file

@ -2,6 +2,7 @@
require 'rubygems' require 'rubygems'
require 'commander' require 'commander'
require 'colorize'
require 'json' require 'json'
require 'pp' require 'pp'
require 'uri' require 'uri'
@ -19,8 +20,7 @@ class Vmfloaty
def run # rubocop:disable Metrics/AbcSize def run # rubocop:disable Metrics/AbcSize
program :version, Vmfloaty::VERSION program :version, Vmfloaty::VERSION
program :description, program :description, "A CLI helper tool for Puppet's vmpooler to help you stay afloat.\n\nConfiguration may be placed in a ~/.vmfloaty.yml file."
"A CLI helper tool for Puppet's vmpooler to help you stay afloat.\n\nConfiguration may be placed in a ~/.vmfloaty.yml file."
config = Conf.read_config config = Conf.read_config
@ -43,7 +43,9 @@ class Vmfloaty
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)' c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
c.action do |args, options| c.action do |args, options|
verbose = options.verbose || config['verbose'] verbose = options.verbose || config['verbose']
FloatyLogger.setlevel = options.loglevel if options.loglevel if options.loglevel
FloatyLogger.setlevel = options.loglevel
end
service = Service.new(options, config) service = Service.new(options, config)
use_token = !options.notoken use_token = !options.notoken
force = options.force force = options.force
@ -98,19 +100,21 @@ class Vmfloaty
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)' c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
c.action do |args, options| c.action do |args, options|
verbose = options.verbose || config['verbose'] verbose = options.verbose || config['verbose']
FloatyLogger.setlevel = options.loglevel if options.loglevel if options.loglevel
FloatyLogger.setlevel = options.loglevel
end
service = Service.new(options, config) service = Service.new(options, config)
filter = args[0] filter = args[0]
if options.active if options.active
# list active vms # list active vms
running_vms = if service.type == 'ABS' if service.type == "ABS"
# this is actually job_ids # this is actually job_ids
service.list_active_job_ids(verbose, service.url, service.user) running_vms = service.list_active_job_ids(verbose, service.url, service.user)
else else
service.list_active(verbose) running_vms = service.list_active(verbose)
end end
host = URI.parse(service.url).host host = URI.parse(service.url).host
if running_vms.empty? if running_vms.empty?
if options.json if options.json
@ -118,15 +122,17 @@ class Vmfloaty
else else
FloatyLogger.info "You have no running VMs on #{host}" FloatyLogger.info "You have no running VMs on #{host}"
end end
elsif options.json
puts Utils.get_host_data(verbose, service, running_vms).to_json
elsif options.hostnameonly
Utils.get_host_data(verbose, service, running_vms).each do |hostname, host_data|
Utils.print_fqdn_for_host(service, hostname, host_data)
end
else else
puts "Your VMs on #{host}:" if options.json
Utils.pretty_print_hosts(verbose, service, running_vms) puts Utils.get_host_data(verbose, service, running_vms).to_json
elsif options.hostnameonly
Utils.get_host_data(verbose, service, running_vms).each do |hostname, host_data|
Utils.print_fqdn_for_host(service, hostname, host_data)
end
else
puts "Your VMs on #{host}:"
Utils.pretty_print_hosts(verbose, service, running_vms)
end
end end
else else
# list available vms from pooler # list available vms from pooler
@ -158,8 +164,7 @@ class Vmfloaty
c.syntax = 'floaty modify hostname [options]' c.syntax = 'floaty modify hostname [options]'
c.summary = 'Modify a VM\'s tags, time to live, disk space, or reservation reason' c.summary = 'Modify a VM\'s tags, time to live, disk space, or reservation reason'
c.description = 'This command makes modifications to the virtual machines state in the pooler service. You can either append tags to the vm, increase how long it stays active for, or increase the amount of disk space.' c.description = 'This command makes modifications to the virtual machines state in the pooler service. You can either append tags to the vm, increase how long it stays active for, or increase the amount of disk space.'
c.example 'Modifies myhost1 to have a TTL of 12 hours and adds a custom tag', c.example 'Modifies myhost1 to have a TTL of 12 hours and adds a custom tag', 'floaty modify myhost1 --lifetime 12 --url https://myurl --token mytokenstring --tags \'{"tag":"myvalue"}\''
'floaty modify myhost1 --lifetime 12 --url https://myurl --token mytokenstring --tags \'{"tag":"myvalue"}\''
c.option '--verbose', 'Enables verbose output' c.option '--verbose', 'Enables verbose output'
c.option '--service STRING', String, 'Configured pooler service name' c.option '--service STRING', String, 'Configured pooler service name'
c.option '--url STRING', String, 'URL of pooler service' c.option '--url STRING', String, 'URL of pooler service'
@ -180,18 +185,18 @@ class Vmfloaty
exit 1 exit 1
end end
running_vms = running_vms =
if modify_all if modify_all
service.list_active(verbose) service.list_active(verbose)
else else
hostname.split(',') hostname.split(',')
end end
tags = options.tags ? JSON.parse(options.tags) : nil tags = options.tags ? JSON.parse(options.tags) : nil
modify_hash = { modify_hash = {
lifetime: options.lifetime, :lifetime => options.lifetime,
disk: options.disk, :disk => options.disk,
tags: tags, :tags => tags,
reason: options.reason :reason => options.reason,
} }
modify_hash.delete_if { |_, value| value.nil? } modify_hash.delete_if { |_, value| value.nil? }
@ -199,10 +204,12 @@ class Vmfloaty
ok = true ok = true
modified_hash = {} modified_hash = {}
running_vms.each do |vm| running_vms.each do |vm|
modified_hash[vm] = service.modify(verbose, vm, modify_hash) begin
rescue ModifyError => e modified_hash[vm] = service.modify(verbose, vm, modify_hash)
FloatyLogger.error e rescue ModifyError => e
ok = false FloatyLogger.error e
ok = false
end
end end
if ok if ok
if modify_all if modify_all
@ -234,7 +241,9 @@ class Vmfloaty
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)' c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
c.action do |args, options| c.action do |args, options|
verbose = options.verbose || config['verbose'] verbose = options.verbose || config['verbose']
FloatyLogger.setlevel = options.loglevel if options.loglevel if options.loglevel
FloatyLogger.setlevel = options.loglevel
end
service = Service.new(options, config) service = Service.new(options, config)
hostnames = args[0] hostnames = args[0]
@ -245,17 +254,17 @@ class Vmfloaty
successes = [] successes = []
if delete_all if delete_all
running_vms = if service.type == 'ABS' if service.type == "ABS"
# this is actually job_ids # this is actually job_ids
service.list_active_job_ids(verbose, service.url, service.user) running_vms = service.list_active_job_ids(verbose, service.url, service.user)
else else
service.list_active(verbose) running_vms = service.list_active(verbose)
end end
if running_vms.empty? if running_vms.empty?
if options.json if options.json
puts {}.to_json puts {}.to_json
else else
FloatyLogger.info 'You have no running VMs.' FloatyLogger.info "You have no running VMs."
end end
else else
confirmed = true confirmed = true
@ -319,8 +328,7 @@ class Vmfloaty
c.syntax = 'floaty snapshot hostname [options]' c.syntax = 'floaty snapshot hostname [options]'
c.summary = 'Takes a snapshot of a given vm' c.summary = 'Takes a snapshot of a given vm'
c.description = 'Will request a snapshot be taken of the given hostname in the pooler service. This command is known to take a while depending on how much load is on the pooler service.' c.description = 'Will request a snapshot be taken of the given hostname in the pooler service. This command is known to take a while depending on how much load is on the pooler service.'
c.example 'Takes a snapshot for a given host', c.example 'Takes a snapshot for a given host', 'floaty snapshot myvm.example.com --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
'floaty snapshot myvm.example.com --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
c.option '--verbose', 'Enables verbose output' c.option '--verbose', 'Enables verbose output'
c.option '--service STRING', String, 'Configured pooler service name' c.option '--service STRING', String, 'Configured pooler service name'
c.option '--url STRING', String, 'URL of pooler service' c.option '--url STRING', String, 'URL of pooler service'
@ -346,8 +354,7 @@ class Vmfloaty
c.syntax = 'floaty revert hostname snapshot [options]' c.syntax = 'floaty revert hostname snapshot [options]'
c.summary = 'Reverts a vm to a specified snapshot' c.summary = 'Reverts a vm to a specified snapshot'
c.description = 'Given a snapshot SHA, vmfloaty will request a revert to the pooler service to go back to a previous snapshot.' c.description = 'Given a snapshot SHA, vmfloaty will request a revert to the pooler service to go back to a previous snapshot.'
c.example 'Reverts to a snapshot for a given host', c.example 'Reverts to a snapshot for a given host', 'floaty revert myvm.example.com n4eb4kdtp7rwv4x158366vd9jhac8btq --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
'floaty revert myvm.example.com n4eb4kdtp7rwv4x158366vd9jhac8btq --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
c.option '--verbose', 'Enables verbose output' c.option '--verbose', 'Enables verbose output'
c.option '--service STRING', String, 'Configured pooler service name' c.option '--service STRING', String, 'Configured pooler service name'
c.option '--url STRING', String, 'URL of pooler service' c.option '--url STRING', String, 'URL of pooler service'
@ -359,9 +366,7 @@ class Vmfloaty
hostname = args[0] hostname = args[0]
snapshot_sha = args[1] || options.snapshot snapshot_sha = args[1] || options.snapshot
if args[1] && options.snapshot FloatyLogger.info "Two snapshot arguments were given....using snapshot #{snapshot_sha}" if args[1] && options.snapshot
FloatyLogger.info "Two snapshot arguments were given....using snapshot #{snapshot_sha}"
end
begin begin
revert_req = service.revert(verbose, hostname, snapshot_sha) revert_req = service.revert(verbose, hostname, snapshot_sha)
@ -386,7 +391,9 @@ class Vmfloaty
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)' c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
c.action do |_, options| c.action do |_, options|
verbose = options.verbose || config['verbose'] verbose = options.verbose || config['verbose']
FloatyLogger.setlevel = options.loglevel if options.loglevel if options.loglevel
FloatyLogger.setlevel = options.loglevel
end
service = Service.new(options, config) service = Service.new(options, config)
if options.json if options.json
pp service.status(verbose) pp service.status(verbose)
@ -468,8 +475,6 @@ class Vmfloaty
c.option '--user STRING', String, 'User to authenticate with' c.option '--user STRING', String, 'User to authenticate with'
c.option '--token STRING', String, 'Token for pooler service' c.option '--token STRING', String, 'Token for pooler service'
c.option '--notoken', 'Makes a request without a token' c.option '--notoken', 'Makes a request without a token'
c.option '--priority STRING', 'Priority for supported backends(ABS) (High(1), Medium(2), Low(3))'
c.option '--ondemand', 'Requested vms are provisioned upon receival of the request, tracked by a request ID'
c.action do |args, options| c.action do |args, options|
verbose = options.verbose || config['verbose'] verbose = options.verbose || config['verbose']
service = Service.new(options, config) service = Service.new(options, config)
@ -484,7 +489,7 @@ class Vmfloaty
FloatyLogger.info "Can't ssh to multiple hosts; Using #{host_os} only..." if args.length > 1 FloatyLogger.info "Can't ssh to multiple hosts; Using #{host_os} only..." if args.length > 1
service.ssh(verbose, host_os, use_token, options.ondemand) service.ssh(verbose, host_os, use_token)
exit 0 exit 0
end end
end end
@ -522,7 +527,7 @@ class Vmfloaty
c.example 'Print a list of the valid service types', 'floaty service types' c.example 'Print a list of the valid service types', 'floaty service types'
c.example 'Print a sample config file with multiple services', 'floaty service examples' c.example 'Print a sample config file with multiple services', 'floaty service examples'
c.example 'list vms from the service named "nspooler-prod"', 'floaty list --service nspooler-prod' c.example 'list vms from the service named "nspooler-prod"', 'floaty list --service nspooler-prod'
c.action do |args, _options| c.action do |args, options|
action = args.first action = args.first
example_config = Utils.strip_heredoc(<<-CONFIG) example_config = Utils.strip_heredoc(<<-CONFIG)

View file

@ -53,10 +53,10 @@ class ABS
def self.list_active(verbose, url, _token, user) def self.list_active(verbose, url, _token, user)
hosts = [] hosts = []
get_active_requests(verbose, url, user).each do |req_hash| get_active_requests(verbose, url, user).each do |req_hash|
next unless req_hash.key?('allocated_resources') if req_hash.key?('allocated_resources')
req_hash['allocated_resources'].each do |onehost|
req_hash['allocated_resources'].each do |onehost| hosts.push(onehost['hostname'])
hosts.push(onehost['hostname']) end
end end
end end
@ -116,7 +116,7 @@ class ABS
ret_status = {} ret_status = {}
hosts.each do |host| hosts.each do |host|
ret_status[host] = { ret_status[host] = {
'ok' => false 'ok' => false,
} }
end end
@ -132,7 +132,7 @@ class ABS
if hosts.include? vm_name['hostname'] if hosts.include? vm_name['hostname']
if all_job_resources_accounted_for(req_hash['allocated_resources'], hosts) if all_job_resources_accounted_for(req_hash['allocated_resources'], hosts)
ret_status[vm_name['hostname']] = { ret_status[vm_name['hostname']] = {
'ok' => true 'ok' => true,
} }
jobs_to_delete.push(req_hash) jobs_to_delete.push(req_hash)
else else
@ -147,7 +147,7 @@ class ABS
jobs_to_delete.each do |job| jobs_to_delete.each do |job|
req_obj = { req_obj = {
'job_id' => job['request']['job']['id'], 'job_id' => job['request']['job']['id'],
'hosts' => job['allocated_resources'] 'hosts' => job['allocated_resources'],
} }
FloatyLogger.info "Deleting #{req_obj}" if verbose FloatyLogger.info "Deleting #{req_obj}" if verbose
@ -172,11 +172,11 @@ class ABS
res_body = JSON.parse(res.body) res_body = JSON.parse(res.body)
if res_body.key?('vmpooler_platforms') if res_body.key?('vmpooler_platforms')
os_list << '*** VMPOOLER Pools ***' os_list << '*** VMPOOLER Pools ***'
os_list += if res_body['vmpooler_platforms'].is_a?(String) if res_body['vmpooler_platforms'].is_a?(String)
JSON.parse(res_body['vmpooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306 os_list += JSON.parse(res_body['vmpooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
else else
res_body['vmpooler_platforms'] os_list += res_body['vmpooler_platforms']
end end
end end
end end
@ -200,11 +200,11 @@ class ABS
if res_body.key?('nspooler_platforms') if res_body.key?('nspooler_platforms')
os_list << '' os_list << ''
os_list << '*** NSPOOLER Pools ***' os_list << '*** NSPOOLER Pools ***'
os_list += if res_body['nspooler_platforms'].is_a?(String) if res_body['nspooler_platforms'].is_a?(String)
JSON.parse(res_body['nspooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306 os_list += JSON.parse(res_body['nspooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
else else
res_body['nspooler_platforms'] os_list += res_body['nspooler_platforms']
end end
end end
end end
@ -214,11 +214,11 @@ class ABS
if res_body.key?('aws_platforms') if res_body.key?('aws_platforms')
os_list << '' os_list << ''
os_list << '*** AWS Pools ***' os_list << '*** AWS Pools ***'
os_list += if res_body['aws_platforms'].is_a?(String) if res_body['aws_platforms'].is_a?(String)
JSON.parse(res_body['aws_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306 os_list += JSON.parse(res_body['aws_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
else else
res_body['aws_platforms'] os_list += res_body['aws_platforms']
end end
end end
end end
@ -248,20 +248,20 @@ class ABS
conn = Http.get_conn(verbose, supported_abs_url(url)) conn = Http.get_conn(verbose, supported_abs_url(url))
conn.headers['X-AUTH-TOKEN'] = token if token conn.headers['X-AUTH-TOKEN'] = token if token
saved_job_id = if continue.nil? if continue.nil?
"#{user}-#{DateTime.now.strftime('%Q')}" saved_job_id = user + "-" + DateTime.now.strftime('%Q')
else else
continue saved_job_id = continue
end end
req_obj = { req_obj = {
resources: os_types, :resources => os_types,
job: { :job => {
id: saved_job_id, :id => saved_job_id,
tags: { :tags => {
user: user :user => user,
} },
} },
} }
if config['vmpooler_fallback'] # optional and not available as cli flag if config['vmpooler_fallback'] # optional and not available as cli flag
@ -271,12 +271,11 @@ class ABS
end end
if config['priority'] if config['priority']
req_obj[:priority] = case config['priority'] req_obj[:priority] = if config['priority'] == 'high'
when 'high'
1 1
when 'medium' elsif config['priority'] == 'medium'
2 2
when 'low' elsif config['priority'] == 'low'
3 3
else else
config['priority'].to_i config['priority'].to_i
@ -292,12 +291,14 @@ class ABS
retries = 360 retries = 360
status = validate_queue_status_response(res.status, res.body, 'Initial request', verbose) status = validate_queue_status_response(res.status, res.body, "Initial request", verbose)
begin begin
(1..retries).each do |i| (1..retries).each do |i|
res_body = check_queue(conn, saved_job_id, req_obj, verbose) res_body = check_queue(conn, saved_job_id, req_obj, verbose)
return translated(res_body, saved_job_id) if res_body.is_a?(Array) # when we get a response with hostnames if res_body && res_body.is_a?(Array) # when we get a response with hostnames
return translated(res_body, saved_job_id)
end
sleep_seconds = 10 if i >= 10 sleep_seconds = 10 if i >= 10
sleep_seconds = i if i < 10 sleep_seconds = i if i < 10
@ -316,10 +317,10 @@ class ABS
# We should fix the ABS API to be more like the vmpooler or nspooler api, but for now # We should fix the ABS API to be more like the vmpooler or nspooler api, but for now
# #
def self.translated(res_body, job_id) def self.translated(res_body, job_id)
vmpooler_formatted_body = { 'job_id' => job_id } vmpooler_formatted_body = {'job_id' => job_id}
res_body.each do |host| res_body.each do |host|
if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].instance_of?(Array) if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].class == Array
vmpooler_formatted_body[host['type']]['hostname'] << host['hostname'] vmpooler_formatted_body[host['type']]['hostname'] << host['hostname']
else else
vmpooler_formatted_body[host['type']] = { 'hostname' => [host['hostname']] } vmpooler_formatted_body[host['type']] = { 'hostname' => [host['hostname']] }
@ -330,9 +331,9 @@ class ABS
vmpooler_formatted_body vmpooler_formatted_body
end end
def self.check_queue(conn, _job_id, req_obj, verbose) def self.check_queue(conn, job_id, req_obj, verbose)
res = conn.post 'request', req_obj.to_json res = conn.post 'request', req_obj.to_json
status = validate_queue_status_response(res.status, res.body, 'Check queue request', verbose) status = validate_queue_status_response(res.status, res.body, "Check queue request", verbose)
unless res.body.empty? || !valid_json?(res.body) unless res.body.empty? || !valid_json?(res.body)
res_body = JSON.parse(res.body) res_body = JSON.parse(res.body)
return res_body return res_body
@ -352,7 +353,7 @@ class ABS
res.body == 'OK' res.body == 'OK'
end end
def self.summary(_verbose, _url) def self.summary(verbose, url)
raise NoMethodError, 'summary is not defined for ABS' raise NoMethodError, 'summary is not defined for ABS'
end end
@ -404,17 +405,17 @@ class ABS
def self.valid_json?(json) def self.valid_json?(json)
JSON.parse(json) JSON.parse(json)
true return true
rescue TypeError, JSON::ParserError => e rescue TypeError, JSON::ParserError => e
false return false
end end
# when missing, adds the required api/v2 in the url # when missing, adds the required api/v2 in the url
def self.supported_abs_url(url) def self.supported_abs_url(url)
expected_ending = 'api/v2' expected_ending = "api/v2"
unless url.include?(expected_ending) if !url.include?(expected_ending)
# add a slash if missing # add a slash if missing
expected_ending = "/#{expected_ending}" if url[-1] != '/' expected_ending = "/#{expected_ending}" if url[-1] != "/"
url = "#{url}#{expected_ending}" url = "#{url}#{expected_ending}"
end end
url url

View file

@ -21,11 +21,13 @@ class Http
url = "https://#{url}" unless url?(url) url = "https://#{url}" unless url?(url)
Faraday.new(url: url, ssl: { verify: false }) do |faraday| conn = Faraday.new(:url => url, :ssl => { :verify => false }) do |faraday|
faraday.request :url_encoded faraday.request :url_encoded
faraday.response :logger if verbose faraday.response :logger if verbose
faraday.adapter Faraday.default_adapter faraday.adapter Faraday.default_adapter
end end
conn
end end
def self.get_conn_with_auth(verbose, url, user, password) def self.get_conn_with_auth(verbose, url, user, password)
@ -35,11 +37,13 @@ class Http
url = "https://#{url}" unless url?(url) url = "https://#{url}" unless url?(url)
Faraday.new(url: url, ssl: { verify: false }) do |faraday| conn = Faraday.new(:url => url, :ssl => { :verify => false }) do |faraday|
faraday.request :url_encoded faraday.request :url_encoded
faraday.request :basic_auth, user, password faraday.request :basic_auth, user, password
faraday.response :logger if verbose faraday.response :logger if verbose
faraday.adapter Faraday.default_adapter faraday.adapter Faraday.default_adapter
end end
conn
end end
end end

View file

@ -1,5 +1,3 @@
# frozen_string_literal: true
require 'logger' require 'logger'
class FloatyLogger < ::Logger class FloatyLogger < ::Logger
@ -21,23 +19,22 @@ class FloatyLogger < ::Logger
def self.setlevel=(level) def self.setlevel=(level)
level = level.downcase level = level.downcase
case level if level == "debug"
when 'debug' self.logger.level = ::Logger::DEBUG
logger.level = ::Logger::DEBUG elsif level == "info"
when 'info' self.logger.level = ::Logger::INFO
logger.level = ::Logger::INFO elsif level == "error"
when 'error' self.logger.level = ::Logger::ERROR
logger.level = ::Logger::ERROR
else else
error('set loglevel to debug, info or error') error("set loglevel to debug, info or error")
end end
end end
def initialize def initialize
super($stderr) super(STDERR)
self.level = ::Logger::INFO self.level = ::Logger::INFO
self.formatter = proc do |_severity, _datetime, _progname, msg| self.formatter = proc do |severity, datetime, progname, msg|
"#{msg}\n" "#{msg}\n"
end end
end end
end end

View file

@ -22,7 +22,7 @@ class NonstandardPooler
status['reserved_hosts'] || [] status['reserved_hosts'] || []
end end
def self.retrieve(verbose, os_type, token, url, _user, _options, _ondemand = nil, _continue = nil) def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil, _continue = nil)
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
conn.headers['X-AUTH-TOKEN'] = token if token conn.headers['X-AUTH-TOKEN'] = token if token
@ -46,8 +46,7 @@ class NonstandardPooler
raise TokenError, 'Token provided was nil; Request cannot be made to modify VM' if token.nil? raise TokenError, 'Token provided was nil; Request cannot be made to modify VM' if token.nil?
modify_hash.each do |key, _value| modify_hash.each do |key, _value|
raise ModifyError, "Configured service type does not support modification of #{key}" unless %i[reason raise ModifyError, "Configured service type does not support modification of #{key}" unless %i[reason reserved_for_reason].include? key
reserved_for_reason].include? key
end end
if modify_hash[:reason] if modify_hash[:reason]

View file

@ -12,11 +12,13 @@ class Pooler
response = conn.get 'vm' response = conn.get 'vm'
response_body = JSON.parse(response.body) response_body = JSON.parse(response.body)
if os_filter hosts = if os_filter
response_body.select { |i| i[/#{os_filter}/] } response_body.select { |i| i[/#{os_filter}/] }
else else
response_body response_body
end end
hosts
end end
def self.list_active(verbose, url, token, _user) def self.list_active(verbose, url, token, _user)
@ -48,10 +50,7 @@ class Pooler
elsif response.status == 403 elsif response.status == 403
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. Request exceeds the configured per pool maximum. #{res_body}" raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. Request exceeds the configured per pool maximum. #{res_body}"
else else
unless ondemand raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}" unless ondemand
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}"
end
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/ondemandvm/#{os_string}. #{res_body}" raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/ondemandvm/#{os_string}. #{res_body}"
end end
end end
@ -64,7 +63,7 @@ class Pooler
FloatyLogger.info "waiting for request #{request_id} to be fulfilled" FloatyLogger.info "waiting for request #{request_id} to be fulfilled"
sleep 5 sleep 5
end end
FloatyLogger.info 'The request has been fulfilled' FloatyLogger.info "The request has been fulfilled"
check_ondemandvm(verbose, request_id, url) check_ondemandvm(verbose, request_id, url)
end end
@ -85,9 +84,8 @@ class Pooler
def self.modify(verbose, url, hostname, token, modify_hash) def self.modify(verbose, url, hostname, token, modify_hash)
raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil? raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil?
modify_hash.each_key do |key| modify_hash.keys.each do |key|
raise ModifyError, "Configured service type does not support modification of #{key}." unless %i[tags lifetime raise ModifyError, "Configured service type does not support modification of #{key}." unless %i[tags lifetime disk].include? key
disk].include? key
end end
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
@ -122,7 +120,8 @@ class Pooler
response = conn.post "vm/#{hostname}/disk/#{disk}" response = conn.post "vm/#{hostname}/disk/#{disk}"
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
def self.delete(verbose, url, hosts, token, _user) def self.delete(verbose, url, hosts, token, _user)
@ -146,22 +145,26 @@ class Pooler
def self.status(verbose, url) def self.status(verbose, url)
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
response = conn.get 'status' response = conn.get '/status'
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
def self.summary(verbose, url) def self.summary(verbose, url)
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
response = conn.get 'summary' response = conn.get '/summary'
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
def self.query(verbose, url, hostname) def self.query(verbose, url, hostname)
conn = Http.get_conn(verbose, url) conn = Http.get_conn(verbose, url)
response = conn.get "vm/#{hostname}" response = conn.get "vm/#{hostname}"
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
def self.snapshot(verbose, url, hostname, token) def self.snapshot(verbose, url, hostname, token)
@ -171,7 +174,8 @@ class Pooler
conn.headers['X-AUTH-TOKEN'] = token conn.headers['X-AUTH-TOKEN'] = token
response = conn.post "vm/#{hostname}/snapshot" response = conn.post "vm/#{hostname}/snapshot"
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
def self.revert(verbose, url, hostname, token, snapshot_sha) def self.revert(verbose, url, hostname, token, snapshot_sha)
@ -183,6 +187,7 @@ class Pooler
raise "Snapshot SHA provided was nil, could not revert #{hostname}" if snapshot_sha.nil? raise "Snapshot SHA provided was nil, could not revert #{hostname}" if snapshot_sha.nil?
response = conn.post "vm/#{hostname}/snapshot/#{snapshot_sha}" response = conn.post "vm/#{hostname}/snapshot/#{snapshot_sha}"
JSON.parse(response.body) res_body = JSON.parse(response.body)
res_body
end end
end end

View file

@ -39,7 +39,7 @@ class Service
def user def user
unless @config['user'] unless @config['user']
FloatyLogger.info "Enter your #{@config['url']} service username:" FloatyLogger.info "Enter your #{@config['url']} service username:"
@config['user'] = $stdin.gets.chomp @config['user'] = STDIN.gets.chomp
end end
@config['user'] @config['user']
end end
@ -87,7 +87,7 @@ class Service
@service_object.wait_for_request verbose, requestid, url @service_object.wait_for_request verbose, requestid, url
end end
def ssh(verbose, host_os, use_token = true, ondemand = nil) def ssh(verbose, host_os, use_token = true)
token_value = nil token_value = nil
if use_token if use_token
begin begin
@ -97,7 +97,7 @@ class Service
FloatyLogger.info 'Could not get token... requesting vm without a token anyway...' FloatyLogger.info 'Could not get token... requesting vm without a token anyway...'
end end
end end
Ssh.ssh(verbose, self, host_os, token_value, ondemand) Ssh.ssh(verbose, self, host_os, token_value)
end end
def query(verbose, hostname) def query(verbose, hostname)
@ -140,8 +140,8 @@ class Service
# some methods do not exist for ABS, and if possible should target the Pooler service # some methods do not exist for ABS, and if possible should target the Pooler service
def maybe_use_vmpooler def maybe_use_vmpooler
if @service_object == ABS # this is not an instance if @service_object == ABS # this is not an instance
unless silent if !self.silent
FloatyLogger.info 'The service in use is ABS, but the requested method should run against vmpooler directly, using fallback_vmpooler config from ~/.vmfloaty.yml' FloatyLogger.info "The service in use is ABS, but the requested method should run against vmpooler directly, using fallback_vmpooler config from ~/.vmfloaty.yml"
self.silent = true self.silent = true
end end

View file

@ -14,45 +14,27 @@ class Ssh
nil nil
end end
def self.command_string(verbose, service, host_os, use_token, ondemand = nil) def self.command_string(verbose, service, host_os, use_token)
ssh_path = which('ssh') ssh_path = which('ssh')
raise 'Could not determine path to ssh' unless ssh_path raise 'Could not determine path to ssh' unless ssh_path
os_types = Utils.generate_os_hash([host_os])
os_types = {}
os_types[host_os] = 1 os_types[host_os] = 1
response = service.retrieve(verbose, os_types, use_token, ondemand) response = service.retrieve(verbose, os_types, use_token)
raise "Could not get vm from #{service.type}:\n #{response}" unless response['ok'] raise "Could not get vm from #{service.type}:\n #{response}" unless response['ok']
user = /win/.match?(host_os) ? 'Administrator' : 'root' user = /win/.match?(host_os) ? 'Administrator' : 'root'
if ondemand hostname = response[host_os]['hostname']
requestid = response['request_id'] hostname = response[host_os]['hostname'][0] if response[host_os]['hostname'].is_a?(Array)
service.wait_for_request(verbose, requestid) hostname = "#{hostname}.#{response['domain']}" unless hostname.end_with?('puppetlabs.net')
hosts = service.check_ondemandvm(verbose, requestid, service.url)
if hosts['domain'].nil?
hostname = hosts[host_os]['hostname']
hostname = hosts[host_os]['hostname'][0] if hosts[host_os]['hostname'].is_a?(Array)
else
# Provides backwards compatibility with VMPooler API v1
hostname = "#{hosts[host_os]['hostname']}.#{hosts['domain']}"
hostname = "#{hosts[host_os]['hostname'][0]}.#{hosts['domain']}" if hosts[host_os]['hostname'].is_a?(Array)
end
else
if response['domain'].nil?
hostname = response[host_os]['hostname']
hostname = response[host_os]['hostname'][0] if response[host_os]['hostname'].is_a?(Array)
else
# Provides backwards compatibility with VMPooler API v1
hostname = "#{response[host_os]['hostname']}.#{response['domain']}"
hostname = "#{response[host_os]['hostname'][0]}.#{response['domain']}" if response[host_os]['hostname'].is_a?(Array)
end
end
"#{ssh_path} #{user}@#{hostname}" "#{ssh_path} #{user}@#{hostname}"
end end
def self.ssh(verbose, service, host_os, use_token, ondemand) def self.ssh(verbose, service, host_os, use_token)
cmd = command_string(verbose, service, host_os, use_token, ondemand) cmd = command_string(verbose, service, host_os, use_token)
# TODO: Should this respect more ssh settings? Can it be configured # TODO: Should this respect more ssh settings? Can it be configured
# by users ssh config and does this respect those settings? # by users ssh config and does this respect those settings?
Kernel.exec(cmd) Kernel.exec(cmd)

View file

@ -9,7 +9,7 @@ class Utils
# TODO: Takes the json response body from an HTTP GET # TODO: Takes the json response body from an HTTP GET
# request and "pretty prints" it # request and "pretty prints" it
def self.standardize_hostnames(response_body) def self.standardize_hostnames(response_body)
# vmpooler api v1 response body example when `floaty get` arguments are `ubuntu-1610-x86_64=2 centos-7-x86_64`: # vmpooler response body example when `floaty get` arguments are `ubuntu-1610-x86_64=2 centos-7-x86_64`:
# { # {
# "ok": true, # "ok": true,
# "domain": "delivery.mycompany.net", # "domain": "delivery.mycompany.net",
@ -21,17 +21,6 @@ class Utils
# } # }
# } # }
# vmpooler api v2 response body example when `floaty get` arguments are `ubuntu-1610-x86_64=2 centos-7-x86_64`:
# {
# "ok": true,
# "ubuntu-1610-x86_64": {
# "hostname": ["gdoy8q3nckuob0i.pooler.example.com", "ctnktsd0u11p9tm.pooler.example.com"]
# },
# "centos-7-x86_64": {
# "hostname": "dlgietfmgeegry2.pooler.example.com"
# }
# }
# nonstandard pooler response body example when `floaty get` arguments are `solaris-11-sparc=2 ubuntu-16.04-power8`: # nonstandard pooler response body example when `floaty get` arguments are `solaris-11-sparc=2 ubuntu-16.04-power8`:
# { # {
# "ok": true, # "ok": true,
@ -50,10 +39,7 @@ class Utils
# "engine"=>"vmpooler" # "engine"=>"vmpooler"
# } # }
unless response_body.delete('ok') raise ArgumentError, "Bad GET response passed to format_hosts: #{response_body.to_json}" unless response_body.delete('ok')
raise ArgumentError,
"Bad GET response passed to format_hosts: #{response_body.to_json}"
end
# vmpooler reports the domain separately from the hostname # vmpooler reports the domain separately from the hostname
domain = response_body.delete('domain') domain = response_body.delete('domain')
@ -64,7 +50,7 @@ class Utils
abs_job_id = response_body.delete('job_id') abs_job_id = response_body.delete('job_id')
result['job_id'] = abs_job_id unless abs_job_id.nil? result['job_id'] = abs_job_id unless abs_job_id.nil?
filtered_response_body = response_body.reject { |key, _| %w[request_id ready].include?(key) } filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' }
filtered_response_body.each do |os, value| filtered_response_body.each do |os, value|
hostnames = Array(value['hostname']) hostnames = Array(value['hostname'])
hostnames.map! { |host| "#{host}.#{domain}" } if domain hostnames.map! { |host| "#{host}.#{domain}" } if domain
@ -109,11 +95,7 @@ class Utils
puts abs_hostnames.join("\n") puts abs_hostnames.join("\n")
when 'Pooler' when 'Pooler'
if host_data['domain'].nil? puts "#{hostname}.#{host_data['domain']}"
puts hostname
else
puts "#{hostname}.#{host_data['domain']}"
end
when 'NonstandardPooler' when 'NonstandardPooler'
puts host_data['fqdn'] puts host_data['fqdn']
else else
@ -124,7 +106,7 @@ class Utils
def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false, indent = 0) def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false, indent = 0)
output_target = print_to_stderr ? $stderr : $stdout output_target = print_to_stderr ? $stderr : $stdout
fetched_data = get_host_data(verbose, service, hostnames) fetched_data = self.get_host_data(verbose, service, hostnames)
fetched_data.each do |hostname, host_data| fetched_data.each do |hostname, host_data|
case service.type case service.type
when 'ABS' when 'ABS'
@ -134,14 +116,13 @@ class Utils
output_target.puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>" output_target.puts "- [JobID:#{host_data['request']['job']['id']}] <#{host_data['state']}>"
host_data['allocated_resources'].each do |allocated_resources, _i| host_data['allocated_resources'].each do |allocated_resources, _i|
if (allocated_resources['engine'] == 'vmpooler' || allocated_resources['engine'] == 'ondemand') && service.config['vmpooler_fallback'] if (allocated_resources['engine'] == "vmpooler" || allocated_resources['engine'] == 'ondemand') && service.config["vmpooler_fallback"]
vmpooler_service = service.clone vmpooler_service = service.clone
vmpooler_service.silent = true vmpooler_service.silent = true
vmpooler_service.maybe_use_vmpooler vmpooler_service.maybe_use_vmpooler
pretty_print_hosts(verbose, vmpooler_service, allocated_resources['hostname'].split('.')[0], self.pretty_print_hosts(verbose, vmpooler_service, allocated_resources['hostname'].split('.')[0], print_to_stderr, indent+2)
print_to_stderr, indent + 2)
else else
# TODO: we could add more specific metadata for the other services, nspooler and aws #TODO we could add more specific metadata for the other services, nspooler and aws
output_target.puts " - #{allocated_resources['hostname']} (#{allocated_resources['type']})" output_target.puts " - #{allocated_resources['hostname']} (#{allocated_resources['type']})"
end end
end end
@ -150,23 +131,16 @@ class Utils
tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil? tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
duration = "#{host_data['running']}/#{host_data['lifetime']} hours" duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
metadata = [host_data['state'], host_data['template'], duration, *tag_pairs] metadata = [host_data['state'], host_data['template'], duration, *tag_pairs]
# For backwards compatibility with vmpooler api v1 message = "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent)
message = if host_data['state'] && host_data['state'] == "destroyed"
if host_data['domain'] output_target.puts message.colorize(:red)
"- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent)
else
"- #{host_data['fqdn']} (#{metadata.join(', ')})".gsub(/^/, ' ' * indent)
end
if host_data['state'] && host_data['state'] == 'destroyed'
output_target.puts "- DESTROYED #{hostname}.#{host_data['domain']}".gsub(/^/, ' ' * indent)
else else
output_target.puts message output_target.puts message
end end
when 'NonstandardPooler' when 'NonstandardPooler'
line = "- #{host_data['fqdn']} (#{host_data['os_triple']}" line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
line += ", #{host_data['hours_left_on_reservation']}h remaining" line += ", #{host_data['hours_left_on_reservation']}h remaining"
line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].nil? || host_data['reserved_for_reason'].empty? line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
line += ')' line += ')'
output_target.puts line output_target.puts line
else else
@ -179,26 +153,30 @@ class Utils
result = {} result = {}
hostnames = [hostnames] unless hostnames.is_a? Array hostnames = [hostnames] unless hostnames.is_a? Array
hostnames.each do |hostname| hostnames.each do |hostname|
response = service.query(verbose, hostname) begin
host_data = response[hostname] response = service.query(verbose, hostname)
if block_given? host_data = response[hostname]
yield host_data result if block_given?
else yield host_data result
case service.type
when 'ABS'
# For ABS, 'hostname' variable is the jobID
result[hostname] = host_data if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
when 'Pooler'
result[hostname] = host_data
when 'NonstandardPooler'
result[hostname] = host_data
else else
raise "Invalid service type #{service.type}" case service.type
when 'ABS'
# For ABS, 'hostname' variable is the jobID
if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
result[hostname] = host_data
end
when 'Pooler'
result[hostname] = host_data
when 'NonstandardPooler'
result[hostname] = host_data
else
raise "Invalid service type #{service.type}"
end
end end
rescue StandardError => e
FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
FloatyLogger.error(e)
end end
rescue StandardError => e
FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
FloatyLogger.error(e)
end end
result result
end end
@ -214,16 +192,18 @@ class Utils
width = pools.keys.map(&:length).max width = pools.keys.map(&:length).max
pools.each do |name, pool| pools.each do |name, pool|
max = pool['max'] begin
ready = pool['ready'] max = pool['max']
pending = pool['pending'] ready = pool['ready']
missing = max - ready - pending pending = pool['pending']
char = 'o' missing = max - ready - pending
puts "#{name.ljust(width)} #{(char * ready)}#{(char * pending)}#{(char * missing)}" char = 'o'
rescue StandardError => e puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
FloatyLogger.error "#{name.ljust(width)} #{e}" rescue StandardError => e
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
end
end end
puts message puts message.colorize(status_response['status']['ok'] ? :default : :red)
when 'NonstandardPooler' when 'NonstandardPooler'
pools = status_response pools = status_response
pools.delete 'ok' pools.delete 'ok'
@ -231,18 +211,20 @@ class Utils
width = pools.keys.map(&:length).max width = pools.keys.map(&:length).max
pools.each do |name, pool| pools.each do |name, pool|
max = pool['total_hosts'] begin
ready = pool['available_hosts'] max = pool['total_hosts']
pending = pool['pending'] || 0 # not available for nspooler ready = pool['available_hosts']
missing = max - ready - pending pending = pool['pending'] || 0 # not available for nspooler
char = 'o' missing = max - ready - pending
puts "#{name.ljust(width)} #{(char * ready)}#{(char * pending)}#{(char * missing)}" char = 'o'
rescue StandardError => e puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
FloatyLogger.error "#{name.ljust(width)} #{e}" rescue StandardError => e
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
end
end end
when 'ABS' when 'ABS'
FloatyLogger.error 'ABS Not OK' unless status_response FloatyLogger.error 'ABS Not OK' unless status_response
puts 'ABS is OK' if status_response puts 'ABS is OK'.green if status_response
else else
raise "Invalid service type #{service.type}" raise "Invalid service type #{service.type}"
end end
@ -274,11 +256,11 @@ class Utils
def self.get_service_config(config, options) def self.get_service_config(config, options)
# The top-level url, user, and token values in the config file are treated as defaults # The top-level url, user, and token values in the config file are treated as defaults
service_config = { service_config = {
'url' => config['url'], 'url' => config['url'],
'user' => config['user'], 'user' => config['user'],
'token' => config['token'], 'token' => config['token'],
'vmpooler_fallback' => config['vmpooler_fallback'], 'vmpooler_fallback' => config['vmpooler_fallback'],
'type' => config['type'] || 'vmpooler' 'type' => config['type'] || 'vmpooler',
} }
if config['services'] if config['services']
@ -289,10 +271,7 @@ class Utils
service_config.merge! values service_config.merge! values
else else
# If the user provided a service name at the command line, use that service if posible, or fail # If the user provided a service name at the command line, use that service if posible, or fail
unless config['services'][options.service] raise ArgumentError, "Could not find a configured service named '#{options.service}' in ~/.vmfloaty.yml" unless config['services'][options.service]
raise ArgumentError,
"Could not find a configured service named '#{options.service}' in ~/.vmfloaty.yml"
end
# If the service is configured but some values are missing, use the top-level defaults to fill them in # If the service is configured but some values are missing, use the top-level defaults to fill them in
service_config.merge! config['services'][options.service] service_config.merge! config['services'][options.service]
@ -316,22 +295,22 @@ class Utils
config = Conf.read_config config = Conf.read_config
# The top-level url, user, and token values in the config file are treated as defaults # The top-level url, user, and token values in the config file are treated as defaults
service_config = { service_config = {
'url' => config['url'], 'url' => config['url'],
'user' => config['user'], 'user' => config['user'],
'token' => config['token'], 'token' => config['token'],
'type' => 'vmpooler' 'type' => 'vmpooler',
} }
# at a minimum, the url needs to be configured # at a minimum, the url needs to be configured
if config['services'] && config['services'][vmpooler_fallback] && config['services'][vmpooler_fallback]['url'] if config['services'] && config['services'][vmpooler_fallback] && config['services'][vmpooler_fallback]['url']
# If the service is configured but some values are missing, use the top-level defaults to fill them in # If the service is configured but some values are missing, use the top-level defaults to fill them in
service_config.merge! config['services'][vmpooler_fallback] service_config.merge! config['services'][vmpooler_fallback]
elsif vmpooler_fallback.nil?
raise ArgumentError,
"The abs service should have a key named 'vmpooler_fallback' in ~/.vmfloaty.yml with a value that points to a vmpooler service name use this format:\nservices:\n myabs:\n url: 'http://abs.com'\n user: 'superman'\n token: 'kryptonite'\n vmpooler_fallback: 'myvmpooler'\n myvmpooler:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'"
else else
raise ArgumentError, if vmpooler_fallback.nil?
"Could not find a configured service named '#{vmpooler_fallback}' in ~/.vmfloaty.yml use this format:\nservices:\n #{vmpooler_fallback}:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'" raise ArgumentError, "The abs service should have a key named 'vmpooler_fallback' in ~/.vmfloaty.yml with a value that points to a vmpooler service name use this format:\nservices:\n myabs:\n url: 'http://abs.com'\n user: 'superman'\n token: 'kryptonite'\n vmpooler_fallback: 'myvmpooler'\n myvmpooler:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'"
else
raise ArgumentError, "Could not find a configured service named '#{vmpooler_fallback}' in ~/.vmfloaty.yml use this format:\nservices:\n #{vmpooler_fallback}:\n url: 'http://vmpooler.com'\n user: 'superman'\n token: 'kryptonite'"
end
end end
service_config service_config

View file

@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Vmfloaty class Vmfloaty
VERSION = '1.8.1' VERSION = '1.3.0'
end end

View file

@ -1,12 +0,0 @@
#!/usr/bin/env bash
# bundle install
docker run -t --rm \
-v $(pwd):/app \
$(grep ^FROM ./Dockerfile |cut -d ' ' -f2) \
/bin/bash -c 'apt-get update -qq && apt-get install -y --no-install-recommends build-essential make openssh-client && cd /app && gem install bundler && bundle install --jobs 3; echo "LOCK_FILE_UPDATE_EXIT_CODE=$?"'
# Update Changelog
docker run -t --rm -e CHANGELOG_GITHUB_TOKEN -v $(pwd):/usr/local/src/your-app \
githubchangeloggenerator/github-changelog-generator:1.16.2 \
github_changelog_generator --future-release $(grep VERSION lib/vmfloaty/version.rb |rev |cut -d "'" -f2 |rev)

View file

@ -1,21 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'simplecov' require 'simplecov'
require 'simplecov-lcov' require 'coveralls'
require 'base64'
SimpleCov::Formatter::LcovFormatter.config do |c|
c.report_with_single_file = true
c.single_report_path = 'coverage/lcov.info'
end
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
[
SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::LcovFormatter
]
)
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::HTMLFormatter,
Coveralls::SimpleCov::Formatter
])
SimpleCov.start do SimpleCov.start do
add_filter %r{^/spec/} add_filter %r{^/spec/}
end end
@ -35,19 +26,3 @@ RSpec.configure do |config|
config.tty = true config.tty = true
config.formatter = :documentation config.formatter = :documentation
end end
def get_headers(username: nil, password: nil, token: nil, content_type: nil, content_length: nil)
headers = {
'Accept' => '*/*',
'Accept-Encoding' => /gzip/,
'User-Agent' => /Faraday/,
}
if username && password
auth = Base64.encode64("#{username}:#{password}").chomp
headers['Authorization'] = "Basic #{auth}"
end
headers['X-Auth-Token'] = token if token
headers['Content-Type'] = content_type if content_type
headers['Content-Length'] = content_length.to_s if content_length
headers
end

View file

@ -3,11 +3,7 @@
require 'spec_helper' require 'spec_helper'
require_relative '../../../lib/vmfloaty/auth' require_relative '../../../lib/vmfloaty/auth'
user = 'first.last'
pass = 'password'
describe Pooler do describe Pooler do
before :each do before :each do
@abs_url = 'https://abs.example.com/api/v2' @abs_url = 'https://abs.example.com/api/v2'
end end
@ -19,20 +15,18 @@ describe Pooler do
end end
it 'returns a token from abs' do it 'returns a token from abs' do
stub_request(:post, 'https://abs.example.com/api/v2/token') stub_request(:post, 'https://first.last:password@abs.example.com/api/v2/token')
.with(headers: get_headers(username: user, password: pass, content_length: 0)) .to_return(:status => 200, :body => @get_token_response, :headers => {})
.to_return(status: 200, body: @get_token_response, headers: {})
token = Auth.get_token(false, @abs_url, user, pass) token = Auth.get_token(false, @abs_url, 'first.last', 'password')
expect(token).to eq @token expect(token).to eq @token
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:post, 'https://abs.example.com/api/v2/token') stub_request(:post, 'https://first.last:password@abs.example.com/api/v2/token')
.with(headers: get_headers(username: user, password: pass, content_length: 0)) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
.to_return(status: 500, body: '{"ok":false}', headers: {})
expect { Auth.get_token(false, @abs_url, user, pass) }.to raise_error(TokenError) expect { Auth.get_token(false, @abs_url, 'first.last', 'password') }.to raise_error(TokenError)
end end
end end
@ -43,24 +37,21 @@ describe Pooler do
end end
it 'deletes the specified token' do it 'deletes the specified token' do
stub_request(:delete, 'https://abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y') stub_request(:delete, 'https://first.last:password@abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
.with(headers: get_headers(username: user, password: pass)) .to_return(:status => 200, :body => @delete_token_response, :headers => {})
.to_return(status: 200, body: @delete_token_response, headers: {})
expect(Auth.delete_token(false, @abs_url, user, pass, expect(Auth.delete_token(false, @abs_url, 'first.last', 'password', @token)).to eq JSON.parse(@delete_token_response)
@token)).to eq JSON.parse(@delete_token_response)
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:delete, 'https://abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y') stub_request(:delete, 'https://first.last:password@abs.example.com/api/v2/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
.with(headers: get_headers(username: user, password: pass)) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
.to_return(status: 500, body: '{"ok":false}', headers: {})
expect { Auth.delete_token(false, @abs_url, user, pass, @token) }.to raise_error(TokenError) expect { Auth.delete_token(false, @abs_url, 'first.last', 'password', @token) }.to raise_error(TokenError)
end end
it 'raises a token error if no token provided' do it 'raises a token error if no token provided' do
expect { Auth.delete_token(false, @abs_url, user, pass, nil) }.to raise_error(TokenError) expect { Auth.delete_token(false, @abs_url, 'first.last', 'password', nil) }.to raise_error(TokenError)
end end
end end
@ -72,16 +63,16 @@ describe Pooler do
it 'checks the status of a token' do it 'checks the status of a token' do
stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y") stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
.with(headers: get_headers) .with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3' })
.to_return(status: 200, body: @token_status_response, headers: {}) .to_return(:status => 200, :body => @token_status_response, :headers => {})
expect(Auth.token_status(false, @abs_url, @token)).to eq JSON.parse(@token_status_response) expect(Auth.token_status(false, @abs_url, @token)).to eq JSON.parse(@token_status_response)
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y") stub_request(:get, "#{@abs_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
.with(headers: get_headers) .with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3' })
.to_return(status: 500, body: '{"ok":false}', headers: {}) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
expect { Auth.token_status(false, @abs_url, @token) }.to raise_error(TokenError) expect { Auth.token_status(false, @abs_url, @token) }.to raise_error(TokenError)
end end

View file

@ -11,12 +11,12 @@ describe ABS do
describe '#list' do describe '#list' do
it 'skips empty platforms and lists aws' do it 'skips empty platforms and lists aws' do
stub_request(:get, 'http://foo/api/v2/status/platforms/vmpooler') stub_request(:get, "http://foo/api/v2/status/platforms/vmpooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
stub_request(:get, 'http://foo/api/v2/status/platforms/ondemand_vmpooler') stub_request(:get, "http://foo/api/v2/status/platforms/ondemand_vmpooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
stub_request(:get, 'http://foo/api/v2/status/platforms/nspooler') stub_request(:get, "http://foo/api/v2/status/platforms/nspooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
body = '{ body = '{
"aws_platforms": [ "aws_platforms": [
"amazon-6-x86_64", "amazon-6-x86_64",
@ -26,55 +26,50 @@ describe ABS do
"redhat-8-arm64" "redhat-8-arm64"
] ]
}' }'
stub_request(:get, 'http://foo/api/v2/status/platforms/aws') stub_request(:get, "http://foo/api/v2/status/platforms/aws").
.to_return(status: 200, body: body, headers: {}) to_return(:status => 200, :body => body, :headers => {})
results = ABS.list(false, 'http://foo')
expect(results).to include('amazon-6-x86_64', 'amazon-7-x86_64', 'amazon-7-arm64', 'centos-7-x86-64-west', results = ABS.list(false, "http://foo")
'redhat-8-arm64')
expect(results).to include("amazon-6-x86_64", "amazon-7-x86_64", "amazon-7-arm64", "centos-7-x86-64-west", "redhat-8-arm64")
end end
it 'legacy JSON string, prior to PR 306' do it 'legacy JSON string, prior to PR 306' do
stub_request(:get, 'http://foo/api/v2/status/platforms/vmpooler') stub_request(:get, "http://foo/api/v2/status/platforms/vmpooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
stub_request(:get, 'http://foo/api/v2/status/platforms/ondemand_vmpooler') stub_request(:get, "http://foo/api/v2/status/platforms/ondemand_vmpooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
stub_request(:get, 'http://foo/api/v2/status/platforms/nspooler') stub_request(:get, "http://foo/api/v2/status/platforms/nspooler").
.to_return(status: 200, body: '', headers: {}) to_return(:status => 200, :body => "", :headers => {})
body = '{ body = '{
"aws_platforms": "[\"amazon-6-x86_64\",\"amazon-7-x86_64\",\"amazon-7-arm64\",\"centos-7-x86-64-west\",\"redhat-8-arm64\"]" "aws_platforms": "[\"amazon-6-x86_64\",\"amazon-7-x86_64\",\"amazon-7-arm64\",\"centos-7-x86-64-west\",\"redhat-8-arm64\"]"
}' }'
stub_request(:get, 'http://foo/api/v2/status/platforms/aws') stub_request(:get, "http://foo/api/v2/status/platforms/aws").
.to_return(status: 200, body: body, headers: {}) to_return(:status => 200, :body => body, :headers => {})
results = ABS.list(false, 'http://foo') results = ABS.list(false, "http://foo")
expect(results).to include('amazon-6-x86_64', 'amazon-7-x86_64', 'amazon-7-arm64', 'centos-7-x86-64-west', expect(results).to include("amazon-6-x86_64", "amazon-7-x86_64", "amazon-7-arm64", "centos-7-x86-64-west", "redhat-8-arm64")
'redhat-8-arm64')
end end
end end
describe '#format' do describe '#format' do
it 'returns an hash formatted like a vmpooler return, plus the job_id' do it 'returns an hash formatted like a vmpooler return, plus the job_id' do
job_id = 'generated_by_floaty_12345' job_id = "generated_by_floaty_12345"
abs_formatted_response = [ abs_formatted_response = [
{ 'hostname' => 'aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', { 'hostname' => 'aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
'engine' => 'vmpooler' }, { 'hostname' => 'aaaaaaaaaaaaaab.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', 'engine' => 'vmpooler' },
{ 'hostname' => 'aaaaaaaaaaaaaab.delivery.puppetlabs.net', 'type' => 'centos-7.2-x86_64', { 'hostname' => 'aaaaaaaaaaaaaac.delivery.puppetlabs.net', 'type' => 'ubuntu-7.2-x86_64', 'engine' => 'vmpooler' },
'engine' => 'vmpooler' },
{ 'hostname' => 'aaaaaaaaaaaaaac.delivery.puppetlabs.net', 'type' => 'ubuntu-7.2-x86_64',
'engine' => 'vmpooler' }
] ]
vmpooler_formatted_response = ABS.translated(abs_formatted_response, job_id) vmpooler_formatted_response = ABS.translated(abs_formatted_response, job_id)
vmpooler_formatted_compare = { vmpooler_formatted_compare = {
'centos-7.2-x86_64' => {}, 'centos-7.2-x86_64' => {},
'ubuntu-7.2-x86_64' => {} 'ubuntu-7.2-x86_64' => {},
} }
vmpooler_formatted_compare['centos-7.2-x86_64']['hostname'] = vmpooler_formatted_compare['centos-7.2-x86_64']['hostname'] = ['aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'aaaaaaaaaaaaaab.delivery.puppetlabs.net']
['aaaaaaaaaaaaaaa.delivery.puppetlabs.net', 'aaaaaaaaaaaaaab.delivery.puppetlabs.net']
vmpooler_formatted_compare['ubuntu-7.2-x86_64']['hostname'] = ['aaaaaaaaaaaaaac.delivery.puppetlabs.net'] vmpooler_formatted_compare['ubuntu-7.2-x86_64']['hostname'] = ['aaaaaaaaaaaaaac.delivery.puppetlabs.net']
vmpooler_formatted_compare['ok'] = true vmpooler_formatted_compare['ok'] = true
@ -91,22 +86,22 @@ describe ABS do
hosts = ['host1'] hosts = ['host1']
allocated_resources = [ allocated_resources = [
{ {
'hostname' => 'host1' 'hostname' => 'host1',
}, },
{ {
'hostname' => 'host2' 'hostname' => 'host2',
} },
] ]
expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(false) expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(false)
hosts = %w[host1 host2] hosts = ['host1', 'host2']
allocated_resources = [ allocated_resources = [
{ {
'hostname' => 'host1' 'hostname' => 'host1',
}, },
{ {
'hostname' => 'host2' 'hostname' => 'host2',
} },
] ]
expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(true) expect(ABS.all_job_resources_accounted_for(allocated_resources, hosts)).to eq(true)
end end
@ -131,16 +126,16 @@ describe ABS do
it 'will skip a line with a null value returned from abs' do it 'will skip a line with a null value returned from abs' do
stub_request(:get, 'https://abs.example.com/api/v2/status/queue') stub_request(:get, 'https://abs.example.com/api/v2/status/queue')
.to_return(status: 200, body: @active_requests_response, headers: {}) .to_return(:status => 200, :body => @active_requests_response, :headers => {})
ret = ABS.get_active_requests(false, @abs_url, @test_user) ret = ABS.get_active_requests(false, @abs_url, @test_user)
expect(ret[0]).to include( expect(ret[0]).to include(
'allocated_resources' => [{ 'allocated_resources' => [{
'hostname' => 'take-this.delivery.puppetlabs.net', 'hostname' => 'take-this.delivery.puppetlabs.net',
'type' => 'win-2012r2-x86_64', 'type' => 'win-2012r2-x86_64',
'engine' => 'vmpooler' 'engine' => 'vmpooler',
}] }],
) )
end end
end end
@ -152,11 +147,7 @@ describe ABS do
[ [
{ "state":"allocated", "last_processed":"2020-01-17 22:29:13 +0000", "allocated_resources":[{"hostname":"craggy-chord.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}, {"hostname":"visible-revival.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}], "audit_log":{"2020-01-17 22:28:45 +0000":"Allocated craggy-chord.delivery.puppetlabs.net, visible-revival.delivery.puppetlabs.net for job 1579300120799"}, "request":{"resources":{"centos-7-x86_64":2}, "job":{"id":"1579300120799", "tags":{"user":"test-user"}, "user":"test-user", "time-received":1579300120}, "priority":3}} { "state":"allocated", "last_processed":"2020-01-17 22:29:13 +0000", "allocated_resources":[{"hostname":"craggy-chord.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}, {"hostname":"visible-revival.delivery.puppetlabs.net", "type":"centos-7-x86_64", "engine":"vmpooler"}], "audit_log":{"2020-01-17 22:28:45 +0000":"Allocated craggy-chord.delivery.puppetlabs.net, visible-revival.delivery.puppetlabs.net for job 1579300120799"}, "request":{"resources":{"centos-7-x86_64":2}, "job":{"id":"1579300120799", "tags":{"user":"test-user"}, "user":"test-user", "time-received":1579300120}, "priority":3}}
]' ]'
@return_request = { @return_request = { '{"job_id":"1579300120799","hosts":{"hostname":"craggy-chord.delivery.puppetlabs.net","type":"centos-7-x86_64","engine":"vmpooler"},{"hostname":"visible-revival.delivery.puppetlabs.net","type":"centos-7-x86_64","engine":"vmpooler"}}'=>true }
"job_id" => "1579300120799",
"hosts" => [{"hostname"=>"craggy-chord.delivery.puppetlabs.net","type"=>"centos-7-x86_64","engine"=>"vmpooler"},
{"hostname"=>"visible-revival.delivery.puppetlabs.net","type"=>"centos-7-x86_64","engine"=>"vmpooler"}]
}
# rubocop:enable Layout/LineLength # rubocop:enable Layout/LineLength
@token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y' @token = 'utpg2i2xswor6h8ttjhu3d47z53yy47y'
@test_user = 'test-user' @test_user = 'test-user'
@ -166,15 +157,15 @@ describe ABS do
it 'will delete the whole job' do it 'will delete the whole job' do
stub_request(:get, 'https://abs.example.com/api/v2/status/queue') stub_request(:get, 'https://abs.example.com/api/v2/status/queue')
.to_return(status: 200, body: @active_requests_response, headers: {}) .to_return(:status => 200, :body => @active_requests_response, :headers => {})
stub_request(:post, 'https://abs.example.com/api/v2/return') stub_request(:post, 'https://abs.example.com/api/v2/return')
.with(headers: get_headers(content_type: 'application/x-www-form-urlencoded', token: @token), body: @return_request.to_json) .with(:body => @return_request)
.to_return(status: 200, body: 'OK', headers: {}) .to_return(:status => 200, :body => 'OK', :headers => {})
ret = ABS.delete(false, @abs_url, @hosts, @token, @test_user) ret = ABS.delete(false, @abs_url, @hosts, @token, @test_user)
expect(ret).to include( expect(ret).to include(
'craggy-chord.delivery.puppetlabs.net' => { 'ok' => true }, 'visible-revival.delivery.puppetlabs.net' => { 'ok' => true } 'craggy-chord.delivery.puppetlabs.net' => { 'ok'=>true }, 'visible-revival.delivery.puppetlabs.net' => { 'ok'=>true },
) )
end end
end end

View file

@ -3,9 +3,6 @@
require 'spec_helper' require 'spec_helper'
require_relative '../../lib/vmfloaty/auth' require_relative '../../lib/vmfloaty/auth'
user = 'first.last'
pass = 'password'
describe Pooler do describe Pooler do
before :each do before :each do
@vmpooler_url = 'https://vmpooler.example.com' @vmpooler_url = 'https://vmpooler.example.com'
@ -18,20 +15,18 @@ describe Pooler do
end end
it 'returns a token from vmpooler' do it 'returns a token from vmpooler' do
stub_request(:post, 'https://vmpooler.example.com/token') stub_request(:post, 'https://first.last:password@vmpooler.example.com/token')
.with(headers: get_headers(username: user, password: pass, content_length: 0)) .to_return(:status => 200, :body => @get_token_response, :headers => {})
.to_return(status: 200, body: @get_token_response, headers: {})
token = Auth.get_token(false, @vmpooler_url, user, pass) token = Auth.get_token(false, @vmpooler_url, 'first.last', 'password')
expect(token).to eq @token expect(token).to eq @token
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:post, 'https://vmpooler.example.com/token') stub_request(:post, 'https://first.last:password@vmpooler.example.com/token')
.with(headers: get_headers(username: user, password: pass, content_length: 0)) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
.to_return(status: 500, body: '{"ok":false}', headers: {})
expect { Auth.get_token(false, @vmpooler_url, user, pass) }.to raise_error(TokenError) expect { Auth.get_token(false, @vmpooler_url, 'first.last', 'password') }.to raise_error(TokenError)
end end
end end
@ -42,18 +37,15 @@ describe Pooler do
end end
it 'deletes the specified token' do it 'deletes the specified token' do
stub_request(:delete, 'https://vmpooler.example.com/token/utpg2i2xswor6h8ttjhu3d47z53yy47y') stub_request(:delete, 'https://first.last:password@vmpooler.example.com/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
.with(headers: get_headers(username: user, password: pass)) .to_return(:status => 200, :body => @delete_token_response, :headers => {})
.to_return(status: 200, body: @delete_token_response, headers: {})
expect(Auth.delete_token(false, @vmpooler_url, user, pass, expect(Auth.delete_token(false, @vmpooler_url, 'first.last', 'password', @token)).to eq JSON.parse(@delete_token_response)
@token)).to eq JSON.parse(@delete_token_response)
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:delete, 'https://vmpooler.example.com/token/utpg2i2xswor6h8ttjhu3d47z53yy47y') stub_request(:delete, 'https://first.last:password@vmpooler.example.com/token/utpg2i2xswor6h8ttjhu3d47z53yy47y')
.with(headers: get_headers(username: user, password: pass)) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
.to_return(status: 500, body: '{"ok":false}', headers: {})
expect { Auth.delete_token(false, @vmpooler_url, 'first.last', 'password', @token) }.to raise_error(TokenError) expect { Auth.delete_token(false, @vmpooler_url, 'first.last', 'password', @token) }.to raise_error(TokenError)
end end
@ -71,16 +63,14 @@ describe Pooler do
it 'checks the status of a token' do it 'checks the status of a token' do
stub_request(:get, "#{@vmpooler_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y") stub_request(:get, "#{@vmpooler_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
.with(headers: get_headers) .to_return(:status => 200, :body => @token_status_response, :headers => {})
.to_return(status: 200, body: @token_status_response, headers: {})
expect(Auth.token_status(false, @vmpooler_url, @token)).to eq JSON.parse(@token_status_response) expect(Auth.token_status(false, @vmpooler_url, @token)).to eq JSON.parse(@token_status_response)
end end
it 'raises a token error if something goes wrong' do it 'raises a token error if something goes wrong' do
stub_request(:get, "#{@vmpooler_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y") stub_request(:get, "#{@vmpooler_url}/token/utpg2i2xswor6h8ttjhu3d47z53yy47y")
.with(headers: get_headers) .to_return(:status => 500, :body => '{"ok":false}', :headers => {})
.to_return(status: 500, body: '{"ok":false}', headers: {})
expect { Auth.token_status(false, @vmpooler_url, @token) }.to raise_error(TokenError) expect { Auth.token_status(false, @vmpooler_url, @token) }.to raise_error(TokenError)
end end

View file

@ -8,7 +8,9 @@ require 'vmfloaty/nonstandard_pooler'
describe NonstandardPooler do describe NonstandardPooler do
before :each do before :each do
@nspooler_url = 'https://nspooler.example.com' @nspooler_url = 'https://nspooler.example.com'
@auth_token_headers = get_headers(token: 'token-value') @auth_token_headers = {
'X-Auth-Token' => 'token-value',
}
end end
describe '#list' do describe '#list' do
@ -34,7 +36,7 @@ describe NonstandardPooler do
it 'returns an array with operating systems from the pooler' do it 'returns an array with operating systems from the pooler' do
stub_request(:get, "#{@nspooler_url}/status") stub_request(:get, "#{@nspooler_url}/status")
.to_return(status: 200, body: @status_response_body, headers: {}) .to_return(:status => 200, :body => @status_response_body, :headers => {})
list = NonstandardPooler.list(false, @nspooler_url, nil) list = NonstandardPooler.list(false, @nspooler_url, nil)
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -42,7 +44,7 @@ describe NonstandardPooler do
it 'filters operating systems based on the filter param' do it 'filters operating systems based on the filter param' do
stub_request(:get, "#{@nspooler_url}/status") stub_request(:get, "#{@nspooler_url}/status")
.to_return(status: 200, body: @status_response_body, headers: {}) .to_return(:status => 200, :body => @status_response_body, :headers => {})
list = NonstandardPooler.list(false, @nspooler_url, 'aix') list = NonstandardPooler.list(false, @nspooler_url, 'aix')
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -51,7 +53,7 @@ describe NonstandardPooler do
it 'returns nothing if the filter does not match' do it 'returns nothing if the filter does not match' do
stub_request(:get, "#{@nspooler_url}/status") stub_request(:get, "#{@nspooler_url}/status")
.to_return(status: 199, body: @status_response_body, headers: {}) .to_return(:status => 199, :body => @status_response_body, :headers => {})
list = NonstandardPooler.list(false, @nspooler_url, 'windows') list = NonstandardPooler.list(false, @nspooler_url, 'windows')
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -87,7 +89,7 @@ describe NonstandardPooler do
.and_return(JSON.parse(@token_status_body_active)) .and_return(JSON.parse(@token_status_body_active))
list = NonstandardPooler.list_active(false, @nspooler_url, 'token-value', 'user') list = NonstandardPooler.list_active(false, @nspooler_url, 'token-value', 'user')
expect(list).to eql %w[sol10-9 sol10-11] expect(list).to eql ['sol10-9', 'sol10-11']
end end
end end
@ -119,19 +121,17 @@ describe NonstandardPooler do
it 'raises an AuthError if the token is invalid' do it 'raises an AuthError if the token is invalid' do
stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc") stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc")
.with(headers: get_headers(token: 'token-value')) .with(:headers => @auth_token_headers)
.to_return(status: 401, body: '{"ok":false,"reason": "token: token-value does not exist"}', headers: {}) .to_return(:status => 401, :body => '{"ok":false,"reason": "token: token-value does not exist"}', :headers => {})
vm_hash = { 'solaris-11-sparc' => 1 } vm_hash = { 'solaris-11-sparc' => 1 }
expect do expect { NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {}) }.to raise_error(AuthError)
NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {})
end.to raise_error(AuthError)
end end
it 'retrieves a single vm with a token' do it 'retrieves a single vm with a token' do
stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc") stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc")
.with(headers: @auth_token_headers) .with(:headers => @auth_token_headers)
.to_return(status: 200, body: @retrieve_response_body_single, headers: {}) .to_return(:status => 200, :body => @retrieve_response_body_single, :headers => {})
vm_hash = { 'solaris-11-sparc' => 1 } vm_hash = { 'solaris-11-sparc' => 1 }
vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {}) vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {})
@ -142,16 +142,15 @@ describe NonstandardPooler do
it 'retrieves a multiple vms with a token' do it 'retrieves a multiple vms with a token' do
stub_request(:post, "#{@nspooler_url}/host/aix-7.1-power+solaris-10-sparc+solaris-10-sparc") stub_request(:post, "#{@nspooler_url}/host/aix-7.1-power+solaris-10-sparc+solaris-10-sparc")
.with(headers: @auth_token_headers) .with(:headers => @auth_token_headers)
.to_return(status: 200, body: @retrieve_response_body_many, headers: {}) .to_return(:status => 200, :body => @retrieve_response_body_many, :headers => {})
vm_hash = { 'aix-7.1-power' => 1, 'solaris-10-sparc' => 2 } vm_hash = { 'aix-7.1-power' => 1, 'solaris-10-sparc' => 2 }
vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {}) vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url, 'first.last', {})
expect(vm_req).to be_an_instance_of Hash expect(vm_req).to be_an_instance_of Hash
expect(vm_req['ok']).to equal true expect(vm_req['ok']).to equal true
expect(vm_req['solaris-10-sparc']['hostname']).to be_an_instance_of Array expect(vm_req['solaris-10-sparc']['hostname']).to be_an_instance_of Array
expect(vm_req['solaris-10-sparc']['hostname']).to eq ['sol10-9.delivery.puppetlabs.net', expect(vm_req['solaris-10-sparc']['hostname']).to eq ['sol10-9.delivery.puppetlabs.net', 'sol10-10.delivery.puppetlabs.net']
'sol10-10.delivery.puppetlabs.net']
expect(vm_req['aix-7.1-power']['hostname']).to eq 'pe-aix-71-ci-acceptance.delivery.puppetlabs.net' expect(vm_req['aix-7.1-power']['hostname']).to eq 'pe-aix-71-ci-acceptance.delivery.puppetlabs.net'
end end
end end
@ -163,22 +162,22 @@ describe NonstandardPooler do
it 'raises an error if the user tries to modify an unsupported attribute' do it 'raises an error if the user tries to modify an unsupported attribute' do
stub_request(:put, 'https://nspooler.example.com/host/myfakehost') stub_request(:put, 'https://nspooler.example.com/host/myfakehost')
.with(body: { '{}' => true }, .with(:body => { '{}' => true },
headers: @auth_token_headers) :headers => @auth_token_headers)
.to_return(status: 200, body: '', headers: {}) .to_return(:status => 200, :body => '', :headers => {})
details = { lifetime: 12 } details = { :lifetime => 12 }
expect { NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', details) } expect { NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', details) }
.to raise_error(ModifyError) .to raise_error(ModifyError)
end end
it 'modifies the reason of a vm' do it 'modifies the reason of a vm' do
modify_request_body = { '{"reserved_for_reason":"testing"}' => nil } modify_request_body = { '{"reserved_for_reason":"testing"}' => true }
stub_request(:put, "#{@nspooler_url}/host/myfakehost") stub_request(:put, "#{@nspooler_url}/host/myfakehost")
.with(body: modify_request_body, .with(:body => modify_request_body,
headers: @auth_token_headers) :headers => @auth_token_headers)
.to_return(status: 200, body: '{"ok": true}', headers: {}) .to_return(:status => 200, :body => '{"ok": true}', :headers => {})
modify_hash = { reason: 'testing' } modify_hash = { :reason => 'testing' }
modify_req = NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', modify_hash) modify_req = NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', modify_hash)
expect(modify_req['ok']).to be true expect(modify_req['ok']).to be true
end end
@ -209,7 +208,7 @@ describe NonstandardPooler do
it 'prints the status' do it 'prints the status' do
stub_request(:get, "#{@nspooler_url}/status") stub_request(:get, "#{@nspooler_url}/status")
.to_return(status: 200, body: @status_response_body, headers: {}) .to_return(:status => 200, :body => @status_response_body, :headers => {})
status = NonstandardPooler.status(false, @nspooler_url) status = NonstandardPooler.status(false, @nspooler_url)
expect(status).to be_an_instance_of Hash expect(status).to be_an_instance_of Hash
@ -232,7 +231,7 @@ describe NonstandardPooler do
it 'prints the summary' do it 'prints the summary' do
stub_request(:get, "#{@nspooler_url}/summary") stub_request(:get, "#{@nspooler_url}/summary")
.to_return(status: 200, body: @status_response_body, headers: {}) .to_return(:status => 200, :body => @status_response_body, :headers => {})
summary = NonstandardPooler.summary(false, @nspooler_url) summary = NonstandardPooler.summary(false, @nspooler_url)
expect(summary).to be_an_instance_of Hash expect(summary).to be_an_instance_of Hash
@ -257,7 +256,7 @@ describe NonstandardPooler do
it 'makes a query about a vm' do it 'makes a query about a vm' do
stub_request(:get, "#{@nspooler_url}/host/sol10-11") stub_request(:get, "#{@nspooler_url}/host/sol10-11")
.to_return(status: 200, body: @query_response_body, headers: {}) .to_return(:status => 200, :body => @query_response_body, :headers => {})
query_req = NonstandardPooler.query(false, @nspooler_url, 'sol10-11') query_req = NonstandardPooler.query(false, @nspooler_url, 'sol10-11')
expect(query_req).to be_an_instance_of Hash expect(query_req).to be_an_instance_of Hash
@ -272,8 +271,8 @@ describe NonstandardPooler do
it 'deletes a single existing vm' do it 'deletes a single existing vm' do
stub_request(:delete, "#{@nspooler_url}/host/sol11-7") stub_request(:delete, "#{@nspooler_url}/host/sol11-7")
.with(headers: @auth_token_headers) .with(:headers => @auth_token_headers)
.to_return(status: 200, body: @delete_response_success, headers: {}) .to_return(:status => 200, :body => @delete_response_success, :headers => {})
request = NonstandardPooler.delete(false, @nspooler_url, 'sol11-7', 'token-value', nil) request = NonstandardPooler.delete(false, @nspooler_url, 'sol11-7', 'token-value', nil)
expect(request['sol11-7']['ok']).to be true expect(request['sol11-7']['ok']).to be true
@ -281,8 +280,8 @@ describe NonstandardPooler do
it 'does not delete a nonexistant vm' do it 'does not delete a nonexistant vm' do
stub_request(:delete, "#{@nspooler_url}/host/fakehost") stub_request(:delete, "#{@nspooler_url}/host/fakehost")
.with(headers: @auth_token_headers) .with(:headers => @auth_token_headers)
.to_return(status: 401, body: @delete_response_failure, headers: {}) .to_return(:status => 401, :body => @delete_response_failure, :headers => {})
request = NonstandardPooler.delete(false, @nspooler_url, 'fakehost', 'token-value', nil) request = NonstandardPooler.delete(false, @nspooler_url, 'fakehost', 'token-value', nil)
expect(request['fakehost']['ok']).to be false expect(request['fakehost']['ok']).to be false

View file

@ -15,7 +15,7 @@ describe Pooler do
it 'returns a hash with operating systems from the pooler' do it 'returns a hash with operating systems from the pooler' do
stub_request(:get, "#{@vmpooler_url}/vm") stub_request(:get, "#{@vmpooler_url}/vm")
.to_return(status: 200, body: @list_response_body, headers: {}) .to_return(:status => 200, :body => @list_response_body, :headers => {})
list = Pooler.list(false, @vmpooler_url, nil) list = Pooler.list(false, @vmpooler_url, nil)
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -23,7 +23,7 @@ describe Pooler do
it 'filters operating systems based on the filter param' do it 'filters operating systems based on the filter param' do
stub_request(:get, "#{@vmpooler_url}/vm") stub_request(:get, "#{@vmpooler_url}/vm")
.to_return(status: 200, body: @list_response_body, headers: {}) .to_return(:status => 200, :body => @list_response_body, :headers => {})
list = Pooler.list(false, @vmpooler_url, 'deb') list = Pooler.list(false, @vmpooler_url, 'deb')
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -32,7 +32,7 @@ describe Pooler do
it 'returns nothing if the filter does not match' do it 'returns nothing if the filter does not match' do
stub_request(:get, "#{@vmpooler_url}/vm") stub_request(:get, "#{@vmpooler_url}/vm")
.to_return(status: 200, body: @list_response_body, headers: {}) .to_return(:status => 200, :body => @list_response_body, :headers => {})
list = Pooler.list(false, @vmpooler_url, 'windows') list = Pooler.list(false, @vmpooler_url, 'windows')
expect(list).to be_an_instance_of Array expect(list).to be_an_instance_of Array
@ -48,8 +48,8 @@ describe Pooler do
it 'raises an AuthError if the token is invalid' do it 'raises an AuthError if the token is invalid' do
stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386") stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 401, body: '{"ok":false}', headers: {}) .to_return(:status => 401, :body => '{"ok":false}', :headers => {})
vm_hash = {} vm_hash = {}
vm_hash['debian-7-i386'] = 1 vm_hash['debian-7-i386'] = 1
@ -58,8 +58,8 @@ describe Pooler do
it 'retrieves a single vm with a token' do it 'retrieves a single vm with a token' do
stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386") stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @retrieve_response_body_single, headers: {}) .to_return(:status => 200, :body => @retrieve_response_body_single, :headers => {})
vm_hash = {} vm_hash = {}
vm_hash['debian-7-i386'] = 1 vm_hash['debian-7-i386'] = 1
@ -71,8 +71,8 @@ describe Pooler do
it 'retrieves a multiple vms with a token' do it 'retrieves a multiple vms with a token' do
stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386+debian-7-i386+centos-7-x86_64") stub_request(:post, "#{@vmpooler_url}/vm/debian-7-i386+debian-7-i386+centos-7-x86_64")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @retrieve_response_body_double, headers: {}) .to_return(:status => 200, :body => @retrieve_response_body_double, :headers => {})
vm_hash = {} vm_hash = {}
vm_hash['debian-7-i386'] = 2 vm_hash['debian-7-i386'] = 2
@ -89,11 +89,11 @@ describe Pooler do
let(:ondemand_response) { '{"ok":true,"request_id":"1234"}' } let(:ondemand_response) { '{"ok":true,"request_id":"1234"}' }
it 'retreives the vm with a token' do it 'retreives the vm with a token' do
stub_request(:post, "#{@vmpooler_url}/ondemandvm/debian-7-i386") stub_request(:post, "#{@vmpooler_url}/ondemandvm/debian-7-i386")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: ondemand_response, headers: {}) .to_return(:status => 200, :body => ondemand_response, :headers => {})
stub_request(:get, "#{@vmpooler_url}/ondemandvm/1234") stub_request(:get, "#{@vmpooler_url}/ondemandvm/1234")
.to_return(status: 200, body: @retrieve_response_body_single, headers: {}) .to_return(:status => 200, :body => @retrieve_response_body_single, :headers => {})
vm_hash = {} vm_hash = {}
vm_hash['debian-7-i386'] = 1 vm_hash['debian-7-i386'] = 1
@ -117,11 +117,11 @@ describe Pooler do
end end
it 'modifies the TTL of a vm' do it 'modifies the TTL of a vm' do
modify_hash = { lifetime: 12 } modify_hash = { :lifetime => 12 }
stub_request(:put, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6") stub_request(:put, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6")
.with(body: { '{"lifetime":12}' => nil }, .with(:body => { '{"lifetime":12}' => true },
headers: get_headers(content_type: 'application/x-www-form-urlencoded', token: 'mytokenfile')) :headers => { 'Content-Type' => 'application/x-www-form-urlencoded', 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @modify_response_body_success, headers: {}) .to_return(:status => 200, :body => @modify_response_body_success, :headers => {})
modify_req = Pooler.modify(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', modify_hash) modify_req = Pooler.modify(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', modify_hash)
expect(modify_req['ok']).to be true expect(modify_req['ok']).to be true
@ -136,8 +136,8 @@ describe Pooler do
it 'deletes a specified vm' do it 'deletes a specified vm' do
stub_request(:delete, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6") stub_request(:delete, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @delete_response_body_success, headers: {}) .to_return(:status => 200, :body => @delete_response_body_success, :headers => {})
expect(Pooler.delete(false, @vmpooler_url, ['fq6qlpjlsskycq6'], 'mytokenfile', nil)).to eq @delete_response expect(Pooler.delete(false, @vmpooler_url, ['fq6qlpjlsskycq6'], 'mytokenfile', nil)).to eq @delete_response
end end
@ -155,7 +155,7 @@ describe Pooler do
it 'prints the status' do it 'prints the status' do
stub_request(:get, "#{@vmpooler_url}/status") stub_request(:get, "#{@vmpooler_url}/status")
.to_return(status: 200, body: @status_response_body, headers: {}) .to_return(:status => 200, :body => @status_response_body, :headers => {})
status = Pooler.status(false, @vmpooler_url) status = Pooler.status(false, @vmpooler_url)
expect(status).to be_an_instance_of Hash expect(status).to be_an_instance_of Hash
@ -178,7 +178,7 @@ describe Pooler do
it 'makes a query about a vm' do it 'makes a query about a vm' do
stub_request(:get, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6") stub_request(:get, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6")
.to_return(status: 200, body: @query_response_body, headers: {}) .to_return(:status => 200, :body => @query_response_body, :headers => {})
query_req = Pooler.query(false, @vmpooler_url, 'fq6qlpjlsskycq6') query_req = Pooler.query(false, @vmpooler_url, 'fq6qlpjlsskycq6')
expect(query_req).to be_an_instance_of Hash expect(query_req).to be_an_instance_of Hash
@ -192,8 +192,8 @@ describe Pooler do
it 'makes a snapshot for a single vm' do it 'makes a snapshot for a single vm' do
stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/snapshot") stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/snapshot")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @snapshot_response_body, headers: {}) .to_return(:status => 200, :body => @snapshot_response_body, :headers => {})
snapshot_req = Pooler.snapshot(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile') snapshot_req = Pooler.snapshot(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile')
expect(snapshot_req['ok']).to be true expect(snapshot_req['ok']).to be true
@ -207,18 +207,15 @@ describe Pooler do
it 'makes a request to revert a vm from a snapshot' do it 'makes a request to revert a vm from a snapshot' do
stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/snapshot/dAfewKNfaweLKNve") stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/snapshot/dAfewKNfaweLKNve")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' })
.to_return(status: 200, body: @revert_response_body, headers: {}) .to_return(:status => 200, :body => @revert_response_body, :headers => {})
revert_req = Pooler.revert(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', 'dAfewKNfaweLKNve') revert_req = Pooler.revert(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', 'dAfewKNfaweLKNve')
expect(revert_req['ok']).to be true expect(revert_req['ok']).to be true
end end
it "doesn't make a request to revert a vm if snapshot is not provided" do it "doesn't make a request to revert a vm if snapshot is not provided" do
expect do expect { Pooler.revert(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', nil) }.to raise_error(RuntimeError, 'Snapshot SHA provided was nil, could not revert fq6qlpjlsskycq6')
Pooler.revert(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile',
nil)
end.to raise_error(RuntimeError, 'Snapshot SHA provided was nil, could not revert fq6qlpjlsskycq6')
end end
it 'raises a TokenError if no token was provided' do it 'raises a TokenError if no token was provided' do
@ -234,7 +231,7 @@ describe Pooler do
it 'makes a request to extend disk space of a vm' do it 'makes a request to extend disk space of a vm' do
stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/disk/12") stub_request(:post, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6/disk/12")
.with(headers: { 'X-Auth-Token' => 'mytokenfile' }).to_return(status: 200, body: @disk_response_body_success, headers: {}) .with(:headers => { 'X-Auth-Token' => 'mytokenfile' }). to_return(:status => 200, :body => @disk_response_body_success, :headers => {})
disk_req = Pooler.disk(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', 12) disk_req = Pooler.disk(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', 12)
expect(disk_req['ok']).to be true expect(disk_req['ok']).to be true

View file

@ -16,7 +16,7 @@ describe Service do
it 'prompts the user for their password and retrieves a token' do it 'prompts the user for their password and retrieves a token' do
config = { 'user' => 'first.last', 'url' => 'http://default.url' } config = { 'user' => 'first.last', 'url' => 'http://default.url' }
service = Service.new(MockOptions.new, config) service = Service.new(MockOptions.new, config)
allow($stdout).to receive(:puts).with('Enter your http://default.url service password:') allow(STDOUT).to receive(:puts).with('Enter your http://default.url service password:')
allow(Commander::UI).to(receive(:password) allow(Commander::UI).to(receive(:password)
.with('Enter your http://default.url service password:', '*') .with('Enter your http://default.url service password:', '*')
.and_return('hunter2')) .and_return('hunter2'))
@ -29,9 +29,9 @@ describe Service do
it 'prompts the user for their username and password if the username is unknown' do it 'prompts the user for their username and password if the username is unknown' do
config = { 'url' => 'http://default.url' } config = { 'url' => 'http://default.url' }
service = Service.new(MockOptions.new({}), config) service = Service.new(MockOptions.new({}), config)
allow($stdout).to receive(:puts).with 'Enter your http://default.url service username:' allow(STDOUT).to receive(:puts).with 'Enter your http://default.url service username:'
allow($stdout).to receive(:puts).with "\n" allow(STDOUT).to receive(:puts).with "\n"
allow($stdin).to receive(:gets).and_return('first.last') allow(STDIN).to receive(:gets).and_return('first.last')
allow(Commander::UI).to(receive(:password) allow(Commander::UI).to(receive(:password)
.with('Enter your http://default.url service password:', '*') .with('Enter your http://default.url service password:', '*')
.and_return('hunter2')) .and_return('hunter2'))
@ -59,16 +59,16 @@ describe Service do
it 'reports the status of a token' do it 'reports the status of a token' do
config = { config = {
'user' => 'first.last', 'user' => 'first.last',
'url' => 'http://default.url' 'url' => 'http://default.url',
} }
options = MockOptions.new('token' => 'token-value') options = MockOptions.new('token' => 'token-value')
service = Service.new(options, config) service = Service.new(options, config)
status = { status = {
'ok' => true, 'ok' => true,
'user' => config['user'], 'user' => config['user'],
'created' => '2017-09-22 02:04:18 +0000', 'created' => '2017-09-22 02:04:18 +0000',
'last_accessed' => '2017-09-22 02:04:28 +0000', 'last_accessed' => '2017-09-22 02:04:28 +0000',
'reserved_hosts' => [] 'reserved_hosts' => [],
} }
allow(Auth).to(receive(:token_status) allow(Auth).to(receive(:token_status)
.with(nil, config['url'], 'token-value') .with(nil, config['url'], 'token-value')

View file

@ -4,35 +4,24 @@ require 'spec_helper'
require 'vmfloaty/ssh' require 'vmfloaty/ssh'
class ServiceStub class ServiceStub
def retrieve(_verbose, os_types, _use_token, ondemand) def retrieve(_verbose, os_types, _use_token)
if os_types.keys[0] == 'abs_host_string' if os_types.keys[0] == 'abs_host_string'
return { return {
os_types.keys[0] => { 'hostname' => ['abs-hostname.delivery.puppetlabs.net'] }, os_types.keys[0] => { 'hostname' => ['abs-hostname.delivery.puppetlabs.net'] },
'ok' => true 'ok' => true,
}
elsif os_types.keys[0] == 'vmpooler_api_v2_host_string'
return {
os_types.keys[0] => { 'hostname' => ['vmpooler-v2-hostname.delivery.puppetlabs.net'] },
'ok' => true
}
else
return {
os_types.keys[0] => { 'hostname' => 'vmpooler-v1-hostname' },
'domain' => 'delivery.puppetlabs.net',
'ok' => true
} }
end end
{
os_types.keys[0] => { 'hostname' => 'vmpooler-hostname' },
'domain' => 'delivery.puppetlabs.net',
'ok' => true,
}
end end
def type def type
return 'abs' if os_types == 'abs_host_string' return 'abs' if os_types == 'abs_host_string'
return 'vmpooler' if os_types == 'vmpooler_api_v1_host_string' || os_types == 'vmpooler_api_v2_host_string' return 'vmpooler' if os_types == 'vmpooler_host_string'
end
def wait_for_request(verbose, requestid)
return true
end end
end end
@ -40,73 +29,21 @@ describe Ssh do
before :each do before :each do
end end
context "for pooled requests" do it 'gets a hostname string for abs' do
it 'gets a hostname string for abs' do verbose = false
verbose = false service = ServiceStub.new
service = ServiceStub.new host_os = 'abs_host_string'
host_os = 'abs_host_string' use_token = false
use_token = false cmd = Ssh.command_string(verbose, service, host_os, use_token)
cmd = Ssh.command_string(verbose, service, host_os, use_token) expect(cmd).to match(/ssh root@abs-hostname.delivery.puppetlabs.net/)
expect(cmd).to match(/ssh root@abs-hostname.delivery.puppetlabs.net/)
end
it 'gets a hostname string for vmpooler api v1' do
verbose = true
service = ServiceStub.new
host_os = 'vmpooler_api_v1_host_string'
use_token = false
cmd = Ssh.command_string(verbose, service, host_os, use_token)
expect(cmd).to match(/ssh root@vmpooler-v1-hostname.delivery.puppetlabs.net/)
end
it 'gets a hostname string for vmpooler api v2' do
verbose = false
service = ServiceStub.new
host_os = 'vmpooler_api_v2_host_string'
use_token = false
cmd = Ssh.command_string(verbose, service, host_os, use_token)
expect(cmd).to match(/ssh root@vmpooler-v2-hostname.delivery.puppetlabs.net/)
end
end end
context "for ondemand requests" do it 'gets a hostname string for vmpooler' do
let(:service) { ServiceStub.new } verbose = false
let(:url) { 'http://pooler.example.com' } service = ServiceStub.new
host_os = 'vmpooler_host_string'
it 'gets a hostname string for abs' do use_token = false
verbose = false cmd = Ssh.command_string(verbose, service, host_os, use_token)
host_os = 'abs_host_string' expect(cmd).to match(/ssh root@vmpooler-hostname.delivery.puppetlabs.net/)
use_token = false
ondemand = true
response = {'abs_host_string' => { 'hostname' => ['abs-hostname.delivery.puppetlabs.net']}}
allow(service).to receive(:url)
allow(service).to receive(:check_ondemandvm).and_return(response)
cmd = Ssh.command_string(verbose, service, host_os, use_token, ondemand)
expect(cmd).to match(/ssh root@abs-hostname.delivery.puppetlabs.net/)
end
it 'gets a hostname string for abs' do
verbose = false
host_os = 'vmpooler_api_v1_host_string'
use_token = false
ondemand = true
response = {'vmpooler_api_v1_host_string' => { 'hostname' => ['vmpooler_api_v1_host_string.delivery.puppetlabs.net']}}
allow(service).to receive(:url)
allow(service).to receive(:check_ondemandvm).and_return(response)
cmd = Ssh.command_string(verbose, service, host_os, use_token, ondemand)
expect(cmd).to match(/ssh root@vmpooler_api_v1_host_string.delivery.puppetlabs.net/)
end
it 'gets a hostname string for abs' do
verbose = false
host_os = 'vmpooler_api_v2_host_string'
use_token = false
ondemand = true
response = {'vmpooler_api_v2_host_string' => { 'hostname' => ['vmpooler_api_v2_host_string.delivery.puppetlabs.net']}}
allow(service).to receive(:url)
allow(service).to receive(:check_ondemandvm).and_return(response)
cmd = Ssh.command_string(verbose, service, host_os, use_token, ondemand)
expect(cmd).to match(/ssh root@vmpooler_api_v2_host_string.delivery.puppetlabs.net/)
end
end end
end end

View file

@ -13,7 +13,7 @@ end
describe Utils do describe Utils do
describe '#standardize_hostnames' do describe '#standardize_hostnames' do
before :each do before :each do
@vmpooler_api_v1_response_body = '{ @vmpooler_response_body = '{
"ok": true, "ok": true,
"domain": "delivery.mycompany.net", "domain": "delivery.mycompany.net",
"ubuntu-1610-x86_64": { "ubuntu-1610-x86_64": {
@ -23,15 +23,6 @@ describe Utils do
"hostname": "dlgietfmgeegry2" "hostname": "dlgietfmgeegry2"
} }
}' }'
@vmpooler_api_v2_response_body = '{
"ok": true,
"ubuntu-1610-x86_64": {
"hostname": ["gdoy8q3nckuob0i.delivery.mycompany.net", "ctnktsd0u11p9tm.delivery.mycompany.net"]
},
"centos-7-x86_64": {
"hostname": "dlgietfmgeegry2.delivery.mycompany.net"
}
}'
@nonstandard_response_body = '{ @nonstandard_response_body = '{
"ok": true, "ok": true,
"solaris-10-sparc": { "solaris-10-sparc": {
@ -43,23 +34,15 @@ describe Utils do
}' }'
end end
it 'formats a result from vmpooler v1 api into a hash of os to hostnames' do it 'formats a result from vmpooler into a hash of os to hostnames' do
result = Utils.standardize_hostnames(JSON.parse(@vmpooler_api_v1_response_body)) result = Utils.standardize_hostnames(JSON.parse(@vmpooler_response_body))
expect(result).to eq('centos-7-x86_64' => ['dlgietfmgeegry2.delivery.mycompany.net'], expect(result).to eq('centos-7-x86_64' => ['dlgietfmgeegry2.delivery.mycompany.net'],
'ubuntu-1610-x86_64' => ['gdoy8q3nckuob0i.delivery.mycompany.net', 'ubuntu-1610-x86_64' => ['gdoy8q3nckuob0i.delivery.mycompany.net', 'ctnktsd0u11p9tm.delivery.mycompany.net'])
'ctnktsd0u11p9tm.delivery.mycompany.net'])
end
it 'formats a result from vmpooler v2 api into a hash of os to hostnames' do
result = Utils.standardize_hostnames(JSON.parse(@vmpooler_api_v2_response_body))
expect(result).to eq('centos-7-x86_64' => ['dlgietfmgeegry2.delivery.mycompany.net'],
'ubuntu-1610-x86_64' => ['gdoy8q3nckuob0i.delivery.mycompany.net',
'ctnktsd0u11p9tm.delivery.mycompany.net'])
end end
it 'formats a result from the nonstandard pooler into a hash of os to hostnames' do it 'formats a result from the nonstandard pooler into a hash of os to hostnames' do
result = Utils.standardize_hostnames(JSON.parse(@nonstandard_response_body)) result = Utils.standardize_hostnames(JSON.parse(@nonstandard_response_body))
expect(result).to eq('solaris-10-sparc' => ['sol10-10.delivery.mycompany.net', 'sol10-11.delivery.mycompany.net'], expect(result).to eq('solaris-10-sparc' => ['sol10-10.delivery.mycompany.net', 'sol10-11.delivery.mycompany.net'],
'ubuntu-16.04-power8' => ['power8-ubuntu16.04-6.delivery.mycompany.net']) 'ubuntu-16.04-power8' => ['power8-ubuntu16.04-6.delivery.mycompany.net'])
end end
end end
@ -67,12 +50,12 @@ describe Utils do
describe '#format_host_output' do describe '#format_host_output' do
before :each do before :each do
@vmpooler_results = { @vmpooler_results = {
'centos-7-x86_64' => ['dlgietfmgeegry2.delivery.mycompany.net'], 'centos-7-x86_64' => ['dlgietfmgeegry2.delivery.mycompany.net'],
'ubuntu-1610-x86_64' => ['gdoy8q3nckuob0i.delivery.mycompany.net', 'ctnktsd0u11p9tm.delivery.mycompany.net'] 'ubuntu-1610-x86_64' => ['gdoy8q3nckuob0i.delivery.mycompany.net', 'ctnktsd0u11p9tm.delivery.mycompany.net'],
} }
@nonstandard_results = { @nonstandard_results = {
'solaris-10-sparc' => ['sol10-10.delivery.mycompany.net', 'sol10-11.delivery.mycompany.net'], 'solaris-10-sparc' => ['sol10-10.delivery.mycompany.net', 'sol10-11.delivery.mycompany.net'],
'ubuntu-16.04-power8' => ['power8-ubuntu16.04-6.delivery.mycompany.net'] 'ubuntu-16.04-power8' => ['power8-ubuntu16.04-6.delivery.mycompany.net'],
} }
@vmpooler_output = <<~OUT.chomp @vmpooler_output = <<~OUT.chomp
- dlgietfmgeegry2.delivery.mycompany.net (centos-7-x86_64) - dlgietfmgeegry2.delivery.mycompany.net (centos-7-x86_64)
@ -115,23 +98,23 @@ describe Utils do
describe '#get_service_config' do describe '#get_service_config' do
before :each do before :each do
@default_config = { @default_config = {
'url' => 'http://default.url', 'url' => 'http://default.url',
'user' => 'first.last.default', 'user' => 'first.last.default',
'token' => 'default-token' 'token' => 'default-token',
} }
@services_config = { @services_config = {
'services' => { 'services' => {
'vm' => { 'vm' => {
'url' => 'http://vmpooler.url', 'url' => 'http://vmpooler.url',
'user' => 'first.last.vmpooler', 'user' => 'first.last.vmpooler',
'token' => 'vmpooler-token' 'token' => 'vmpooler-token',
}, },
'ns' => { 'ns' => {
'url' => 'http://nspooler.url', 'url' => 'http://nspooler.url',
'user' => 'first.last.nspooler', 'user' => 'first.last.nspooler',
'token' => 'nspooler-token' 'token' => 'nspooler-token',
} },
} },
} }
end end
@ -143,26 +126,26 @@ describe Utils do
it 'allows selection by configured service key' do it 'allows selection by configured service key' do
config = @default_config.merge @services_config config = @default_config.merge @services_config
options = MockOptions.new(service: 'ns') options = MockOptions.new(:service => 'ns')
expect(Utils.get_service_config(config, options)).to include @services_config['services']['ns'] expect(Utils.get_service_config(config, options)).to include @services_config['services']['ns']
end end
it 'uses top-level service config values as defaults when configured service values are missing' do it 'uses top-level service config values as defaults when configured service values are missing' do
config = @default_config.merge @services_config config = @default_config.merge @services_config
config['services']['vm'].delete 'url' config['services']['vm'].delete 'url'
options = MockOptions.new(service: 'vm') options = MockOptions.new(:service => 'vm')
expect(Utils.get_service_config(config, options)['url']).to eq 'http://default.url' expect(Utils.get_service_config(config, options)['url']).to eq 'http://default.url'
end end
it "raises an error if passed a service name that hasn't been configured" do it "raises an error if passed a service name that hasn't been configured" do
config = @default_config.merge @services_config config = @default_config.merge @services_config
options = MockOptions.new(service: 'none') options = MockOptions.new(:service => 'none')
expect { Utils.get_service_config(config, options) }.to raise_error ArgumentError expect { Utils.get_service_config(config, options) }.to raise_error ArgumentError
end end
it 'prioritizes values passed as command line options over configuration options' do it 'prioritizes values passed as command line options over configuration options' do
config = @default_config config = @default_config
options = MockOptions.new(url: 'http://alternate.url', token: 'alternate-token') options = MockOptions.new(:url => 'http://alternate.url', :token => 'alternate-token')
expected = config.merge('url' => 'http://alternate.url', 'token' => 'alternate-token') expected = config.merge('url' => 'http://alternate.url', 'token' => 'alternate-token')
expect(Utils.get_service_config(config, options)).to include expected expect(Utils.get_service_config(config, options)).to include expected
end end
@ -199,15 +182,15 @@ describe Utils do
{ {
'template' => 'ubuntu-1604-x86_64', 'template' => 'ubuntu-1604-x86_64',
'lifetime' => 12, 'lifetime' => 12,
'running' => 9.66, 'running' => 9.66,
'state' => 'running', 'state' => 'running',
'ip' => '127.0.0.1', 'ip' => '127.0.0.1',
'domain' => domain 'domain' => domain,
} }
end end
it 'outputs fqdn for host' do it 'outputs fqdn for host' do
expect($stdout).to receive(:puts).with(fqdn) expect(STDOUT).to receive(:puts).with(fqdn)
subject subject
end end
@ -218,17 +201,17 @@ describe Utils do
let(:hostname) { 'sol11-9.delivery.mycompany.net' } let(:hostname) { 'sol11-9.delivery.mycompany.net' }
let(:host_data) do let(:host_data) do
{ {
'fqdn' => hostname, 'fqdn' => hostname,
'os_triple' => 'solaris-11-sparc', 'os_triple' => 'solaris-11-sparc',
'reserved_by_user' => 'first.last', 'reserved_by_user' => 'first.last',
'reserved_for_reason' => '', 'reserved_for_reason' => '',
'hours_left_on_reservation' => 35.89 'hours_left_on_reservation' => 35.89,
} }
end end
let(:fqdn) { hostname } # for nspooler these are the same let(:fqdn) { hostname } # for nspooler these are the same
it 'outputs fqdn for host' do it 'outputs fqdn for host' do
expect($stdout).to receive(:puts).with(fqdn) expect(STDOUT).to receive(:puts).with(fqdn)
subject subject
end end
@ -248,19 +231,19 @@ describe Utils do
{ {
'hostname' => fqdn, 'hostname' => fqdn,
'type' => template, 'type' => template,
'enging' => 'vmpooler' 'enging' => 'vmpooler',
} },
], ],
'request' => { 'request' => {
'job' => { 'job' => {
'id' => hostname 'id' => hostname,
} }
} },
} }
end end
it 'outputs fqdn for host' do it 'outputs fqdn for host' do
expect($stdout).to receive(:puts).with(fqdn) expect(STDOUT).to receive(:puts).with(fqdn)
subject subject
end end
@ -280,73 +263,7 @@ describe Utils do
subject { Utils.pretty_print_hosts(verbose, service, hostname, print_to_stderr) } subject { Utils.pretty_print_hosts(verbose, service, hostname, print_to_stderr) }
describe 'with vmpooler api v2 service' do describe 'with vmpooler service' do
let(:service) { Service.new(MockOptions.new, 'url' => url) }
let(:hostname) { 'mcpy42eqjxli9g2' }
let(:fqdn) { [hostname, 'delivery.puppetlabs.net'].join('.') }
let(:response_body) do
{
hostname => {
'template' => 'ubuntu-1604-x86_64',
'lifetime' => 12,
'running' => 9.66,
'state' => 'running',
'ip' => '127.0.0.1',
'fqdn' => fqdn
}
}
end
let(:default_output) { "- #{fqdn} (running, ubuntu-1604-x86_64, 9.66/12 hours)" }
it 'prints output with host fqdn, template and duration info' do
expect($stdout).to receive(:puts).with(default_output)
subject
end
context 'when tags are supplied' do
let(:hostname) { 'aiydvzpg23r415q' }
let(:response_body) do
{
hostname => {
'template' => 'redhat-7-x86_64',
'lifetime' => 48,
'running' => 7.67,
'state' => 'running',
'tags' => {
'user' => 'bob',
'role' => 'agent'
},
'ip' => '127.0.0.1',
'fqdn' => fqdn
}
}
end
it 'prints output with host fqdn, template, duration info, and tags' do
output = "- #{fqdn} (running, redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)"
expect($stdout).to receive(:puts).with(output)
subject
end
end
context 'when print_to_stderr option is true' do
let(:print_to_stderr) { true }
it 'outputs to stderr instead of stdout' do
expect($stderr).to receive(:puts).with(default_output)
subject
end
end
end
describe 'with vmpooler api v1 service' do
let(:service) { Service.new(MockOptions.new, 'url' => url) } let(:service) { Service.new(MockOptions.new, 'url' => url) }
let(:hostname) { 'mcpy42eqjxli9g2' } let(:hostname) { 'mcpy42eqjxli9g2' }
@ -358,10 +275,10 @@ describe Utils do
hostname => { hostname => {
'template' => 'ubuntu-1604-x86_64', 'template' => 'ubuntu-1604-x86_64',
'lifetime' => 12, 'lifetime' => 12,
'running' => 9.66, 'running' => 9.66,
'state' => 'running', 'state' => 'running',
'ip' => '127.0.0.1', 'ip' => '127.0.0.1',
'domain' => domain 'domain' => domain,
} }
} }
end end
@ -369,7 +286,7 @@ describe Utils do
let(:default_output) { "- #{fqdn} (running, ubuntu-1604-x86_64, 9.66/12 hours)" } let(:default_output) { "- #{fqdn} (running, ubuntu-1604-x86_64, 9.66/12 hours)" }
it 'prints output with host fqdn, template and duration info' do it 'prints output with host fqdn, template and duration info' do
expect($stdout).to receive(:puts).with(default_output) expect(STDOUT).to receive(:puts).with(default_output)
subject subject
end end
@ -381,14 +298,14 @@ describe Utils do
hostname => { hostname => {
'template' => 'redhat-7-x86_64', 'template' => 'redhat-7-x86_64',
'lifetime' => 48, 'lifetime' => 48,
'running' => 7.67, 'running' => 7.67,
'state' => 'running', 'state' => 'running',
'tags' => { 'tags' => {
'user' => 'bob', 'user' => 'bob',
'role' => 'agent' 'role' => 'agent',
}, },
'ip' => '127.0.0.1', 'ip' => '127.0.0.1',
'domain' => domain 'domain' => domain,
} }
} }
end end
@ -396,7 +313,7 @@ describe Utils do
it 'prints output with host fqdn, template, duration info, and tags' do it 'prints output with host fqdn, template, duration info, and tags' do
output = "- #{fqdn} (running, redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)" output = "- #{fqdn} (running, redhat-7-x86_64, 7.67/48 hours, user: bob, role: agent)"
expect($stdout).to receive(:puts).with(output) expect(STDOUT).to receive(:puts).with(output)
subject subject
end end
@ -406,7 +323,7 @@ describe Utils do
let(:print_to_stderr) { true } let(:print_to_stderr) { true }
it 'outputs to stderr instead of stdout' do it 'outputs to stderr instead of stdout' do
expect($stderr).to receive(:puts).with(default_output) expect(STDERR).to receive(:puts).with(default_output)
subject subject
end end
@ -420,11 +337,11 @@ describe Utils do
let(:response_body) do let(:response_body) do
{ {
hostname => { hostname => {
'fqdn' => hostname, 'fqdn' => hostname,
'os_triple' => 'solaris-11-sparc', 'os_triple' => 'solaris-11-sparc',
'reserved_by_user' => 'first.last', 'reserved_by_user' => 'first.last',
'reserved_for_reason' => '', 'reserved_for_reason' => '',
'hours_left_on_reservation' => 35.89 'hours_left_on_reservation' => 35.89,
} }
} }
end end
@ -432,7 +349,7 @@ describe Utils do
let(:default_output) { "- #{hostname} (solaris-11-sparc, 35.89h remaining)" } let(:default_output) { "- #{hostname} (solaris-11-sparc, 35.89h remaining)" }
it 'prints output with host, template, and time remaining' do it 'prints output with host, template, and time remaining' do
expect($stdout).to receive(:puts).with(default_output) expect(STDOUT).to receive(:puts).with(default_output)
subject subject
end end
@ -441,11 +358,11 @@ describe Utils do
let(:response_body) do let(:response_body) do
{ {
hostname => { hostname => {
'fqdn' => hostname, 'fqdn' => hostname,
'os_triple' => 'solaris-11-sparc', 'os_triple' => 'solaris-11-sparc',
'reserved_by_user' => 'first.last', 'reserved_by_user' => 'first.last',
'reserved_for_reason' => 'testing', 'reserved_for_reason' => 'testing',
'hours_left_on_reservation' => 35.89 'hours_left_on_reservation' => 35.89,
} }
} }
end end
@ -453,7 +370,7 @@ describe Utils do
it 'prints output with host, template, time remaining, and reason' do it 'prints output with host, template, time remaining, and reason' do
output = '- sol11-9.delivery.mycompany.net (solaris-11-sparc, 35.89h remaining, reason: testing)' output = '- sol11-9.delivery.mycompany.net (solaris-11-sparc, 35.89h remaining, reason: testing)'
expect($stdout).to receive(:puts).with(output) expect(STDOUT).to receive(:puts).with(output)
subject subject
end end
@ -463,7 +380,7 @@ describe Utils do
let(:print_to_stderr) { true } let(:print_to_stderr) { true }
it 'outputs to stderr instead of stdout' do it 'outputs to stderr instead of stdout' do
expect($stderr).to receive(:puts).with(default_output) expect(STDERR).to receive(:puts).with(default_output)
subject subject
end end
@ -475,7 +392,7 @@ describe Utils do
let(:hostname) { '1597952189390' } let(:hostname) { '1597952189390' }
let(:fqdn) { 'example-noun.delivery.mycompany.net' } let(:fqdn) { 'example-noun.delivery.mycompany.net' }
let(:fqdn_hostname) { 'example-noun' } let(:fqdn_hostname) {'example-noun'}
let(:template) { 'ubuntu-1604-x86_64' } let(:template) { 'ubuntu-1604-x86_64' }
# This seems to be the miminal stub response from ABS for the current output # This seems to be the miminal stub response from ABS for the current output
@ -487,14 +404,14 @@ describe Utils do
{ {
'hostname' => fqdn, 'hostname' => fqdn,
'type' => template, 'type' => template,
'engine' => 'vmpooler' 'engine' => 'vmpooler',
} },
], ],
'request' => { 'request' => {
'job' => { 'job' => {
'id' => hostname 'id' => hostname,
} }
} },
} }
} }
end end
@ -503,58 +420,58 @@ describe Utils do
let(:domain) { 'delivery.mycompany.net' } let(:domain) { 'delivery.mycompany.net' }
let(:response_body_vmpooler) do let(:response_body_vmpooler) do
{ {
fqdn_hostname => { fqdn_hostname => {
'template' => template, 'template' => template,
'lifetime' => 48, 'lifetime' => 48,
'running' => 7.67, 'running' => 7.67,
'state' => 'running', 'state' => 'running',
'tags' => { 'tags' => {
'user' => 'bob', 'user' => 'bob',
'role' => 'agent' 'role' => 'agent',
}, },
'ip' => '127.0.0.1', 'ip' => '127.0.0.1',
'domain' => domain 'domain' => domain,
} }
} }
end end
before(:each) do before(:each) do
allow(Utils).to receive(:get_vmpooler_service_config).and_return({ allow(Utils).to receive(:get_vmpooler_service_config).and_return({
'url' => 'http://vmpooler.example.com', 'url' => 'http://vmpooler.example.com',
'token' => 'krypto-knight' 'token' => 'krypto-knight'
}) })
allow(service).to receive(:query) allow(service).to receive(:query)
.with(anything, fqdn_hostname) .with(anything, fqdn_hostname)
.and_return(response_body_vmpooler) .and_return(response_body_vmpooler)
end end
let(:default_output_first_line) { "- [JobID:#{hostname}] <allocated>" } let(:default_output_first_line) { "- [JobID:#{hostname}] <allocated>" }
let(:default_output_second_line) { " - #{fqdn} (#{template})" } let(:default_output_second_line) { " - #{fqdn} (#{template})" }
it 'prints output with job id, host, and template' do it 'prints output with job id, host, and template' do
expect($stdout).to receive(:puts).with(default_output_first_line) expect(STDOUT).to receive(:puts).with(default_output_first_line)
expect($stdout).to receive(:puts).with(default_output_second_line) expect(STDOUT).to receive(:puts).with(default_output_second_line)
subject subject
end end
it 'prints more information when vmpooler_fallback is set output with job id, host, template, lifetime, user and role' do it 'prints more information when vmpooler_fallback is set output with job id, host, template, lifetime, user and role' do
fallback = { 'vmpooler_fallback' => 'vmpooler' } fallback = {'vmpooler_fallback' => 'vmpooler'}
service.config.merge! fallback service.config.merge! fallback
default_output_second_line = " - #{fqdn} (running, #{template}, 7.67/48 hours, user: bob, role: agent)" default_output_second_line=" - #{fqdn} (running, #{template}, 7.67/48 hours, user: bob, role: agent)"
expect($stdout).to receive(:puts).with(default_output_first_line) expect(STDOUT).to receive(:puts).with(default_output_first_line)
expect($stdout).to receive(:puts).with(default_output_second_line) expect(STDOUT).to receive(:puts).with(default_output_second_line)
subject subject
end end
it 'prints DESTROYED and hostname when destroyed' do it 'prints in red when destroyed' do
fallback = { 'vmpooler_fallback' => 'vmpooler' } fallback = {'vmpooler_fallback' => 'vmpooler'}
service.config.merge! fallback service.config.merge! fallback
response_body_vmpooler[fqdn_hostname]['state'] = 'destroyed' response_body_vmpooler[fqdn_hostname]['state'] = "destroyed"
default_output_second_line = " - DESTROYED #{fqdn}" default_output_second_line_red=" - #{fqdn} (destroyed, #{template}, 7.67/48 hours, user: bob, role: agent)".red
expect($stdout).to receive(:puts).with(default_output_first_line) expect(STDOUT).to receive(:puts).with(default_output_first_line)
expect($stdout).to receive(:puts).with(default_output_second_line) expect(STDOUT).to receive(:puts).with(default_output_second_line_red)
subject subject
end end
@ -563,8 +480,8 @@ describe Utils do
let(:print_to_stderr) { true } let(:print_to_stderr) { true }
it 'outputs to stderr instead of stdout' do it 'outputs to stderr instead of stdout' do
expect($stderr).to receive(:puts).with(default_output_first_line) expect(STDERR).to receive(:puts).with(default_output_first_line)
expect($stderr).to receive(:puts).with(default_output_second_line) expect(STDERR).to receive(:puts).with(default_output_second_line)
subject subject
end end
@ -577,34 +494,34 @@ describe Utils do
let(:hostname) { '1597952189390' } let(:hostname) { '1597952189390' }
let(:fqdn) { 'this-noun.delivery.mycompany.net' } let(:fqdn) { 'this-noun.delivery.mycompany.net' }
let(:fqdn_ns) { 'that-noun.delivery.mycompany.net' } let(:fqdn_ns) { 'that-noun.delivery.mycompany.net' }
let(:fqdn_hostname) { 'this-noun' } let(:fqdn_hostname) {'this-noun'}
let(:fqdn_ns_hostname) { 'that-noun' } let(:fqdn_ns_hostname) {'that-noun'}
let(:template) { 'ubuntu-1604-x86_64' } let(:template) { 'ubuntu-1604-x86_64' }
let(:template_ns) { 'solaris-10-sparc' } let(:template_ns) { 'solaris-10-sparc' }
# This seems to be the miminal stub response from ABS for the current output # This seems to be the miminal stub response from ABS for the current output
let(:response_body) do let(:response_body) do
{ {
hostname => { hostname => {
'state' => 'allocated', 'state' => 'allocated',
'allocated_resources' => [ 'allocated_resources' => [
{ {
'hostname' => fqdn, 'hostname' => fqdn,
'type' => template, 'type' => template,
'engine' => 'vmpooler' 'engine' => 'vmpooler',
}, },
{ {
'hostname' => fqdn_ns, 'hostname' => fqdn_ns,
'type' => template_ns, 'type' => template_ns,
'engine' => 'nspooler' 'engine' => 'nspooler',
} },
], ],
'request' => { 'request' => {
'job' => { 'job' => {
'id' => hostname 'id' => hostname,
} }
},
} }
}
} }
end end
@ -612,29 +529,29 @@ describe Utils do
let(:domain) { 'delivery.mycompany.net' } let(:domain) { 'delivery.mycompany.net' }
let(:response_body_vmpooler) do let(:response_body_vmpooler) do
{ {
fqdn_hostname => { fqdn_hostname => {
'template' => template, 'template' => template,
'lifetime' => 48, 'lifetime' => 48,
'running' => 7.67, 'running' => 7.67,
'state' => 'running', 'state' => 'running',
'tags' => { 'tags' => {
'user' => 'bob', 'user' => 'bob',
'role' => 'agent' 'role' => 'agent',
}, },
'ip' => '127.0.0.1', 'ip' => '127.0.0.1',
'domain' => domain 'domain' => domain,
} }
} }
end end
before(:each) do before(:each) do
allow(Utils).to receive(:get_vmpooler_service_config).and_return({ allow(Utils).to receive(:get_vmpooler_service_config).and_return({
'url' => 'http://vmpooler.example.com', 'url' => 'http://vmpooler.example.com',
'token' => 'krypto-knight' 'token' => 'krypto-knight'
}) })
allow(service).to receive(:query) allow(service).to receive(:query)
.with(anything, fqdn_hostname) .with(anything, fqdn_hostname)
.and_return(response_body_vmpooler) .and_return(response_body_vmpooler)
end end
let(:default_output_first_line) { "- [JobID:#{hostname}] <allocated>" } let(:default_output_first_line) { "- [JobID:#{hostname}] <allocated>" }
@ -642,9 +559,9 @@ describe Utils do
let(:default_output_third_line) { " - #{fqdn_ns} (#{template_ns})" } let(:default_output_third_line) { " - #{fqdn_ns} (#{template_ns})" }
it 'prints output with job id, host, and template' do it 'prints output with job id, host, and template' do
expect($stdout).to receive(:puts).with(default_output_first_line) expect(STDOUT).to receive(:puts).with(default_output_first_line)
expect($stdout).to receive(:puts).with(default_output_second_line) expect(STDOUT).to receive(:puts).with(default_output_second_line)
expect($stdout).to receive(:puts).with(default_output_third_line) expect(STDOUT).to receive(:puts).with(default_output_third_line)
subject subject
end end
@ -653,9 +570,9 @@ describe Utils do
let(:print_to_stderr) { true } let(:print_to_stderr) { true }
it 'outputs to stderr instead of stdout' do it 'outputs to stderr instead of stdout' do
expect($stderr).to receive(:puts).with(default_output_first_line) expect(STDERR).to receive(:puts).with(default_output_first_line)
expect($stderr).to receive(:puts).with(default_output_second_line) expect(STDERR).to receive(:puts).with(default_output_second_line)
expect($stderr).to receive(:puts).with(default_output_third_line) expect(STDERR).to receive(:puts).with(default_output_third_line)
subject subject
end end
@ -669,59 +586,54 @@ describe Utils do
config = { config = {
'user' => 'foo', 'user' => 'foo',
'services' => { 'services' => {
'myabs' => { 'myabs' => {
'url' => 'http://abs.com', 'url' => 'http://abs.com',
'token' => 'krypto-night', 'token' => 'krypto-night',
'type' => 'abs' 'type' => 'abs'
} }
} }
} }
allow(Conf).to receive(:read_config).and_return(config) allow(Conf).to receive(:read_config).and_return(config)
expect do expect{Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])}.to raise_error(ArgumentError)
Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])
end.to raise_error(ArgumentError)
end end
it 'returns an error if the vmpooler_fallback is setup but cannot be found' do it 'returns an error if the vmpooler_fallback is setup but cannot be found' do
config = { config = {
'user' => 'foo', 'user' => 'foo',
'services' => { 'services' => {
'myabs' => { 'myabs' => {
'url' => 'http://abs.com', 'url' => 'http://abs.com',
'token' => 'krypto-night', 'token' => 'krypto-night',
'type' => 'abs', 'type' => 'abs',
'vmpooler_fallback' => 'myvmpooler' 'vmpooler_fallback' => 'myvmpooler'
} }
} }
} }
allow(Conf).to receive(:read_config).and_return(config) allow(Conf).to receive(:read_config).and_return(config)
expect do expect{Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])}.to raise_error(ArgumentError, /myvmpooler/)
Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])
end.to raise_error(ArgumentError,
/myvmpooler/)
end end
it 'returns the vmpooler_fallback config' do it 'returns the vmpooler_fallback config' do
config = { config = {
'user' => 'foo', 'user' => 'foo',
'services' => { 'services' => {
'myabs' => { 'myabs' => {
'url' => 'http://abs.com', 'url' => 'http://abs.com',
'token' => 'krypto-night', 'token' => 'krypto-night',
'type' => 'abs', 'type' => 'abs',
'vmpooler_fallback' => 'myvmpooler' 'vmpooler_fallback' => 'myvmpooler'
}, },
'myvmpooler' => { 'myvmpooler' => {
'url' => 'http://vmpooler.com', 'url' => 'http://vmpooler.com',
'token' => 'krypto-knight' 'token' => 'krypto-knight'
} }
} }
} }
allow(Conf).to receive(:read_config).and_return(config) allow(Conf).to receive(:read_config).and_return(config)
expect(Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])).to include({ expect(Utils.get_vmpooler_service_config(config['services']['myabs']['vmpooler_fallback'])).to include({
'url' => 'http://vmpooler.com', 'url' => 'http://vmpooler.com',
'token' => 'krypto-knight', 'token' => 'krypto-knight',
'user' => 'foo', 'user' => 'foo',
'type' => 'vmpooler' 'type' => 'vmpooler'
}) })
end end
end end
end end

View file

@ -8,9 +8,12 @@ Gem::Specification.new do |s|
s.version = Vmfloaty::VERSION s.version = Vmfloaty::VERSION
s.authors = [ s.authors = [
'Brian Cain', 'Brian Cain',
'Puppet' 'Puppet',
]
s.email = [
'brianccain@gmail.com',
'dio-gems@puppet.com',
] ]
s.email = 'info@puppet.com'
s.license = 'Apache-2.0' s.license = 'Apache-2.0'
s.homepage = 'https://github.com/puppetlabs/vmfloaty' s.homepage = 'https://github.com/puppetlabs/vmfloaty'
s.description = 'A helper tool for vmpooler to help you stay afloat' s.description = 'A helper tool for vmpooler to help you stay afloat'
@ -21,6 +24,7 @@ Gem::Specification.new do |s|
s.test_files = Dir['spec/**/*'] s.test_files = Dir['spec/**/*']
s.require_path = 'lib' s.require_path = 'lib'
s.add_dependency 'commander', '>= 4.4.3', '< 4.7.0' s.add_dependency 'colorize', '~> 0.8.1'
s.add_dependency 'faraday', '~> 1.5', '>= 1.5.1' s.add_dependency 'commander', '>= 4.4.3', '< 4.6.0'
s.add_dependency 'faraday', '~> 0.17.0'
end end