├── Gemfile ├── spec ├── spec_helper.rb ├── unit │ └── rackspace_base_spec.rb ├── integration_spec_helper.rb ├── integration │ └── integration_spec.rb └── cassettes │ └── v1 │ ├── should_list_images.yml │ └── should_list_server_flavors.yml ├── lib ├── knife-rackspace │ └── version.rb └── chef │ └── knife │ ├── rackspace_network_list.rb │ ├── rackspace_network_delete.rb │ ├── rackspace_network_create.rb │ ├── rackspace_image_list.rb │ ├── rackspace_flavor_list.rb │ ├── rackspace_server_list.rb │ ├── rackspace_server_delete.rb │ ├── rackspace_base.rb │ └── rackspace_server_create.rb ├── .gitignore ├── .chef └── knife.rb ├── knife-rackspace.gemspec ├── Rakefile ├── .travis.yml ├── CHANGELOG.md ├── LICENSE └── README.rdoc /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path('../../lib', __FILE__) 2 | require 'chef/knife/bootstrap' 3 | require 'chef/knife/rackspace_base' 4 | -------------------------------------------------------------------------------- /lib/knife-rackspace/version.rb: -------------------------------------------------------------------------------- 1 | module Knife 2 | module Rackspace 3 | VERSION = '0.10.1' 4 | MAJOR, MINOR, TINY = VERSION.split('.') 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .rake_tasks~ 2 | tags 3 | coverage 4 | rdoc 5 | pkg 6 | test/tmp 7 | test/version_tmp 8 | tmp 9 | pkg 10 | *.gem 11 | *.rbc 12 | lib/bundler/man 13 | spec/reports 14 | .config 15 | InstalledFiles 16 | .bundle 17 | .rackspace_cloud_credentials* 18 | *.lock 19 | 20 | # YARD artifacts 21 | .yardoc 22 | _yardoc 23 | doc/ 24 | 25 | .DS_Store 26 | Icon? 27 | 28 | # Thumbnails 29 | ._* 30 | 31 | # Files that might appear on external disk 32 | .Spotlight-V100 33 | .Trashes 34 | 35 | *.swp 36 | *.swo 37 | -------------------------------------------------------------------------------- /.chef/knife.rb: -------------------------------------------------------------------------------- 1 | current_dir = File.dirname(__FILE__) 2 | log_level :info 3 | log_location STDOUT 4 | #node_name "knife-rackspace" 5 | #client_key "#{current_dir}/knife-rackspace.pem" 6 | #validation_client_name "knife-rackspace-validator" 7 | #validation_key "#{current_dir}/knife-rackspace-validator.pem" 8 | #chef_server_url "https://api.opscode.com/organizations/knife-rackspace" 9 | #cache_type 'basicfile' 10 | #cache_options( :path => "#{ENV['home']}/.chef/checksums" ) 11 | #cookbook_path ["#{current_dir}/../cookbooks"] 12 | 13 | knife[:rackspace_api_username] = "#{ENV['OS_USERNAME']}" 14 | knife[:rackspace_api_key] = "#{ENV['OS_PASSWORD']}" 15 | 16 | #https_proxy 'https://localhost:8888' 17 | #knife[:ssl_verify_peer] = false 18 | 19 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_network_list.rb: -------------------------------------------------------------------------------- 1 | require 'chef/knife/rackspace_base' 2 | 3 | class Chef 4 | class Knife 5 | class RackspaceNetworkList < Knife 6 | 7 | include Knife::RackspaceBase 8 | 9 | banner "knife rackspace network list (options)" 10 | 11 | def run 12 | if version_one? 13 | ui.error "Networks are not supported in v1" 14 | exit 1 15 | else 16 | networks_list = [ 17 | ui.color('Label', :bold), 18 | ui.color('CIDR', :bold), 19 | ui.color('ID', :bold) 20 | ] 21 | end 22 | connection.networks.sort_by(&:id).each do |network| 23 | networks_list << network.label 24 | networks_list << network.cidr 25 | networks_list << network.id.to_s 26 | end 27 | puts ui.list(networks_list, :uneven_columns_across, 3) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_network_delete.rb: -------------------------------------------------------------------------------- 1 | require 'chef/knife/rackspace_base' 2 | 3 | class Chef 4 | class Knife 5 | class RackspaceNetworkDelete < Knife 6 | 7 | include Knife::RackspaceBase 8 | 9 | banner "knife rackspace network delete NETWORK_ID [NETWORK_ID] (options)" 10 | 11 | def run 12 | if version_one? 13 | ui.error "Networks are not supported in v1" 14 | exit 1 15 | else 16 | @name_args.each do |net_id| 17 | network = connection.networks.get(net_id) 18 | unless(network) 19 | ui.error "Could not locate network: #{net_id}" 20 | exit 1 21 | end 22 | msg_pair("Network ID", network.id) 23 | msg_pair("Label", network.label) 24 | msg_pair("CIDR", network.cidr) 25 | 26 | puts "\n" 27 | confirm("Do you really want to delete this network") 28 | 29 | network.destroy 30 | 31 | ui.warn("Deleted network #{network.id}") 32 | end 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/unit/rackspace_base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'chef/knife/rackspace_base' 4 | require 'chef/knife' 5 | 6 | class RackspaceBaseTester < Chef::Knife 7 | include Chef::Knife::RackspaceBase 8 | end 9 | 10 | describe "auth_endpoint" do 11 | it "should select the custom endpoint if specified" do 12 | tester = RackspaceBaseTester.new 13 | 14 | test_url = "http://test-url.com" 15 | Chef::Config[:knife][:rackspace_auth_url] = test_url 16 | Chef::Config[:knife][:rackspace_region] = :ord 17 | 18 | tester.auth_endpoint.should == test_url 19 | end 20 | 21 | [:dfw, :ord, :syd].each do |region| 22 | it "should pick the US endpoint if the region is #{region}" do 23 | tester = RackspaceBaseTester.new 24 | Chef::Config[:knife][:rackspace_auth_url] = nil 25 | Chef::Config[:knife][:rackspace_region] = region 26 | 27 | tester.auth_endpoint.should == ::Fog::Rackspace::US_AUTH_ENDPOINT 28 | end 29 | end 30 | 31 | it "should pick the UK end point if the region is :lon" do 32 | tester = RackspaceBaseTester.new 33 | Chef::Config[:knife][:rackspace_auth_url] = nil 34 | Chef::Config[:knife][:rackspace_region] = 'lon' 35 | 36 | tester.auth_endpoint.should == ::Fog::Rackspace::UK_AUTH_ENDPOINT 37 | end 38 | end -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_network_create.rb: -------------------------------------------------------------------------------- 1 | require 'chef/knife/rackspace_base' 2 | 3 | class Chef 4 | class Knife 5 | class RackspaceNetworkCreate < Knife 6 | 7 | include Knife::RackspaceBase 8 | 9 | banner "knife rackspace network create (options)" 10 | 11 | option :label, 12 | :short => "-L LABEL", 13 | :long => "--label LABEL", 14 | :description => "Label for the network", 15 | :required => true 16 | 17 | option :cidr, 18 | :short => "-C CIDR", 19 | :long => "--cidr CIDR", 20 | :description => "CIDR for the network", 21 | :required => true 22 | 23 | def run 24 | if version_one? 25 | ui.error "Networks are not supported in v1" 26 | exit 1 27 | else 28 | networks_list = [ 29 | ui.color('Label', :bold), 30 | ui.color('CIDR', :bold), 31 | ui.color('ID', :bold) 32 | ] 33 | end 34 | options = {} 35 | [:cidr, :label].each do |key| 36 | options[key] = config[key] 37 | end 38 | net = connection.networks.create(options) 39 | 40 | msg_pair("Network ID", net.id) 41 | msg_pair("Label", net.label) 42 | msg_pair("CIDR", net.cidr) 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /knife-rackspace.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "knife-rackspace/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "knife-rackspace" 7 | s.version = Knife::Rackspace::VERSION 8 | s.version = "#{s.version}-alpha-#{ENV['TRAVIS_BUILD_NUMBER']}" if ENV['TRAVIS'] 9 | s.has_rdoc = true 10 | s.authors = ["Adam Jacob","Seth Chisamore", "Matt Ray","Rackspace Developers","JJ Asghar"] 11 | s.email = ["adam@chef.io","schisamo@chef.io", "matt@chef.io","jj@chef.io"] 12 | s.homepage = "https://docs.chef.io/plugin_knife_rackspace.html" 13 | s.summary = "Rackspace Support for Chef's Knife Command" 14 | s.description = s.summary 15 | s.extra_rdoc_files = ["README.rdoc", "LICENSE" ] 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 20 | s.add_dependency "knife-windows" 21 | s.add_dependency "fog", '>= 1.22' 22 | s.add_dependency "chef", ">= 0.10.10" 23 | s.require_paths = ["lib"] 24 | 25 | s.add_development_dependency "knife-dsl" 26 | s.add_development_dependency "rspec" 27 | s.add_development_dependency "vcr" 28 | s.add_development_dependency "ansi" 29 | s.add_development_dependency "rake" 30 | end 31 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_image_list.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Seth Chisamore () 3 | # Copyright:: Copyright (c) 2011 Opscode, Inc. 4 | # License:: Apache License, Version 2.0 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | require 'chef/knife/rackspace_base' 20 | 21 | class Chef 22 | class Knife 23 | class RackspaceImageList < Knife 24 | 25 | include Knife::RackspaceBase 26 | 27 | banner "knife rackspace image list (options)" 28 | 29 | def run 30 | image_list = [ 31 | ui.color('ID', :bold), 32 | ui.color('Name', :bold) 33 | ] 34 | 35 | connection.images.sort_by(&:name).each do |image| 36 | image_list << image.id.to_s 37 | image_list << image.name 38 | end 39 | 40 | puts ui.list(image_list, :uneven_columns_across, 2) 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Adam Jacob () 3 | # Author:: Daniel DeLeo () 4 | # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'bundler' 21 | Bundler::GemHelper.install_tasks 22 | 23 | require 'rspec/core/rake_task' 24 | RSpec::Core::RakeTask.new(:spec) 25 | task :default => [:credentials, :spec, 'integration:live'] 26 | 27 | task :credentials do 28 | if ENV['TRAVIS_SECURE_ENV_VARS'] == 'false' 29 | puts "Setting vars" 30 | ENV['OS_USERNAME'] = '_RAX_USERNAME_' 31 | ENV['OS_PASSWORD'] = '_RAX_PASSWORD_' 32 | ENV['RS_TENANT_ID'] = '000000' 33 | ENV['RS_CDN_TENANT_NAME'] = '_CDN-TENANT-NAME_' 34 | end 35 | fail "Not all required variables detected" unless ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['RS_CDN_TENANT_NAME'] && ENV['RS_TENANT_ID'] 36 | end 37 | 38 | namespace :integration do 39 | desc 'Run the integration tests' 40 | RSpec::Core::RakeTask.new(:test) do |t| 41 | t.pattern = 'spec/integration/**' 42 | end 43 | 44 | desc 'Run the integration tests live (no VCR cassettes)' 45 | task :live do 46 | unless ENV['TRAVIS'] == 'true' && ENV['TRAVIS_SECURE_ENV_VARS'] == 'false' 47 | ENV['INTEGRATION_TESTS'] = 'live' 48 | Rake::Task['integration:test'].invoke 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_flavor_list.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Seth Chisamore () 3 | # Copyright:: Copyright (c) 2011-2012 Opscode, Inc. 4 | # License:: Apache License, Version 2.0 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | require 'chef/knife/rackspace_base' 20 | 21 | class Chef 22 | class Knife 23 | class RackspaceFlavorList < Knife 24 | 25 | include Knife::RackspaceBase 26 | 27 | banner "knife rackspace flavor list (options)" 28 | 29 | def run 30 | if version_one? 31 | flavor_list = [ 32 | ui.color('ID', :bold), 33 | ui.color('Name', :bold), 34 | ui.color('Architecture', :bold), 35 | ui.color('RAM', :bold), 36 | ui.color('Disk', :bold) 37 | ] 38 | else 39 | flavor_list = [ 40 | ui.color('ID', :bold), 41 | ui.color('Name', :bold), 42 | ui.color('VCPUs', :bold), 43 | ui.color('RAM', :bold), 44 | ui.color('Disk', :bold) 45 | ] 46 | end 47 | connection.flavors.sort_by(&:id).each do |flavor| 48 | bits = flavor.respond_to?(:bits) ? "#{flavor.bits.to_s}-bit" : "" 49 | 50 | flavor_list << flavor.id.to_s 51 | flavor_list << flavor.name 52 | flavor_list << bits if version_one? 53 | flavor_list << flavor.vcpus.to_s unless version_one? 54 | flavor_list << "#{flavor.ram.to_s}" 55 | flavor_list << "#{flavor.disk.to_s} GB" 56 | end 57 | puts ui.list(flavor_list, :uneven_columns_across, 5) 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2 4 | - 2.1 5 | - 2.0.0 6 | env: 7 | global: 8 | - excon_debug: true 9 | - secure: |- 10 | eEsikE/p2yz7/cFvCN/NOoljxBqjzsTWnKC7iZ+fEGGsyhKVJgWn4AasBusZ 11 | mhtQcOqwakRulzVc+EZN4pqWHgaMC7SnSwhqRU5u1E+BPI4iWNsu+7rjiXhE 12 | cJK1vE8YodgsgRDQ6evZVQLkwJpRk0qq2tM2LDqpzvy2MeQJIGc= 13 | - secure: |- 14 | V3ohIIF3I8lD05zTUs2nu+CcIzBYcvt1c1euRJ+SPcAH493b4cPquw1NZNFy 15 | WDIW+1qDQi1DXr8C3Yq8bL4+pY66SukHtxyLhx0V26lGUvI8naq3IqageBQK 16 | pkb2zZwVYO0a5mLEKOI/7omExBVHDxxX9Bw45vCHLKId3Wt21HE= 17 | - secure: |- 18 | OyKQU1muVBijz2/EkLUgBWbwPKG2UqRhIfpB1ZFkfdQ/06+Vaf82ZEQk3DvY 19 | 2lYFrzvSN1yWrKTMU3XES/dPlVlH87LDOrRhNhgW/NeHhC5BzdwrtvBm08RN 20 | 64ACuFG8fch9zIbx2VTkyLV8xsFXPPSaKMbEXrnikLwqnl5M8PQ= 21 | - secure: |- 22 | DoDVG0HwFg2a7Fj72tlxb8KJto+cBEh7J9YQZ35hK2cmeTsBAcZ4oSOUeAFg 23 | s2MvBhX0man0zjYPStbL1vcpuS1Ecea3kGzefG0lYhHAzvK7wqqRqhKNFsnd 24 | FPEVgZrcj3/Lc7mlkbigZouDM7BJLQbMGOv/KOS6f3nYzIhkOfE= 25 | - secure: |- 26 | SB4aoB5BCqqSFMpxJvN031tikc7VzXGX6PaOIngu5h3M9k3Qmkuvel8oQISb 27 | fhcbsmuA0EKlaCvjQsgXFoUvUE6UnPCc7h2816fEAEz7FrRF1Q1mnbZ2V/kG 28 | PtPYcPl4ZH4VxwAD+6kTtbl1aCTP8nKXTFXlKlrPAawpS7ef0B8= 29 | - secure: |- 30 | J01xNjFaqlwzin59fpvgKkp49p5VI128cFvM3pxvlErPLnjWE9kJ4NKzzznv 31 | tVc12zVat/twxepvjSzg88b0q4Ks6P0Ovy0LeQCFUkva/jiBQuGukByR3joU 32 | xuAFiCssBoaZEEKlN69n/zhihFxG/0z8Tn4h9pgAkSAyAq8UZJ0= 33 | - secure: |- 34 | W7NIurlDI/LtO27N5Yv9i2i/TLvwSL6L5bF0yJMtPNsL21xbcqBkcFY+0PEU 35 | 2jIzA6Ib861UACb9Xh45tXmY/zuUHQ/otuIdAwocawulxBjrTuNUDo58ZVEv 36 | GzvTdFIaOWczTTvBcaNy9msenXiRBQTWriMFR0uPKIH/mYGF3Ew= 37 | - secure: |- 38 | RQDTTLjob/9p+9XpcpYo4VaQSVvVbbHtUcpVyTXcnHwMq3WJzXXBoj/9iFxA 39 | Uupx9IhP0gZhX6kzcm5BG+oKTYAxTQkf2tRCRkVMBFCJKreER1SuSDVvljdV 40 | KLMfTbC5qwXox78PtD23BjO5k8hCJCSHfs0XuQ5y7k1mMFjM4ok= 41 | deploy: 42 | provider: rubygems 43 | api_key: 44 | secure: YeHeF7cuLuN3lHJQNQ4jpgfhaHGuB861cF6dzoyGPzAi/PO3wmTZfDNG27iI3zCe3CPviDSPiK4v14SQA1Xq3UtvSmeE+zcX/PxYsjNp7EQPn8J6fq2DfjmhYU5ECXnojbTkoh2HIM29YXBjxS8VlSTFDHYx0oV6uMZFgrzSLrI= 45 | on: 46 | tags: true 47 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_server_list.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Adam Jacob () 3 | # Copyright:: Copyright (c) 2009 Opscode, Inc. 4 | # License:: Apache License, Version 2.0 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | require 'chef/knife/rackspace_base' 20 | 21 | class Chef 22 | class Knife 23 | class RackspaceServerList < Knife 24 | 25 | include Knife::RackspaceBase 26 | 27 | banner "knife rackspace server list (options)" 28 | 29 | def run 30 | $stdout.sync = true 31 | 32 | server_list = [ 33 | ui.color('Instance ID', :bold), 34 | ui.color('Name', :bold), 35 | ui.color('Public IP', :bold), 36 | ui.color('Private IP', :bold), 37 | ui.color('Flavor', :bold), 38 | ui.color('Image', :bold), 39 | ui.color('State', :bold) 40 | ] 41 | connection.servers.all.each do |server| 42 | server = connection.servers.get(server.id) 43 | server_list << server.id.to_s 44 | server_list << server.name 45 | server_list << ip_address(server, 'public') 46 | server_list << ip_address(server, 'private') 47 | server_list << (server.flavor_id == nil ? "" : server.flavor_id.to_s) 48 | server_list << (server.image_id == nil ? "" : server.image_id.to_s) 49 | server_list << begin 50 | case server.state.downcase 51 | when 'deleted','suspended' 52 | ui.color(server.state.downcase, :red) 53 | when 'build','unknown' 54 | ui.color(server.state.downcase, :yellow) 55 | else 56 | ui.color(server.state.downcase, :green) 57 | end 58 | end 59 | end 60 | puts ui.list(server_list, :uneven_columns_across, 7) 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.10.1 2 | * Support new chef-vault bootrap flags (--bootstrap-vault-file, -bootstrap-vault-json, and --bootstrap-vault-item) 3 | 4 | ## v0.10.0 5 | * KNIFE-498 knife rackspace uses direct TCP connection on port 22 to verify SSHD 6 | * Update Windows bootstrapping instructions in the README 7 | * Fix warning for deprecated :keypair for :key_name 8 | 9 | ## v0.9.3 10 | * KNIFE-497 Create server command does not honor timeout parameter 11 | 12 | ## v0.9.2 13 | * KNIFE-480 Add support for user-data 14 | * --secret-file support for bootstrap 15 | 16 | ## v0.9.1 17 | * KNIFE-460 Remove extraneous flavor reloads 18 | * KNIFE-459 Add support for config-drive 19 | * KNIFE-440 fix two minor typos in the ui.error message 20 | * use {public_ip_address}.xip.io instead of {public_ip_address}.rs-cloud.xip.io 21 | 22 | ## v0.9.0 23 | * KNIFE-398 support secret/secret_file in knife.rb 24 | * KNIFE-420 Add --ssh-keypair for using ssh keys already registered with nova. 25 | * KNIFE-437 remove default region and make region required 26 | * replace static.cloud-ips with xip (cloud-ips was deprecated https://community.rackspace.com/general/f/34/t/623) 27 | * updated Fog dependency to 1.16 28 | 29 | ## v0.8.4 30 | * KNIFE-408 TypeError: wrong argument type Symbol (expected Module) 31 | 32 | ## v0.8.2 33 | * KNIFE-335 Wait for RackConnect and/or Service Level automation before bootstrapping 34 | * KNIFE-366 Allow arbitrary bootstrap networks 35 | * KNIFE-399 update knife rackspace to support string based flavor ids 36 | * Fixing issue with bootstrapping Windows server 37 | * Fog 1.16 updates 38 | 39 | ## v0.8.0 40 | * KNIFE-68 enable ability to modify ssh port number 41 | * KNIFE-180 include option to pass :disk_config option to fog for new node bootstrap 42 | * KNIFE-312 updated to reflect new configuration options in Fog 1.10.1 43 | * KNIFE-314 provisioning First Gen Cloud Server is broken 44 | * KNIFE-315 fixed DEPRECATION warnings related to use of old rackpace_auth_url and removed rackspace_endpoint 45 | 46 | ## v0.7.0 47 | * KNIFE_RACKSPACE-32 Ensure hint file is created to improve Ohai detection. 48 | * KNIFE-181 correct mixed use of 'rackspace_auth_url' and 'rackspace_api_auth_url'. Only 'rackspace_auth_url' is correct. 49 | * KNIFE-182 default to Rackspace Open Cloud (v2) 50 | * KNIFE-267 Rackspace server create with networks 51 | * KNIFE-271 Enable winrm authentication on knife-rackspace 52 | * KNIFE-281 pass https_proxy and http_proxy setting onto fog; added ssl_verify_peer setting to disable certificate validation 53 | * KNIFE-282 Add the ability to inject files on server creation 54 | * KNIFE-289 Add Integration Tests 55 | 56 | * KNOWN ISSUES: KNIFE-296 knife-windows overrides -x option with winrm-user 57 | 58 | ## v0.6.2 59 | * bump release to fix permission issues inside the gem 60 | 61 | ## v0.6.0 62 | * KNIFE_RACKSPACE-39 support for Rackspace Open Cloud (v2) 63 | * server list puts the name in second column 64 | * flavor list supports VCPUs for v2 65 | * server delete for v2 will attempt the name when purging since we set the name 66 | * docs updated to reflect all of the regions and APIs supported 67 | 68 | ## v0.5.16 69 | * KNIFE_RACKSPACE-36 Changed to code to use IP address for bootstrapping 70 | * KNIFE_RACKSPACE-38 Support the -P --purge option 71 | * Refactored to use msg_pair method like other knife plugins with eye on eventual base class. 72 | * KNIFE_RACKSPACE-29 Support private network to connect to for bootstrap 73 | * KNIFE_RACKSPACE-40 Support for disabling host key checking 74 | * Added the 'unknown' state to `rackspace server list`, appeared transitory 75 | 76 | ## v0.5.14 77 | * KNIFE_RACKSPACE-25 version bump to match knife-ec2's dependencies 78 | * KNIFE_RACKSPACE-33 chef-full is new default 79 | * updated authors 80 | * Fix of small typo "backspace" > "rackspace". 81 | * KNIFE_RACKSPACE-31 chef dependency needed, add explicit gem deps 82 | * KNIFE_RACKSPACE-7 switch to uneven_columns_across for prettier output 83 | * updated for rackspace_api_username and the correct current image number for Ubuntu 10.04 LTS 84 | * KNIFE-RACKSPACE-26 fog doesn't provide cores enumeration anymore 85 | * updated copyright and removed trailing comma 86 | * KNIFE_RACKSPACE-30 Make use of --json-attributes option for knife 87 | bootstrap. 88 | 89 | ## v0.5.12 90 | * remove dependency on net-ssh and net-ssh-multi..neither is access directly in plugin 91 | * KNIFE_RACKSPACE-18: Increase net-ssh-multi dependecy to 1.1.0 92 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_server_delete.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Adam Jacob () 3 | # Author:: Matt Ray () 4 | # Copyright:: Copyright (c) 2009-2012 Opscode, Inc. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'chef/knife/rackspace_base' 21 | 22 | # These two are needed for the '--purge' deletion case 23 | require 'chef/node' 24 | require 'chef/api_client' 25 | 26 | class Chef 27 | class Knife 28 | class RackspaceServerDelete < Knife 29 | 30 | include Knife::RackspaceBase 31 | 32 | banner "knife rackspace server delete SERVER_ID [SERVER_ID] (options)" 33 | 34 | option :purge, 35 | :short => "-P", 36 | :long => "--purge", 37 | :boolean => true, 38 | :default => false, 39 | :description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the Rackspace node itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)." 40 | 41 | option :chef_node_name, 42 | :short => "-N NAME", 43 | :long => "--node-name NAME", 44 | :description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option." 45 | 46 | # Extracted from Chef::Knife.delete_object, because it has a 47 | # confirmation step built in... By specifying the '--purge' 48 | # flag (and also explicitly confirming the server destruction!) 49 | # the user is already making their intent known. It is not 50 | # necessary to make them confirm two more times. 51 | def destroy_item(klass, name, type_name) 52 | begin 53 | object = klass.load(name) 54 | object.destroy 55 | ui.warn("Deleted #{type_name} #{name}") 56 | rescue Net::HTTPServerException 57 | ui.warn("Could not find a #{type_name} named #{name} to delete!") 58 | end 59 | end 60 | 61 | def run 62 | @name_args.each do |instance_id| 63 | begin 64 | server = connection.servers.get(instance_id) 65 | msg_pair("Instance ID", server.id.to_s) 66 | msg_pair("Host ID", server.host_id) 67 | msg_pair("Name", server.name) 68 | msg_pair("Flavor", server.flavor.name) 69 | msg_pair("Image", server.image.name) if server.image 70 | msg_pair("Public IP Address", ip_address(server, 'public')) 71 | msg_pair("Private IP Address", ip_address(server, 'private')) 72 | 73 | puts "\n" 74 | confirm("Do you really want to delete this server") 75 | 76 | server.destroy 77 | 78 | ui.warn("Deleted server #{server.id}") 79 | 80 | if config[:purge] 81 | if version_one? 82 | thing_to_delete = config[:chef_node_name] || instance_id 83 | destroy_item(Chef::Node, thing_to_delete, "node") 84 | destroy_item(Chef::ApiClient, thing_to_delete, "client") 85 | else 86 | #v2 nodes may be named automatically 87 | thing_to_delete = config[:chef_node_name] || server.name 88 | destroy_item(Chef::Node, thing_to_delete, "node") 89 | destroy_item(Chef::ApiClient, thing_to_delete, "client") 90 | end 91 | else 92 | ui.warn("Corresponding node and client for the #{instance_id} server were not deleted and remain registered with the Chef Server") 93 | end 94 | 95 | rescue NoMethodError 96 | ui.error("Could not locate server '#{instance_id}'.") 97 | end 98 | end 99 | end 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /spec/integration_spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'vcr' 3 | require 'ansi/code' 4 | require 'ansi/diff' 5 | 6 | Chef::Config[:knife][:rackspace_api_username] = "#{ENV['OS_USERNAME']}" 7 | Chef::Config[:knife][:rackspace_api_key] = "#{ENV['OS_PASSWORD']}" 8 | Chef::Config[:knife][:ssl_verify_peer] = false 9 | # Chef::Config[:knife][:rackspace_version] = "#{ENV['RS_VERSION']}" 10 | 11 | VCR.configure do |c| 12 | c.cassette_library_dir = 'spec/cassettes' 13 | c.hook_into :excon 14 | c.configure_rspec_metadata! 15 | 16 | # Sensitive data 17 | c.filter_sensitive_data('_RAX_USERNAME_') { Chef::Config[:knife][:rackspace_api_username] } 18 | c.filter_sensitive_data('_RAX_PASSWORD_') { Chef::Config[:knife][:rackspace_api_key] } 19 | c.filter_sensitive_data('_CDN-TENANT-NAME_') { ENV['RS_CDN_TENANT_NAME'] } 20 | c.filter_sensitive_data('000000') { ENV['RS_TENANT_ID'] } 21 | 22 | c.before_record do |interaction| 23 | # Sensitive data 24 | filter_headers(interaction, /X-\w*-Token/, '_ONE-TIME-TOKEN_') 25 | 26 | # Transient data (trying to avoid unnecessary cassette churn) 27 | filter_headers(interaction, 'X-Compute-Request-Id', '_COMPUTE-REQUEST-ID_') 28 | filter_headers(interaction, 'X-Varnish', '_VARNISH-REQUEST-ID_') 29 | 30 | # Throw away build state - just makes server.wait_for loops really long during replay 31 | begin 32 | json = JSON.parse(interaction.response.body) 33 | if json['server']['status'] == 'BUILD' 34 | # Ignoring interaction because server is in BUILD state 35 | interaction.ignore! 36 | end 37 | rescue 38 | end 39 | end 40 | 41 | c.before_playback do | interaction | 42 | interaction.filter!('_TENANT-ID_', '0000000') 43 | end 44 | 45 | c.default_cassette_options = { 46 | # :record => :none, 47 | # Ignores cache busting parameters. 48 | :match_requests_on => [:host, :path] 49 | } 50 | c.default_cassette_options.merge!({:record => :all}) if ENV['INTEGRATION_TESTS'] == 'live' 51 | end 52 | 53 | def filter_headers(interaction, pattern, placeholder) 54 | [interaction.request.headers, interaction.response.headers].each do | headers | 55 | sensitive_tokens = headers.select{|key| key.to_s.match(pattern)} 56 | sensitive_tokens.each do |key, value| 57 | headers[key] = placeholder 58 | end 59 | end 60 | end 61 | 62 | RSpec.configure do |c| 63 | # so we can use :vcr rather than :vcr => true; 64 | # in RSpec 3 this will no longer be necessary. 65 | c.treat_symbols_as_metadata_keys_with_true_values = true 66 | end 67 | 68 | def clean_output(output) 69 | output = ANSI.unansi(output) 70 | output.gsub!(/\s+$/,'') 71 | output.gsub!("\e[0G", '') 72 | output 73 | end 74 | 75 | RSpec::Matchers.define :match_output do |expected_output| 76 | match do |actual_output| 77 | clean_output(actual_output) == expected_output.strip 78 | end 79 | # Nice when it works, but has ANSI::Diff has some bugs that prevent it from showing any output 80 | failure_message_for_should do |actual_output| 81 | buffer = StringIO.new 82 | buffer.puts clean_output(actual_output) 83 | buffer.puts 84 | buffer.puts expected_output 85 | buffer.string 86 | # output = clean_output actual_output 87 | # ANSI::Diff.new(output, expected_output) 88 | end 89 | description do 90 | 'Compare actual and expected output, ignoring ansi color and trailing whitespace' 91 | end 92 | end 93 | 94 | def server_list 95 | stdout, stderr, status = knife_capture('rackspace server list') 96 | status == 0 ? stdout : stderr 97 | end 98 | 99 | def capture_instance_data(stdout, labels = {}) 100 | result = {} 101 | labels.each do | key, label | 102 | result[key] = clean_output(stdout).match(/^#{label}: (.*)$/)[1] 103 | end 104 | result 105 | end 106 | 107 | # Ideally this belongs in knife-dsl, but it causes a scoping conflict with knife.rb. 108 | # See https://github.com/chef-workflow/knife-dsl/issues/2 109 | def knife_capture(command, args=[], input=nil) 110 | null = Gem.win_platform? ? File.open('NUL:', 'r') : File.open('/dev/null', 'r') 111 | 112 | if defined? Pry 113 | Pry.config.input = STDIN 114 | Pry.config.output = STDOUT 115 | end 116 | 117 | warn = $VERBOSE 118 | $VERBOSE = nil 119 | old_stderr, old_stdout, old_stdin = $stderr, $stdout, $stdin 120 | 121 | $stderr = StringIO.new('', 'r+') 122 | $stdout = StringIO.new('', 'r+') 123 | $stdin = input ? StringIO.new(input, 'r') : null 124 | $VERBOSE = warn 125 | 126 | status = Chef::Knife::DSL::Support.run_knife(command, args) 127 | return $stdout.string, $stderr.string, status 128 | ensure 129 | warn = $VERBOSE 130 | $VERBOSE = nil 131 | $stderr = old_stderr 132 | $stdout = old_stdout 133 | $stdin = old_stdin 134 | $VERBOSE = warn 135 | null.close 136 | end 137 | -------------------------------------------------------------------------------- /spec/integration/integration_spec.rb: -------------------------------------------------------------------------------- 1 | # require 'integration_spec_helper' 2 | # require 'fog' 3 | # require 'knife/dsl' 4 | # require 'chef/knife/rackspace_server_create' 5 | # # include Chef::Knife::DSL 6 | # 7 | # [:v1, :v2].each do |api| 8 | # describe api do 9 | # before(:each) do 10 | # Chef::Config[:knife][:rackspace_version] = api.to_s #v2 by default 11 | # Chef::Config[:knife][:rackspace_region] = :iad 12 | # 13 | # Chef::Knife::Bootstrap.any_instance.stub(:run) 14 | # Chef::Knife::RackspaceServerCreate.any_instance.stub(:tcp_test_ssh).with(anything).and_return(true) 15 | # end 16 | # 17 | # it 'should list server flavors', :vcr do 18 | # stdout, stderr, status = knife_capture('rackspace flavor list') 19 | # status.should be(0), "Non-zero exit code.\n#{stdout}\n#{stderr}" 20 | # 21 | # expected_output = { 22 | # :v1 => """ 23 | # ID Name Architecture RAM Disk 24 | # 1 256 server 64-bit 256 10 GB 25 | # 2 512 server 64-bit 512 20 GB 26 | # 3 1GB server 64-bit 1024 40 GB 27 | # 4 2GB server 64-bit 2048 80 GB 28 | # 5 4GB server 64-bit 4096 160 GB 29 | # 6 8GB server 64-bit 8192 320 GB 30 | # 7 15.5GB server 64-bit 15872 620 GB 31 | # 8 30GB server 64-bit 30720 1200 GB 32 | # """, 33 | # :v2 => """ 34 | # ID Name VCPUs RAM Disk 35 | # 2 512MB Standard Instance 1 512 20 GB 36 | # 3 1GB Standard Instance 1 1024 40 GB 37 | # 4 2GB Standard Instance 2 2048 80 GB 38 | # 5 4GB Standard Instance 2 4096 160 GB 39 | # 6 8GB Standard Instance 4 8192 320 GB 40 | # 7 15GB Standard Instance 6 15360 620 GB 41 | # 8 30GB Standard Instance 8 30720 1200 GB 42 | # performance1-1 1 GB Performance 1 1024 20 GB 43 | # performance1-2 2 GB Performance 2 2048 40 GB 44 | # performance1-4 4 GB Performance 4 4096 40 GB 45 | # performance1-8 8 GB Performance 8 8192 40 GB 46 | # performance2-120 120 GB Performance 32 122880 40 GB 47 | # performance2-15 15 GB Performance 4 15360 40 GB 48 | # performance2-30 30 GB Performance 8 30720 40 GB 49 | # performance2-60 60 GB Performance 16 61440 40 GB 50 | # performance2-90 90 GB Performance 24 92160 40 GB 51 | # """} 52 | # stdout = ANSI.unansi stdout 53 | # stdout.should match_output(expected_output[api]) 54 | # end 55 | # 56 | # it 'should list images', :vcr do 57 | # sample_image = { 58 | # :v1 => 'Ubuntu 12.04 LTS', 59 | # :v2 => 'Ubuntu 12.04 LTS (Precise Pangolin)' 60 | # } 61 | # 62 | # stdout, stderr, status = knife_capture('rackspace image list') 63 | # status.should be(0), "Non-zero exit code.\n#{stdout}\n#{stderr}" 64 | # stdout = clean_output(stdout) 65 | # stdout.should match /^ID\s*Name\s*$/ 66 | # stdout.should include sample_image[api] 67 | # end 68 | # 69 | # it 'should manage servers', :vcr do 70 | # pending "The test works, but I'm in the process of cleaning up sensitive data in the cassettes" 71 | # 72 | # image = { 73 | # :v1 => '112', 74 | # :v2 => 'e4dbdba7-b2a4-4ee5-8e8f-4595b6d694ce' 75 | # } 76 | # flavor = 2 77 | # server_list.should_not include 'test-node' 78 | # 79 | # args = %W{rackspace server create -I #{image[api]} -f #{flavor} -N test-node -S test-server} 80 | # stdout, stderr, status = knife_capture(args) 81 | # status.should be(0), "Non-zero exit code.\n#{stdout}\n#{stderr}" 82 | # instance_data = capture_instance_data(stdout, { 83 | # :name => 'Name', 84 | # :instance_id => 'Instance ID', 85 | # :public_ip => 'Public IP Address', 86 | # :private_ip => 'Private IP Address' 87 | # }) 88 | # 89 | # # Wanted to assert active state, but got build during test 90 | # server_list.should match /#{instance_data[:instance_id]}\s*#{instance_data[:name]}\s*#{instance_data[:public_ip]}\s*#{instance_data[:private_ip]}\s*#{flavor}\s*#{image}/ 91 | # 92 | # args = %W{rackspace server delete #{instance_data[:instance_id]} -y} 93 | # stdout, stderr, status = knife_capture(args) 94 | # status.should be(0), "Non-zero exit code.\n#{stdout}\n#{stderr}" 95 | # 96 | # # Need to deal with deleting vs deleted states before we can check this 97 | # # server_list.should_not match /#{instance_data[:instance_id]}\s*#{instance_data[:name]}\s*#{instance_data[:public_ip]}\s*#{instance_data[:private_ip]}\s*#{flavor}\s*#{image}/ 98 | # end 99 | # end 100 | # end 101 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_base.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Seth Chisamore () 3 | # Copyright:: Copyright (c) 2011-2013 Opscode, Inc. 4 | # License:: Apache License, Version 2.0 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | require 'chef/knife' 20 | require 'fog' 21 | 22 | class Chef 23 | class Knife 24 | module RackspaceBase 25 | 26 | # :nodoc: 27 | # Would prefer to do this in a rational way, but can't be done b/c of 28 | # Mixlib::CLI's design :( 29 | def self.included(includer) 30 | includer.class_eval do 31 | 32 | deps do 33 | require 'fog' 34 | require 'net/ssh/multi' 35 | require 'readline' 36 | require 'chef/json_compat' 37 | end 38 | 39 | option :rackspace_api_key, 40 | :short => "-K KEY", 41 | :long => "--rackspace-api-key KEY", 42 | :description => "Your rackspace API key", 43 | :proc => Proc.new { |key| Chef::Config[:knife][:rackspace_api_key] = key } 44 | 45 | option :rackspace_username, 46 | :short => "-A USERNAME", 47 | :long => "--rackspace-username USERNAME", 48 | :description => "Your rackspace API username", 49 | :proc => Proc.new { |username| Chef::Config[:knife][:rackspace_username] = username } 50 | 51 | option :rackspace_version, 52 | :long => '--rackspace-version VERSION', 53 | :description => 'Rackspace Cloud Servers API version', 54 | :default => "v2", 55 | :proc => Proc.new { |version| Chef::Config[:knife][:rackspace_version] = version } 56 | 57 | option :rackspace_auth_url, 58 | :long => "--rackspace-auth-url URL", 59 | :description => "Your rackspace API auth url", 60 | :proc => Proc.new { |url| Chef::Config[:knife][:rackspace_auth_url] = url } 61 | 62 | option :rackspace_region, 63 | :long => "--rackspace-region REGION", 64 | :description => "Your rackspace region", 65 | :proc => Proc.new { |region| Chef::Config[:knife][:rackspace_region] = region } 66 | 67 | option :file, 68 | :long => '--file DESTINATION-PATH=SOURCE-PATH', 69 | :description => 'File to inject on node', 70 | :proc => Proc.new {|arg| 71 | Chef::Config[:knife][:file] ||= [] 72 | Chef::Config[:knife][:file] << arg 73 | } 74 | end 75 | end 76 | 77 | def connection 78 | Chef::Log.debug("version #{Chef::Config[:knife][:rackspace_version]} (config)") 79 | Chef::Log.debug("version #{config[:rackspace_version]} (cli)") 80 | Chef::Log.debug("rackspace_api_key #{Chef::Config[:knife][:rackspace_api_key]}") 81 | Chef::Log.debug("rackspace_username #{Chef::Config[:knife][:rackspace_username]}") 82 | Chef::Log.debug("rackspace_api_username #{Chef::Config[:knife][:rackspace_api_username]}") 83 | Chef::Log.debug("rackspace_auth_url #{Chef::Config[:knife][:rackspace_auth_url]}") 84 | Chef::Log.debug("rackspace_auth_url #{config[:rackspace_api_auth_url]}") 85 | Chef::Log.debug("rackspace_auth_url #{auth_endpoint} (using)") 86 | Chef::Log.debug("rackspace_region #{Chef::Config[:knife][:rackspace_region]}") 87 | Chef::Log.debug("rackspace_region #{config[:rackspace_region]}") 88 | 89 | if version_one? 90 | Chef::Log.debug("rackspace v1") 91 | region_warning_for_v1 92 | @connection ||= begin 93 | connection = Fog::Compute.new(connection_params({ 94 | :version => 'v1' 95 | })) 96 | end 97 | else 98 | Chef::Log.debug("rackspace v2") 99 | @connection ||= begin 100 | connection = Fog::Compute.new(connection_params({ 101 | :version => 'v2' 102 | })) 103 | end 104 | end 105 | end 106 | 107 | def region_warning_for_v1 108 | if Chef::Config[:knife][:rackspace_region] || config[:rackspace_region] 109 | Chef::Log.warn("Ignoring the rackspace_region parameter as it is only supported for Next Gen Cloud Servers (v2)") 110 | end 111 | end 112 | 113 | def connection_params(options={}) 114 | unless locate_config_value(:rackspace_region) 115 | ui.error "Please specify region via the command line using the --rackspace-region switch or add a knife[:rackspace_region] = REGION to your knife file." 116 | exit 1 117 | end 118 | 119 | hash = options.merge({ 120 | :provider => 'Rackspace', 121 | :rackspace_api_key => Chef::Config[:knife][:rackspace_api_key], 122 | :rackspace_username => (Chef::Config[:knife][:rackspace_username] || Chef::Config[:knife][:rackspace_api_username]), 123 | :rackspace_auth_url => auth_endpoint, 124 | :rackspace_region => locate_config_value(:rackspace_region) 125 | }) 126 | 127 | hash[:connection_options] ||= {} 128 | Chef::Log.debug("https_proxy #{ Chef::Config[:https_proxy] || ""} (config)") 129 | Chef::Log.debug("http_proxy #{ Chef::Config[:http_proxy] || ""} (config)") 130 | if Chef::Config.has_key?(:https_proxy) || Chef::Config.has_key?(:http_proxy) 131 | hash[:connection_options] = {:proxy => Chef::Config[:https_proxy] || Chef::Config[:http_proxy] } 132 | end 133 | Chef::Log.debug("using proxy #{hash[:connection_options][:proxy] || ""} (config)") 134 | Chef::Log.debug("ssl_verify_peer #{Chef::Config[:knife].has_key?(:ssl_verify_peer) ? Chef::Config[:knife][:ssl_verify_peer] : ""} (config)") 135 | hash[:connection_options][:ssl_verify_peer] = Chef::Config[:knife][:ssl_verify_peer] if Chef::Config[:knife].has_key?(:ssl_verify_peer) 136 | 137 | hash 138 | end 139 | 140 | def auth_endpoint 141 | url = locate_config_value(:rackspace_auth_url) 142 | return url if url 143 | (locate_config_value(:rackspace_region) == 'lon') ? ::Fog::Rackspace::UK_AUTH_ENDPOINT : ::Fog::Rackspace::US_AUTH_ENDPOINT 144 | end 145 | 146 | def locate_config_value(key) 147 | key = key.to_sym 148 | Chef::Config[:knife][key] || config[key] 149 | end 150 | 151 | def msg_pair(label, value, color=:cyan) 152 | if value && !value.to_s.empty? 153 | puts "#{ui.color(label, color)}: #{value}" 154 | end 155 | end 156 | 157 | def ip_address(server, network='public') 158 | if version_one? 159 | case network 160 | when 'public'; v1_public_ip(server) 161 | when 'private'; v1_private_ip(server) 162 | else raise NotImplementedError 163 | end 164 | else 165 | if network == 'public' && v2_access_ip(server) != "" 166 | v2_access_ip(server) 167 | else 168 | v2_ip_address(server, network) 169 | end 170 | end 171 | end 172 | 173 | def public_dns_name(server) 174 | if public_ip_address = ip_address(server, 'public') 175 | @public_dns_name ||= begin 176 | Resolv.getname(public_ip_address) 177 | rescue 178 | "#{public_ip_address}.xip.io" 179 | end 180 | end 181 | end 182 | 183 | private 184 | 185 | def version_one? 186 | rackspace_api_version == 'v1' 187 | end 188 | 189 | def rackspace_api_version 190 | version = locate_config_value(:rackspace_version) || 'v2' 191 | version.downcase 192 | end 193 | 194 | def v1_public_ip(server) 195 | server.public_ip_address == nil ? "" : server.public_ip_address 196 | end 197 | 198 | def v1_private_ip(server) 199 | server.addresses["private"].first == nil ? "" : server.addresses["private"].first 200 | end 201 | 202 | def v2_ip_address(server, network) 203 | network_ips = server.addresses[network] 204 | extract_ipv4_address(network_ips) if network_ips 205 | end 206 | 207 | def v2_access_ip(server) 208 | server.access_ipv4_address == nil ? "" : server.access_ipv4_address 209 | end 210 | 211 | def extract_ipv4_address(ip_addresses) 212 | address = ip_addresses.select { |ip| ip["version"] == 4 }.first 213 | address ? address["addr"] : "" 214 | end 215 | end 216 | end 217 | end 218 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = Knife Rackspace 2 | 3 | {Build Status}[https://travis-ci.org/chef/knife-rackspace] 4 | 5 | = DESCRIPTION: 6 | 7 | This is the official Opscode Knife plugin for Rackspace Cloud Servers. This plugin gives knife the ability to create, bootstrap, and manage servers on all the regions for Rackspace Cloud Servers. 8 | 9 | = INSTALLATION: 10 | 11 | Be sure you are running the latest version Chef. Versions earlier than 0.10.0 don't support plugins: 12 | 13 | gem install chef 14 | 15 | This plugin is distributed as a Ruby Gem. To install it, run: 16 | 17 | gem install knife-rackspace 18 | 19 | Depending on your system's configuration, you may need to run this command with root privileges. 20 | 21 | Ensure only the latest knife-rackspace gem and no other is installed. In some cases having older versions of the gem 22 | will cause the new OpenStack functionality not to function properly. To check: 23 | 24 | $> gem list --local | grep knife-rackspace 25 | knife-rackspace (0.6.2, 0.5.12) 26 | $> gem uninstall knife-rackspace -v "= 0.5.12" 27 | Successfully uninstalled knife-rackspace-0.5.12 28 | $> gem list --local | grep knife-rackspace 29 | knife-rackspace (0.6.2) 30 | 31 | 32 | = CONFIGURATION: 33 | 34 | In order to communicate with the Rackspace Cloud API you will have to tell Knife about your Username and API Key. The easiest way to accomplish this is to create some entries in your knife.rb file: 35 | 36 | knife[:rackspace_api_username] = "Your Rackspace API username" 37 | knife[:rackspace_api_key] = "Your Rackspace API Key" 38 | 39 | If your knife.rb file will be checked into a SCM system (ie readable by others) you may want to read the values from environment variables: 40 | 41 | knife[:rackspace_api_username] = "#{ENV['RACKSPACE_USERNAME']}" 42 | knife[:rackspace_api_key] = "#{ENV['RACKSPACE_API_KEY']}" 43 | 44 | You also have the option of passing your Rackspace API Username/Key into the individual knife subcommands using the -A (or --rackspace-api-username) -K (or --rackspace-api-key) command options 45 | 46 | # provision a new 1GB Ubuntu 10.04 webserver 47 | knife rackspace server create -I 112 -f 3 -A 'Your Rackspace API username' -K "Your Rackspace API Key" -r 'role[webserver]' 48 | 49 | To select for the previous Rackspace API (aka 'v1'), you can use the --rackspace-version v1 command option. 'v2' is the default, so if you're still using exclusively 'v1' you will probably want to add the following to your knife.rb: 50 | 51 | knife[:rackspace_version] = 'v1' 52 | 53 | This plugin also has support for authenticating against an alternate API Auth URL. This is useful if you are a using a custom endpoint, here is an example of configuring your knife.rb: 54 | 55 | knife[:rackspace_auth_url] = "auth.my-custom-endpoint.com" 56 | 57 | 58 | Different regions can be specified by using the `--rackspace-region` switch or using the `knife[:rackspace_region]` in the knife.rb file. Valid regions include :dfw, :ord, :lon, and :syd. 59 | 60 | If you are behind a proxy you can specify it in the knife.rb file as follows: 61 | 62 | https_proxy https://PROXY_IP_ADDRESS:PORT 63 | 64 | SSL certificate verification can be disabled by include the following in your knife.rb file: 65 | 66 | knife[:ssl_verify_peer] = false 67 | 68 | Additionally the following options may be set in your knife.rb: 69 | 70 | * flavor 71 | * image 72 | * distro 73 | * template_file 74 | 75 | = SUBCOMMANDS: 76 | 77 | This plugin provides the following Knife subcommands. Specific command options can be found by invoking the subcommand with a --help flag 78 | 79 | == knife rackspace server create 80 | 81 | Provisions a new server in the Rackspace Cloud and then perform a Chef bootstrap (using the SSH protocol). The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists (provided by the provisioning). It is primarily intended for Chef Client systems that talk to a Chef server. By default the server is bootstrapped using the {chef-full}[https://github.com/opscode/chef/blob/master/chef/lib/chef/knife/bootstrap/chef-full.erb] template. This can be overridden using the -d or --template-file command options. 82 | 83 | If no name is provided, nodes created with the v1 API are named after their instance ID, with the v2 API they are given a random 'rs-XXXXXXXXX' name. 84 | 85 | Files can be injected onto the provisioned system using the --file switch. For example to inject my_script.sh into /root/initialize.sh you would use the following switch 86 | 87 | --file /root/initialize.sh=my_script.sh. 88 | 89 | Note: You can only inject text files and the maximum destination path is 255 characters. 90 | 91 | You may specify if want to manage your disk partitioning scheme with the --rackspace-disk-config DISKCONFIG option. If you bootstrap a `v2` node and leave this set to the default "AUTO", larger nodes take longer to bootstrap as it grows the disk from 10G to fill the full amount of local disk provided. This option allows you to pass "MANUAL" - which give you a node (in 1/2 to 1/4 of the time) and lets you manage ignoring, or formatting the rest of the disk on your own. 92 | 93 | http://docs.openstack.org/essex/openstack-compute/starter/content/Launch_and_manage_instances-d1e1885.html 94 | 95 | You may specify a custom network using the --network [LABEL_OR_ID] option. You can also remove the default internal ServiceNet and PublicNet networks by specifying the --no-default-networks switch. To use a network other than PublicNet for the bootstrap connection, specify the --bootstrap-network LABEL option. 96 | 97 | Note: If you are using one of the `performanceX-X` machines, you need to put `-f` or `--flavor` in quotes. 98 | 99 | === Windows 100 | 101 | Windows Servers require special treatment with the knife-rackspace gem. 102 | 103 | First, you'll need to ensure you've installed the knife-windows gem. Installation instructions can be found over here: http://docs.opscode.com/plugin_knife_windows.html#install-this-plugin 104 | 105 | Secondly, you need to make sure that the image you're using has WinRM pre-configured. Unfortuantely, none of the Rackspace Windows image have this done by default, so you'll need to run the following instructions in a Windows machine, then save a Snapshot to use when creating servers with knife rackspace: http://docs.opscode.com/plugin_knife_windows.html#requirements 106 | 107 | Thirdly, you must pass two extra parameters to the knife rackspace create command: 108 | 109 | --bootstrap-protocol winrm --distro windows-chef-client-msi 110 | 111 | If you have troubles, make sure you add the -VV switch for extra verbosity. The --server-create-timeout switch may also be your friend, as Windows machines take a long time to build compared to Linux ones. 112 | 113 | == knife rackspace server delete 114 | 115 | Deletes an existing server in the currently configured Rackspace Cloud account by the server/instance id. You can find the instance id by entering knife rackspace server list. Please note - this does not delete the associated node and client objects from the Chef server unless you pass the -P or --purge command option. Using the --purge option with v2 nodes will attempt to delete the node and client by the name of the node. 116 | 117 | == knife rackspace server list 118 | 119 | Outputs a list of all servers in the currently configured Rackspace Cloud account. Please note - this shows all instances associated with the account, some of which may not be currently managed by the Chef server. You may need to use the --rackspace-version and --rackspace-region options to see nodes in different Rackspace regions. 120 | 121 | == knife rackspace flavor list 122 | 123 | Outputs a list of all available flavors (available hardware configuration for a server) available to the currently configured Rackspace Cloud account. Each flavor has a unique combination of disk space, memory capacity and priority for CPU time. This data can be useful when choosing a flavor id to pass to the knife rackspace server create subcommand. You may need to use the --rackspace-version and --rackspace-region options to see nodes in different Rackspace regions. 124 | 125 | == knife rackspace image list 126 | 127 | Outputs a list of all available images available to the currently configured Rackspace Cloud account. An image is a collection of files used to create or rebuild a server. Rackspace provides a number of pre-built OS images by default. This data can be useful when choosing an image id to pass to the knife rackspace server create subcommand. You may need to use the --rackspace-version and --rackspace-region options to see nodes in different Rackspace regions. 128 | 129 | == knife rackspace network list 130 | 131 | Outputs a list of available networks to the currently configured Rackspace Cloud account. Networks can be added at a server during the creation process using the --network [LABEL_OR_ID] option. Knife does not currently support adding a network to an existing server. 132 | 133 | == knife rackspace network create 134 | 135 | Creates a new cloud network. Both the label and the CIDR are required parameters which are specified using the --label LABEL and --cidr CIDR respectively. The CIDR should be in the form of 172.16.0.0/24 or 2001:DB8::/64. Refer to http://www.rackspace.com/knowledge_center/article/using-cidr-notation-in-cloud-networks for more information. 136 | 137 | == knife rackspace network delete 138 | 139 | Deletes one or more specified networks by id. The network must be detached from all hosts before it is deleted. 140 | 141 | 142 | == Knife & Rackspace Rackconnect 143 | 144 | Rackspace Rackconnect allows the creation of a hybrid setup where you can have Cloud servers which are connected to bare metal hardware like Firewalls and Load balancers. You can read more about this product at http://www.rackspace.com/cloud/hybrid/rackconnect/ 145 | 146 | Under the hood, this changes the behaviour of how the cloud servers are configured and how IP addresses are assigned to them. So when using knife-rackspace with a 'Rack connected' cloud account you need use some additional parameters. See the sections below for more information regarding the two versions of Rack Connect. 147 | 148 | Note: If you account is leveraging private cloud networks for Rackconnnect then you are using Rackconnect v3. You can also find your version of Rackconnect by checking with your support team 149 | 150 | 151 | === Knife and Rackconnect version 2 152 | 153 | knife rackspace server create \ 154 | --server-name \ 155 | --image \ 156 | --flavor \ 157 | -r 'role[base]' \ 158 | --rackconnect-wait 159 | 160 | Note: If the server is also part of Rackspace Managed Operations service level you will need to add the --rackspace-servicelevel-wait option. 161 | 162 | knife rackspace server create \ 163 | --server-name \ 164 | --image \ 165 | --flavor \ 166 | -r 'role[base]' \ 167 | --rackconnect-wait \ 168 | --rackspace-servicelevel-wait 169 | 170 | --rackconnect-wait does the following :- 171 | 172 | * Rackconnect version 2 changes the networking on the cloud server and forces all trafic to route via the dedicated firewall or load balancer. It also then assigns the cloud server a new public IP address. The status of this automation provided by updates to the cloud server metadata. This option makes Knife wait for the Rackconnect automation to complete by checking the metadata. 173 | 174 | * Once the status is updated, it triggers the bootstrap process. 175 | 176 | 177 | --rackspace-servicelevel-wait does the following :- 178 | 179 | * For Cloud servers in the Managed operations service level, Rackspace installs additional agents and software which enables them to provide support. This automation. like the Rackconnect one, updates the cloud server metadata of its status. Likewise, using this option, makes knife wait till the automation is complete before triggering the bootstrap process. 180 | 181 | 182 | 183 | === Knife and Rackconnect version 3 184 | 185 | In case of version 3, there is a different command line option. 186 | 187 | knife rackspace server create \ 188 | --server-name \ 189 | --image \ 190 | --flavor \ 191 | -r 'role[base]' \ 192 | --rackconnect-v3-network-id 193 | 194 | 195 | --rackconnect-v3-network-id does the following :- 196 | * Create the server with the corresponding cloud network. The network id the id of an existing cloud network. 197 | * Knife will then issue addtional API calls to the Rackconnect API to assign a new public IP to the cloud server. The new IP is also stored in the Cloud Server Metadata under accessv4IP. 198 | * Knife then waits for the IP to be provisioned before triggering the bootstrap process. 199 | 200 | Functionally, this operates the same way as version 2. However, behind the scenes, Rackconnect v3 is signifcantly different in implementation. You can learn about the differences here : 201 | http://www.rackspace.com/knowledge_center/article/comparing-rackconnect-v30-and-rackconnect-v20 202 | 203 | 204 | = LICENSE: 205 | 206 | Author:: Adam Jacob () 207 | Author:: Seth Chisamore () 208 | Author:: Matt Ray () 209 | Author:: JJ Asghar () 210 | Author:: Rackspace Developers 211 | Copyright:: Copyright (c) 2009-2012 Opscode, Inc. 212 | Copyright:: Copyright (c) 2013-2015 Chef Software, Inc. 213 | License:: Apache License, Version 2.0 214 | 215 | Licensed under the Apache License, Version 2.0 (the "License"); 216 | you may not use this file except in compliance with the License. 217 | You may obtain a copy of the License at 218 | 219 | http://www.apache.org/licenses/LICENSE-2.0 220 | 221 | Unless required by applicable law or agreed to in writing, software 222 | distributed under the License is distributed on an "AS IS" BASIS, 223 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 224 | See the License for the specific language governing permissions and 225 | limitations under the License. 226 | -------------------------------------------------------------------------------- /spec/cassettes/v1/should_list_images.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: get 5 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/images/detail.json 6 | body: 7 | encoding: US-ASCII 8 | string: '' 9 | headers: 10 | User-Agent: 11 | - fog/1.19.0 12 | Content-Type: 13 | - application/json 14 | Accept: 15 | - application/json 16 | X-Auth-Token: _ONE-TIME-TOKEN_ 17 | response: 18 | status: 19 | code: 200 20 | message: 21 | headers: 22 | Server: 23 | - Jetty(8.0.y.z-SNAPSHOT) 24 | X-Varnish: _VARNISH-REQUEST-ID_ 25 | Vary: 26 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 27 | Cache-Control: 28 | - s-maxage=1800 29 | Content-Type: 30 | - application/json 31 | x-purge-key: 32 | - /000000/images 33 | Date: 34 | - Fri, 17 Jan 2014 19:13:27 GMT 35 | Via: 36 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 37 | Connection: 38 | - close 39 | Last-Modified: 40 | - Mon, 09 Jul 2012 17:15:23 GMT 41 | Age: 42 | - '0' 43 | Content-Length: 44 | - '2547' 45 | body: 46 | encoding: US-ASCII 47 | string: ! '{"images":[{"id":118,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"CentOS 48 | 6.0"},{"id":104,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"Debian 49 | 6 (Squeeze)"},{"id":125,"status":"ACTIVE","updated":"2012-05-03T07:21:06-05:00","name":"Ubuntu 50 | 12.04 LTS"},{"id":107,"status":"ACTIVE","updated":"2012-04-24T10:48:08-05:00","name":"FreeBSD 51 | 9.0"},{"id":24,"status":"ACTIVE","updated":"2010-01-26T12:07:04-06:00","name":"Windows 52 | Server 2008 SP2 x64"},{"id":109,"status":"ACTIVE","updated":"2011-11-03T06:28:56-05:00","name":"openSUSE 53 | 12"},{"id":127,"status":"ACTIVE","updated":"2012-07-09T12:15:23-05:00","name":"CentOS 54 | 6.3"},{"id":85,"status":"ACTIVE","updated":"2010-01-26T12:07:17-06:00","name":"Windows 55 | Server 2008 R2 x64"},{"id":110,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"Red 56 | Hat Enterprise Linux 5.5"},{"id":114,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"CentOS 57 | 5.6"},{"id":112,"status":"ACTIVE","updated":"2011-04-21T10:24:01-05:00","name":"Ubuntu 58 | 10.04 LTS"},{"id":56,"status":"ACTIVE","updated":"2010-09-17T07:12:56-05:00","name":"Windows 59 | Server 2008 SP2 x86 + SQL Server 2008 R2 Standard"},{"id":122,"status":"ACTIVE","updated":"2012-02-06T04:34:21-06:00","name":"CentOS 60 | 6.2"},{"id":100,"status":"ACTIVE","updated":"2011-09-12T09:09:23-05:00","name":"Arch 61 | 2012.08"},{"id":31,"status":"ACTIVE","updated":"2010-01-26T12:07:44-06:00","name":"Windows 62 | Server 2008 SP2 x86"},{"id":91,"status":"ACTIVE","updated":"2012-04-24T16:44:01-05:00","name":"Windows 63 | Server 2008 R2 x64 + SQL Server 2012 Standard"},{"id":111,"status":"ACTIVE","updated":"2011-09-12T10:53:12-05:00","name":"Red 64 | Hat Enterprise Linux 6"},{"id":92,"status":"ACTIVE","updated":"2012-04-24T16:44:01-05:00","name":"Windows 65 | Server 2008 R2 x64 + SQL Server 2012 Web"},{"id":57,"status":"ACTIVE","updated":"2010-09-17T07:16:25-05:00","name":"Windows 66 | Server 2008 SP2 x64 + SQL Server 2008 R2 Standard"},{"id":120,"status":"ACTIVE","updated":"2012-01-03T04:39:05-06:00","name":"Fedora 67 | 16"},{"id":86,"status":"ACTIVE","updated":"2010-09-17T07:19:20-05:00","name":"Windows 68 | Server 2008 R2 x64 + SQL Server 2008 R2 Standard"},{"id":108,"status":"ACTIVE","updated":"2011-11-01T08:32:30-05:00","name":"Gentoo 69 | 12.3"},{"id":126,"status":"ACTIVE","updated":"2012-05-29T17:11:45-05:00","name":"Fedora 70 | 17"},{"id":121,"status":"ACTIVE","updated":"2012-05-04T10:51:28-05:00","name":"CentOS 71 | 5.8"},{"id":89,"status":"ACTIVE","updated":"2011-10-04T08:39:34-05:00","name":"Windows 72 | Server 2008 R2 x64 + SQL Server 2008 R2 Web"}]}' 73 | http_version: 74 | recorded_at: Fri, 17 Jan 2014 19:13:27 GMT 75 | - request: 76 | method: post 77 | uri: https://identity.api.rackspacecloud.com/v2.0/tokens 78 | body: 79 | encoding: UTF-8 80 | string: ! '{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"_RAX_USERNAME_","apiKey":"_RAX_PASSWORD_"}}}' 81 | headers: 82 | User-Agent: 83 | - fog/1.20.0 84 | Content-Type: 85 | - application/json 86 | Accept: 87 | - application/json 88 | X-Auth-Token: _ONE-TIME-TOKEN_ 89 | response: 90 | status: 91 | code: 200 92 | message: 93 | headers: 94 | Server: 95 | - nginx/0.8.55 96 | Date: 97 | - Tue, 04 Mar 2014 21:23:43 GMT 98 | Content-Type: 99 | - application/json 100 | Transfer-Encoding: 101 | - '' 102 | Connection: 103 | - close 104 | vary: 105 | - Accept, Accept-Encoding, X-Auth-Token 106 | VIA: 107 | - 1.0 Repose (Repose/2.3.5) 108 | Front-End-Https: 109 | - 'on' 110 | body: 111 | encoding: US-ASCII 112 | string: ! '{"access":{"token":{"id":"_ONE-TIME-TOKEN_","expires":"2014-03-05T06:42:51.029Z","tenant":{"id":"000000","name":"000000"},"RAX-AUTH:authenticatedBy":["APIKEY"]},"serviceCatalog":[{"name":"cloudFiles","endpoints":[{"region":"DFW","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.dfw1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.dfw1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"ORD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.ord1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.ord1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"SYD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.syd2.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.syd2.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"IAD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.iad3.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.iad3.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"HKG","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.hkg1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.hkg1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"}],"type":"object-store"},{"name":"cloudFilesCDN","endpoints":[{"region":"DFW","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"ORD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn2.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"SYD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn4.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"IAD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn5.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"HKG","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn6.clouddrive.com\/v1\/_CDN-TENANT-NAME_"}],"type":"rax:object-cdn"},{"name":"cloudBlockStorage","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.blockstorage.api.rackspacecloud.com\/v1\/000000"}],"type":"volume"},{"name":"cloudDatabases","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.databases.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:database"},{"name":"cloudLoadBalancers","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:load-balancer"},{"name":"cloudServersOpenStack","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/syd.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/syd.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/ord.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/ord.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/dfw.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/dfw.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/iad.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/iad.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/hkg.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/hkg.servers.api.rackspacecloud.com\/","versionId":"2"}],"type":"compute"},{"name":"cloudQueues","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-iad.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-ord.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-dfw.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-syd.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-hkg.queues.api.rackspacecloud.com\/v1\/000000"}],"type":"rax:queues"},{"name":"autoscale","endpoints":[{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.autoscale.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:autoscale"},{"name":"cloudOrchestration","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.orchestration.api.rackspacecloud.com\/v1\/000000"}],"type":"orchestration"},{"name":"cloudBackup","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.backup.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:backup"},{"name":"cloudImages","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.images.api.rackspacecloud.com\/v2\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.images.api.rackspacecloud.com\/v2\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.images.api.rackspacecloud.com\/v2\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.images.api.rackspacecloud.com\/v2\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.images.api.rackspacecloud.com\/v2\/000000"}],"type":"image"},{"name":"cloudDNS","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/dns.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:dns"},{"name":"cloudMonitoring","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/monitoring.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:monitor"},{"name":"cloudServers","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/servers.api.rackspacecloud.com\/v1.0\/000000","versionInfo":"https:\/\/servers.api.rackspacecloud.com\/v1.0","versionList":"https:\/\/servers.api.rackspacecloud.com\/","versionId":"1.0"}],"type":"compute"}],"user":{"id":"296063","roles":[{"id":"10000150","description":"Checkmate 113 | Access role","name":"checkmate"},{"tenantId":"_CDN-TENANT-NAME_","id":"5","description":"A 114 | Role that allows a user access to keystone Service methods","name":"object-store:default"},{"tenantId":"000000","id":"6","description":"A 115 | Role that allows a user access to keystone Service methods","name":"compute:default"},{"id":"3","description":"User 116 | Admin Role.","name":"identity:user-admin"}],"name":"_RAX_USERNAME_","RAX-AUTH:defaultRegion":"DFW"}}}' 117 | http_version: 118 | recorded_at: Tue, 04 Mar 2014 21:23:43 GMT 119 | - request: 120 | method: get 121 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/images/detail.json 122 | body: 123 | encoding: US-ASCII 124 | string: '' 125 | headers: 126 | User-Agent: 127 | - fog/1.20.0 128 | Content-Type: 129 | - application/json 130 | Accept: 131 | - application/json 132 | X-Auth-Token: _ONE-TIME-TOKEN_ 133 | response: 134 | status: 135 | code: 200 136 | message: 137 | headers: 138 | Server: 139 | - Jetty(8.0.y.z-SNAPSHOT) 140 | X-Varnish: _VARNISH-REQUEST-ID_ 141 | Vary: 142 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 143 | Cache-Control: 144 | - s-maxage=1800 145 | Content-Type: 146 | - application/json 147 | x-purge-key: 148 | - /000000/images 149 | Date: 150 | - Tue, 04 Mar 2014 21:23:44 GMT 151 | Via: 152 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 153 | Connection: 154 | - close 155 | Last-Modified: 156 | - Mon, 09 Jul 2012 17:15:23 GMT 157 | Age: 158 | - '0' 159 | Content-Length: 160 | - '2547' 161 | body: 162 | encoding: US-ASCII 163 | string: ! '{"images":[{"id":118,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"CentOS 164 | 6.0"},{"id":104,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"Debian 165 | 6 (Squeeze)"},{"id":125,"status":"ACTIVE","updated":"2012-05-03T07:21:06-05:00","name":"Ubuntu 166 | 12.04 LTS"},{"id":107,"status":"ACTIVE","updated":"2012-04-24T10:48:08-05:00","name":"FreeBSD 167 | 9.0"},{"id":24,"status":"ACTIVE","updated":"2010-01-26T12:07:04-06:00","name":"Windows 168 | Server 2008 SP2 x64"},{"id":109,"status":"ACTIVE","updated":"2011-11-03T06:28:56-05:00","name":"openSUSE 169 | 12"},{"id":127,"status":"ACTIVE","updated":"2012-07-09T12:15:23-05:00","name":"CentOS 170 | 6.3"},{"id":85,"status":"ACTIVE","updated":"2010-01-26T12:07:17-06:00","name":"Windows 171 | Server 2008 R2 x64"},{"id":110,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"Red 172 | Hat Enterprise Linux 5.5"},{"id":114,"status":"ACTIVE","updated":"2011-08-17T05:11:30-05:00","name":"CentOS 173 | 5.6"},{"id":112,"status":"ACTIVE","updated":"2011-04-21T10:24:01-05:00","name":"Ubuntu 174 | 10.04 LTS"},{"id":56,"status":"ACTIVE","updated":"2010-09-17T07:12:56-05:00","name":"Windows 175 | Server 2008 SP2 x86 + SQL Server 2008 R2 Standard"},{"id":122,"status":"ACTIVE","updated":"2012-02-06T04:34:21-06:00","name":"CentOS 176 | 6.2"},{"id":100,"status":"ACTIVE","updated":"2011-09-12T09:09:23-05:00","name":"Arch 177 | 2012.08"},{"id":31,"status":"ACTIVE","updated":"2010-01-26T12:07:44-06:00","name":"Windows 178 | Server 2008 SP2 x86"},{"id":91,"status":"ACTIVE","updated":"2012-04-24T16:44:01-05:00","name":"Windows 179 | Server 2008 R2 x64 + SQL Server 2012 Standard"},{"id":111,"status":"ACTIVE","updated":"2011-09-12T10:53:12-05:00","name":"Red 180 | Hat Enterprise Linux 6"},{"id":92,"status":"ACTIVE","updated":"2012-04-24T16:44:01-05:00","name":"Windows 181 | Server 2008 R2 x64 + SQL Server 2012 Web"},{"id":57,"status":"ACTIVE","updated":"2010-09-17T07:16:25-05:00","name":"Windows 182 | Server 2008 SP2 x64 + SQL Server 2008 R2 Standard"},{"id":120,"status":"ACTIVE","updated":"2012-01-03T04:39:05-06:00","name":"Fedora 183 | 16"},{"id":86,"status":"ACTIVE","updated":"2010-09-17T07:19:20-05:00","name":"Windows 184 | Server 2008 R2 x64 + SQL Server 2008 R2 Standard"},{"id":108,"status":"ACTIVE","updated":"2011-11-01T08:32:30-05:00","name":"Gentoo 185 | 12.3"},{"id":126,"status":"ACTIVE","updated":"2012-05-29T17:11:45-05:00","name":"Fedora 186 | 17"},{"id":121,"status":"ACTIVE","updated":"2012-05-04T10:51:28-05:00","name":"CentOS 187 | 5.8"},{"id":89,"status":"ACTIVE","updated":"2011-10-04T08:39:34-05:00","name":"Windows 188 | Server 2008 R2 x64 + SQL Server 2008 R2 Web"}]}' 189 | http_version: 190 | recorded_at: Tue, 04 Mar 2014 21:23:44 GMT 191 | recorded_with: VCR 2.8.0 192 | -------------------------------------------------------------------------------- /lib/chef/knife/rackspace_server_create.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Adam Jacob () 3 | # Author:: Matt Ray () 4 | # Copyright:: Copyright (c) 2009-2012 Opscode, Inc. 5 | # License:: Apache License, Version 2.0 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | require 'chef/knife/rackspace_base' 21 | require 'chef/knife/winrm_base' 22 | require 'chef/knife' 23 | 24 | class Chef 25 | class Knife 26 | class RackspaceServerCreate < Knife 27 | 28 | include Knife::RackspaceBase 29 | include Chef::Knife::WinrmBase 30 | 31 | 32 | deps do 33 | require 'fog' 34 | require 'readline' 35 | require 'chef/json_compat' 36 | require 'chef/knife/bootstrap' 37 | Chef::Knife::Bootstrap.load_deps 38 | end 39 | 40 | banner "knife rackspace server create (options)" 41 | 42 | attr_accessor :initial_sleep_delay 43 | 44 | option :flavor, 45 | :short => "-f FLAVOR", 46 | :long => "--flavor FLAVOR", 47 | :description => "The flavor of server; default is 2 (512 MB)", 48 | :proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f.to_s }, 49 | :default => 2 50 | 51 | option :image, 52 | :short => "-I IMAGE", 53 | :long => "--image IMAGE", 54 | :description => "The image of the server", 55 | :proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_s } 56 | 57 | option :server_name, 58 | :short => "-S NAME", 59 | :long => "--server-name NAME", 60 | :description => "The server name" 61 | 62 | option :chef_node_name, 63 | :short => "-N NAME", 64 | :long => "--node-name NAME", 65 | :description => "The Chef node name for your new node" 66 | 67 | option :bootstrap_network, 68 | :long => "--bootstrap-network LABEL", 69 | :description => "Use IP address on this network for bootstrap", 70 | :default => 'public' 71 | 72 | option :private_network, 73 | :long => "--private-network", 74 | :description => "Equivalent to --bootstrap-network private", 75 | :boolean => true, 76 | :default => false 77 | 78 | option :ssh_user, 79 | :short => "-x USERNAME", 80 | :long => "--ssh-user USERNAME", 81 | :description => "The ssh username; default is 'root'", 82 | :default => "root" 83 | 84 | option :ssh_password, 85 | :short => "-P PASSWORD", 86 | :long => "--ssh-password PASSWORD", 87 | :description => "The ssh password" 88 | 89 | option :ssh_port, 90 | :short => "-p PORT", 91 | :long => "--ssh-port PORT", 92 | :description => "The ssh port", 93 | :default => "22", 94 | :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key } 95 | 96 | option :identity_file, 97 | :short => "-i IDENTITY_FILE", 98 | :long => "--identity-file IDENTITY_FILE", 99 | :description => "The SSH identity file used for authentication" 100 | 101 | option :prerelease, 102 | :long => "--prerelease", 103 | :description => "Install the pre-release chef gems" 104 | 105 | option :bootstrap_version, 106 | :long => "--bootstrap-version VERSION", 107 | :description => "The version of Chef to install", 108 | :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v } 109 | 110 | option :distro, 111 | :short => "-d DISTRO", 112 | :long => "--distro DISTRO", 113 | :description => "Bootstrap a distro using a template; default is 'chef-full'", 114 | :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d } 115 | 116 | option :template_file, 117 | :long => "--template-file TEMPLATE", 118 | :description => "Full path to location of template to use", 119 | :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t }, 120 | :default => false 121 | 122 | option :run_list, 123 | :short => "-r RUN_LIST", 124 | :long => "--run-list RUN_LIST", 125 | :description => "Comma separated list of roles/recipes to apply", 126 | :proc => lambda { |o| o.split(/[\s,]+/) }, 127 | :default => [] 128 | 129 | option :first_boot_attributes, 130 | :short => "-j JSON_ATTRIBS", 131 | :long => "--json-attributes", 132 | :description => "A JSON string to be added to the first run of chef-client", 133 | :proc => lambda { |o| JSON.parse(o) }, 134 | :default => {} 135 | 136 | option :rackspace_metadata, 137 | :short => "-M JSON", 138 | :long => "--rackspace-metadata JSON", 139 | :description => "JSON string version of metadata hash to be supplied with the server create call", 140 | :proc => Proc.new { |m| Chef::Config[:knife][:rackspace_metadata] = JSON.parse(m) }, 141 | :default => "" 142 | 143 | option :rackconnect_wait, 144 | :long => "--rackconnect-wait", 145 | :description => "Wait until the Rackconnect automation setup is complete before bootstrapping chef", 146 | :boolean => true, 147 | :default => false 148 | 149 | option :rackconnect_v3_network_id, 150 | :long => '--rackconnect-v3-network-id ID', 151 | :description => 'Rackconnect V3 ONLY: Link a new server to an existing network', 152 | :proc => lambda { |o| Chef::Config[:knife][:rackconnect_v3_network_id] = o }, 153 | :default => nil 154 | 155 | option :rackspace_servicelevel_wait, 156 | :long => "--rackspace-servicelevel-wait", 157 | :description => "Wait until the Rackspace service level automation setup is complete before bootstrapping chef", 158 | :boolean => true, 159 | :default => false 160 | 161 | option :hint, 162 | :long => "--hint HINT_NAME[=HINT_FILE]", 163 | :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.", 164 | :proc => Proc.new { |h| 165 | Chef::Config[:knife][:hints] ||= {} 166 | name, path = h.split("=") 167 | Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new 168 | } 169 | 170 | option :host_key_verify, 171 | :long => "--[no-]host-key-verify", 172 | :description => "Verify host key, enabled by default", 173 | :boolean => true, 174 | :default => true 175 | 176 | option :tcp_test_ssh, 177 | :long => "--[no-]tcp-test-ssh", 178 | :description => "Check that SSH is available using a TCP check directly on port 22, enabled by default", 179 | :boolean => true, 180 | :default => true 181 | 182 | option :ssh_wait_timeout, 183 | :long => "--ssh-wait-timeout TIMEOUT", 184 | :description => "The ssh wait timeout, before attempting ssh", 185 | :default => "0" 186 | 187 | option :retry_ssh_every, 188 | :long => "--retry-ssh-every TIMEOUT", 189 | :description => "Retry SSH after n seconds (retry each period)", 190 | :default => "5" 191 | 192 | option :retry_ssh_limit, 193 | :long => "--retry-ssh-limit COUNT", 194 | :description => "Retry SSH at most this number of times", 195 | :default => "5" 196 | 197 | option :default_networks, 198 | :long => "--[no-]default-networks", 199 | :description => "Include public and service networks, enabled by default", 200 | :boolean => true, 201 | :default => true 202 | 203 | option :network, 204 | :long => '--network [LABEL_OR_ID]', 205 | :description => "Add private network. Use multiple --network options to specify multiple networks.", 206 | :proc => Proc.new{ |name| 207 | Chef::Config[:knife][:rackspace_networks] ||= [] 208 | (Chef::Config[:knife][:rackspace_networks] << name).uniq! 209 | } 210 | 211 | option :bootstrap_protocol, 212 | :long => "--bootstrap-protocol protocol", 213 | :description => "Protocol to bootstrap Windows servers. options: winrm", 214 | :default => nil 215 | 216 | option :server_create_timeout, 217 | :long => "--server-create-timeout timeout", 218 | :description => "How long to wait until the server is ready; default is 1200 seconds", 219 | :default => 1200, 220 | :proc => Proc.new { |v| Chef::Config[:knife][:server_create_timeout] = v} 221 | 222 | option :bootstrap_proxy, 223 | :long => "--bootstrap-proxy PROXY_URL", 224 | :description => "The proxy server for the node being bootstrapped", 225 | :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_proxy] = v } 226 | 227 | option :rackspace_disk_config, 228 | :long => "--rackspace-disk-config DISKCONFIG", 229 | :description => "Specify if want to manage your own disk partitioning scheme (AUTO or MANUAL), default is AUTO", 230 | :proc => Proc.new { |k| Chef::Config[:knife][:rackspace_disk_config] = k }, 231 | :default => "AUTO" 232 | 233 | option :rackspace_config_drive, 234 | :long => "--rackspace_config_drive CONFIGDRIVE", 235 | :description => "Creates a config drive device in /dev/disk/by-label/config-2 if set to TRUE", 236 | :proc => Proc.new { |k| Chef::Config[:knife][:rackspace_config_drive] = k }, 237 | :default => "false" 238 | 239 | option :rackspace_user_data_file, 240 | :long => "--rackspace_user_data_file USERDATA", 241 | :description => "User data file will be placed in the openstack/latest/user_data directory on the config drive", 242 | :proc => Proc.new { |k| Chef::Config[:knife][:rackspace_user_data] = k } 243 | 244 | option :ssh_keypair, 245 | :long => "--ssh-keypair KEYPAIR_NAME", 246 | :description => "Name of existing nova SSH keypair. Public key will be injected into the instance.", 247 | :proc => Proc.new { |v| Chef::Config[:knife][:rackspace_ssh_keypair] = v }, 248 | :default => nil 249 | 250 | option :secret_file, 251 | :long => "--secret-file SECRET_FILE", 252 | :description => "A file containing the secret key to use to encrypt data bag item values", 253 | :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } 254 | 255 | option :bootstrap_vault_file, 256 | :long => '--bootstrap-vault-file VAULT_FILE', 257 | :description => 'A JSON file with a list of vault(s) and item(s) to be updated' 258 | 259 | option :bootstrap_vault_json, 260 | :long => '--bootstrap-vault-json VAULT_JSON', 261 | :description => 'A JSON string with the vault(s) and item(s) to be updated' 262 | 263 | option :bootstrap_vault_item, 264 | :long => '--bootstrap-vault-item VAULT_ITEM', 265 | :description => 'A single vault and item to update as "vault:item"', 266 | :proc => Proc.new { |i| 267 | (vault, item) = i.split(/:/) 268 | Chef::Config[:knife][:bootstrap_vault_item] ||= {} 269 | Chef::Config[:knife][:bootstrap_vault_item][vault] ||= [] 270 | Chef::Config[:knife][:bootstrap_vault_item][vault].push(item) 271 | Chef::Config[:knife][:bootstrap_vault_item] 272 | } 273 | 274 | def load_winrm_deps 275 | require 'winrm' 276 | require 'em-winrm' 277 | require 'chef/knife/bootstrap_windows_winrm' 278 | require 'chef/knife/core/windows_bootstrap_context' 279 | require 'chef/knife/winrm' 280 | end 281 | 282 | def tcp_test_ssh(server, bootstrap_ip) 283 | return true unless config[:tcp_test_ssh] != nil 284 | 285 | limit = Chef::Config[:knife][:retry_ssh_limit].to_i 286 | count = 0 287 | 288 | begin 289 | Net::SSH.start(bootstrap_ip, 'root', :password => server.password ) do |ssh| 290 | Chef::Log.debug("sshd accepting connections on #{bootstrap_ip}") 291 | break 292 | end 293 | rescue 294 | count += 1 295 | 296 | if count <= limit 297 | print '.' 298 | sleep config[:retry_ssh_every].to_i 299 | tcp_test_ssh(server, bootstrap_ip) 300 | else 301 | ui.error "Unable to SSH into #{bootstrap_ip}" 302 | exit 1 303 | end 304 | end 305 | end 306 | 307 | def parse_file_argument(arg) 308 | dest, src = arg.split('=') 309 | unless dest && src 310 | ui.error "Unable to process file arguments #{arg}. The --file option requires both the destination on the remote machine as well as the local source be supplied using the form DESTINATION-PATH=SOURCE-PATH" 311 | exit 1 312 | end 313 | [dest, src] 314 | end 315 | 316 | def encode_file(file) 317 | begin 318 | filename = File.expand_path(file) 319 | content = File.read(filename) 320 | rescue Errno::ENOENT => e 321 | ui.error "Unable to read source file - #{filename}" 322 | exit 1 323 | end 324 | Base64.encode64(content) 325 | end 326 | 327 | def files 328 | return {} unless Chef::Config[:knife][:file] 329 | 330 | files = [] 331 | Chef::Config[:knife][:file].each do |arg| 332 | dest, src = parse_file_argument(arg) 333 | Chef::Log.debug("Inject file #{src} into #{dest}") 334 | files << { 335 | :path => dest, 336 | :contents => encode_file(src) 337 | } 338 | end 339 | files 340 | end 341 | 342 | 343 | 344 | def tcp_test_winrm(hostname, port) 345 | TCPSocket.new(hostname, port) 346 | return true 347 | rescue SocketError 348 | sleep 2 349 | false 350 | rescue Errno::ETIMEDOUT 351 | false 352 | rescue Errno::EPERM 353 | false 354 | rescue Errno::ECONNREFUSED 355 | sleep 2 356 | false 357 | rescue Errno::EHOSTUNREACH 358 | sleep 2 359 | false 360 | rescue Errno::ENETUNREACH 361 | sleep 2 362 | false 363 | end 364 | 365 | def run 366 | $stdout.sync = true 367 | 368 | # Maybe deprecate this option at some point 369 | config[:bootstrap_network] = 'private' if config[:private_network] 370 | 371 | unless Chef::Config[:knife][:image] 372 | ui.error("You have not provided a valid image value. Please note the short option for this value recently changed from '-i' to '-I'.") 373 | exit 1 374 | end 375 | 376 | if locate_config_value(:bootstrap_protocol) == 'winrm' 377 | load_winrm_deps 378 | end 379 | 380 | rackconnect_wait = Chef::Config[:knife][:rackconnect_wait] || config[:rackconnect_wait] 381 | rackconnect3 = Chef::Config[:knife][:rackconnect_v3_network_id] || config[:rackconnect_v3_network_id] 382 | rackspace_servicelevel_wait = Chef::Config[:knife][:rackspace_servicelevel_wait] || config[:rackspace_servicelevel_wait] 383 | node_name = get_node_name(config[:chef_node_name] || config[:server_name]) 384 | networks = get_networks(Chef::Config[:knife][:rackspace_networks], rackconnect3) 385 | 386 | server = connection.servers.new( 387 | :name => node_name, 388 | :image_id => Chef::Config[:knife][:image], 389 | :flavor_id => locate_config_value(:flavor), 390 | :metadata => Chef::Config[:knife][:rackspace_metadata], 391 | :disk_config => Chef::Config[:knife][:rackspace_disk_config], 392 | :user_data => user_data, 393 | :config_drive => locate_config_value(:rackspace_config_drive) || false, 394 | :personality => files, 395 | :key_name => Chef::Config[:knife][:rackspace_ssh_keypair] 396 | ) 397 | 398 | if version_one? 399 | server.save 400 | else 401 | server.save(:networks => networks) 402 | end 403 | 404 | msg_pair("Instance ID", server.id) 405 | msg_pair("Host ID", server.host_id) 406 | msg_pair("Name", server.name) 407 | msg_pair("Flavor", server.flavor.name) 408 | msg_pair("Image", server.image.name) 409 | msg_pair("Metadata", server.metadata.all) 410 | msg_pair("ConfigDrive", server.config_drive) 411 | msg_pair("UserData", Chef::Config[:knife][:rackspace_user_data]) 412 | msg_pair("RackConnect Wait", rackconnect_wait ? 'yes' : 'no') 413 | msg_pair("RackConnect V3", rackconnect3 ? 'yes' : 'no') 414 | msg_pair("ServiceLevel Wait", rackspace_servicelevel_wait ? 'yes' : 'no') 415 | msg_pair("SSH Key", Chef::Config[:knife][:rackspace_ssh_keypair]) 416 | 417 | # wait for it to be ready to do stuff 418 | begin 419 | server.wait_for(Integer(locate_config_value(:server_create_timeout))) { 420 | print "."; 421 | Chef::Log.debug("#{progress}%") 422 | 423 | if rackconnect_wait and rackspace_servicelevel_wait 424 | Chef::Log.debug("rackconnect_automation_status: #{metadata.all['rackconnect_automation_status']}") 425 | Chef::Log.debug("rax_service_level_automation: #{metadata.all['rax_service_level_automation']}") 426 | ready? and metadata.all['rackconnect_automation_status'] == 'DEPLOYED' and metadata.all['rax_service_level_automation'] == 'Complete' 427 | elsif rackconnect_wait 428 | Chef::Log.debug("rackconnect_automation_status: #{metadata.all['rackconnect_automation_status']}") 429 | ready? and metadata.all['rackconnect_automation_status'] == 'DEPLOYED' 430 | elsif rackspace_servicelevel_wait 431 | Chef::Log.debug("rax_service_level_automation: #{metadata.all['rax_service_level_automation']}") 432 | ready? and metadata.all['rax_service_level_automation'] == 'Complete' 433 | else 434 | ready? 435 | end 436 | } 437 | rescue Fog::Errors::TimeoutError 438 | ui.error('Timeout waiting for the server to be created') 439 | msg_pair('Progress', "#{server.progress}%") 440 | msg_pair('rackconnect_automation_status', server.metadata.all['rackconnect_automation_status']) 441 | msg_pair('rax_service_level_automation', server.metadata.all['rax_service_level_automation']) 442 | Chef::Application.fatal! 'Server didn\'t finish on time' 443 | end 444 | 445 | msg_pair("Metadata", server.metadata) 446 | 447 | print "\n#{ui.color("Waiting server", :magenta)}" 448 | 449 | puts("\n") 450 | 451 | if Chef::Config[:knife][:rackconnect_v3_network_id] 452 | print "\n#{ui.color("Setting up RackconnectV3 network and IPs", :magenta)}" 453 | setup_rackconnect_network!(server) 454 | while server.ipv4_address == "" 455 | server.reload 456 | sleep 5 457 | end 458 | end 459 | 460 | if networks && Chef::Config[:knife][:rackspace_networks] 461 | msg_pair("Networks", Chef::Config[:knife][:rackspace_networks].sort.join(', ')) 462 | end 463 | 464 | msg_pair("Public DNS Name", public_dns_name(server)) 465 | msg_pair("Public IP Address", ip_address(server, 'public')) 466 | msg_pair("Private IP Address", ip_address(server, 'private')) 467 | msg_pair("Password", server.password) 468 | msg_pair("Metadata", server.metadata.all) 469 | 470 | bootstrap_ip_address = ip_address(server, config[:bootstrap_network]) 471 | 472 | Chef::Log.debug("Bootstrap IP Address #{bootstrap_ip_address}") 473 | if bootstrap_ip_address.nil? 474 | ui.error("No IP address available for bootstrapping.") 475 | exit 1 476 | end 477 | 478 | if locate_config_value(:bootstrap_protocol) == 'winrm' 479 | print "\n#{ui.color("Waiting for winrm", :magenta)}" 480 | print(".") until tcp_test_winrm(bootstrap_ip_address, locate_config_value(:winrm_port)) 481 | bootstrap_for_windows_node(server, bootstrap_ip_address).run 482 | else 483 | print "\n#{ui.color("Waiting for sshd", :magenta)}" 484 | tcp_test_ssh(server, bootstrap_ip_address) 485 | bootstrap_for_node(server, bootstrap_ip_address).run 486 | end 487 | 488 | puts "\n" 489 | msg_pair("Instance ID", server.id) 490 | msg_pair("Host ID", server.host_id) 491 | msg_pair("Name", server.name) 492 | msg_pair("Flavor", server.flavor.name) 493 | msg_pair("Image", server.image.name) if server.image 494 | msg_pair("Boot Image ID", server.boot_image_id) if server.boot_image_id 495 | msg_pair("Metadata", server.metadata) 496 | msg_pair("Public DNS Name", public_dns_name(server)) 497 | msg_pair("Public IP Address", ip_address(server, 'public')) 498 | msg_pair("Private IP Address", ip_address(server, 'private')) 499 | msg_pair("Password", server.password) 500 | msg_pair("Environment", config[:environment] || '_default') 501 | msg_pair("Run List", config[:run_list].join(', ')) 502 | end 503 | 504 | def setup_rackconnect_network!(server) 505 | auth_token = connection.authenticate 506 | tenant_id = connection.endpoint_uri.path.split("/").last 507 | region = connection.region 508 | uri = URI("https://#{region}.rackconnect.api.rackspacecloud.com/v3/#{tenant_id}/public_ips") 509 | 510 | Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| 511 | begin 512 | req = Net::HTTP::Post.new(uri.request_uri) 513 | req['X-Auth-Token'] = auth_token 514 | req['Content-Type'] = 'application/json' 515 | req.body = JSON.dump("cloud_server" => { "id" => server.id }) 516 | http.use_ssl = true 517 | http.request req 518 | rescue StandardError => e 519 | puts "HTTP Request failed (#{e.message})" 520 | end 521 | end 522 | end 523 | 524 | def user_data 525 | file = Chef::Config[:knife][:rackspace_user_data] 526 | return unless file 527 | 528 | begin 529 | filename = File.expand_path(file) 530 | content = File.read(filename) 531 | rescue Errno::ENOENT => e 532 | ui.error "Unable to read source file - #{filename}" 533 | exit 1 534 | end 535 | content 536 | end 537 | 538 | def bootstrap_for_node(server, bootstrap_ip_address) 539 | bootstrap = Chef::Knife::Bootstrap.new 540 | bootstrap.name_args = [bootstrap_ip_address] 541 | bootstrap.config[:ssh_user] = config[:ssh_user] || "root" 542 | bootstrap.config[:ssh_password] = server.password 543 | bootstrap.config[:ssh_port] = config[:ssh_port] || Chef::Config[:knife][:ssh_port] 544 | bootstrap.config[:identity_file] = config[:identity_file] 545 | bootstrap.config[:host_key_verify] = config[:host_key_verify] 546 | bootstrap.config[:bootstrap_vault_file] = config[:bootstrap_vault_file] if config[:bootstrap_vault_file] 547 | bootstrap.config[:bootstrap_vault_json] = config[:bootstrap_vault_json] if config[:bootstrap_vault_json] 548 | bootstrap.config[:bootstrap_vault_item] = config[:bootstrap_vault_item] if config[:bootstrap_vault_item] 549 | # bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes 550 | bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root' 551 | bootstrap.config[:distro] = locate_config_value(:distro) || 'chef-full' 552 | bootstrap_common_params(bootstrap, server) 553 | end 554 | 555 | def bootstrap_common_params(bootstrap, server) 556 | bootstrap.config[:environment] = config[:environment] 557 | bootstrap.config[:run_list] = config[:run_list] 558 | if version_one? 559 | bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id 560 | else 561 | bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.name 562 | end 563 | bootstrap.config[:prerelease] = config[:prerelease] 564 | bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version) 565 | bootstrap.config[:template_file] = locate_config_value(:template_file) 566 | bootstrap.config[:first_boot_attributes] = config[:first_boot_attributes] 567 | bootstrap.config[:bootstrap_proxy] = locate_config_value(:bootstrap_proxy) 568 | bootstrap.config[:encrypted_data_bag_secret] = config[:encrypted_data_bag_secret] 569 | bootstrap.config[:encrypted_data_bag_secret_file] = config[:encrypted_data_bag_secret_file] 570 | bootstrap.config[:secret] = locate_config_value(:secret) 571 | bootstrap.config[:secret_file] = locate_config_value(:secret_file) || "" 572 | 573 | Chef::Config[:knife][:hints] ||= {} 574 | Chef::Config[:knife][:hints]["rackspace"] ||= {} 575 | bootstrap 576 | end 577 | 578 | def bootstrap_for_windows_node(server, bootstrap_ip_address) 579 | bootstrap = Chef::Knife::BootstrapWindowsWinrm.new 580 | bootstrap.name_args = [bootstrap_ip_address] 581 | bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator' 582 | bootstrap.config[:winrm_password] = locate_config_value(:winrm_password) || server.password 583 | bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport) 584 | bootstrap.config[:winrm_port] = locate_config_value(:winrm_port) 585 | bootstrap.config[:distro] = locate_config_value(:distro) || 'windows-chef-client-msi' 586 | bootstrap_common_params(bootstrap, server) 587 | end 588 | 589 | end 590 | #v2 servers require a name, random if chef_node_name is empty, empty if v1 591 | def get_node_name(chef_node_name) 592 | return chef_node_name unless chef_node_name.nil? 593 | #lazy uuids 594 | chef_node_name = "rs-"+rand.to_s.split('.')[1] unless version_one? 595 | end 596 | 597 | def get_networks(names, rackconnect3=false) 598 | names = Array(names) 599 | 600 | if(Chef::Config[:knife][:rackspace_version] == 'v2') 601 | if rackconnect3 602 | nets = [Chef::Config[:knife][:rackconnect_v3_network_id]] 603 | elsif config[:default_networks] 604 | nets = [ 605 | '00000000-0000-0000-0000-000000000000', 606 | '11111111-1111-1111-1111-111111111111' 607 | ] 608 | else 609 | nets = [] 610 | end 611 | 612 | available_networks = connection.networks.all 613 | 614 | names.each do |name| 615 | net = available_networks.detect{|n| n.label == name || n.id == name} 616 | if(net) 617 | nets << net.id 618 | else 619 | ui.error("Failed to locate network: #{name}") 620 | exit 1 621 | end 622 | end 623 | nets 624 | elsif(names && !names.empty?) 625 | ui.error("Custom networks are only available in v2 API") 626 | exit 1 627 | end 628 | end 629 | end 630 | end 631 | -------------------------------------------------------------------------------- /spec/cassettes/v1/should_list_server_flavors.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: get 5 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/detail.json 6 | body: 7 | encoding: US-ASCII 8 | string: '' 9 | headers: 10 | User-Agent: 11 | - fog/1.19.0 12 | Content-Type: 13 | - application/json 14 | Accept: 15 | - application/json 16 | X-Auth-Token: _ONE-TIME-TOKEN_ 17 | response: 18 | status: 19 | code: 200 20 | message: 21 | headers: 22 | Server: 23 | - Jetty(8.0.y.z-SNAPSHOT) 24 | X-Varnish: _VARNISH-REQUEST-ID_ 25 | Vary: 26 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 27 | Cache-Control: 28 | - s-maxage=1800 29 | Content-Type: 30 | - application/json 31 | x-purge-key: 32 | - /flavors 33 | Date: 34 | - Fri, 17 Jan 2014 19:13:19 GMT 35 | Via: 36 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 37 | Connection: 38 | - close 39 | Last-Modified: 40 | - Tue, 06 Dec 2011 17:31:55 GMT 41 | Age: 42 | - '0' 43 | Content-Length: 44 | - '422' 45 | body: 46 | encoding: US-ASCII 47 | string: ! '{"flavors":[{"id":1,"ram":256,"disk":10,"name":"256 server"},{"id":2,"ram":512,"disk":20,"name":"512 48 | server"},{"id":3,"ram":1024,"disk":40,"name":"1GB server"},{"id":4,"ram":2048,"disk":80,"name":"2GB 49 | server"},{"id":5,"ram":4096,"disk":160,"name":"4GB server"},{"id":6,"ram":8192,"disk":320,"name":"8GB 50 | server"},{"id":7,"ram":15872,"disk":620,"name":"15.5GB server"},{"id":8,"ram":30720,"disk":1200,"name":"30GB 51 | server"}]}' 52 | http_version: 53 | recorded_at: Fri, 17 Jan 2014 19:13:19 GMT 54 | - request: 55 | method: get 56 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/1.json 57 | body: 58 | encoding: US-ASCII 59 | string: '' 60 | headers: 61 | User-Agent: 62 | - fog/1.19.0 63 | Content-Type: 64 | - application/json 65 | Accept: 66 | - application/json 67 | X-Auth-Token: _ONE-TIME-TOKEN_ 68 | response: 69 | status: 70 | code: 200 71 | message: 72 | headers: 73 | Server: 74 | - Jetty(8.0.y.z-SNAPSHOT) 75 | X-Varnish: _VARNISH-REQUEST-ID_ 76 | Vary: 77 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 78 | Cache-Control: 79 | - s-maxage=1800 80 | Content-Type: 81 | - application/json 82 | x-purge-key: 83 | - /flavors 84 | Date: 85 | - Fri, 17 Jan 2014 19:13:19 GMT 86 | Via: 87 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 88 | Connection: 89 | - close 90 | Last-Modified: 91 | - Wed, 19 Sep 2007 18:24:59 GMT 92 | Age: 93 | - '0' 94 | Content-Length: 95 | - '59' 96 | body: 97 | encoding: US-ASCII 98 | string: ! '{"flavor":{"id":1,"ram":256,"disk":10,"name":"256 server"}}' 99 | http_version: 100 | recorded_at: Fri, 17 Jan 2014 19:13:19 GMT 101 | - request: 102 | method: get 103 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/2.json 104 | body: 105 | encoding: US-ASCII 106 | string: '' 107 | headers: 108 | User-Agent: 109 | - fog/1.19.0 110 | Content-Type: 111 | - application/json 112 | Accept: 113 | - application/json 114 | X-Auth-Token: _ONE-TIME-TOKEN_ 115 | response: 116 | status: 117 | code: 200 118 | message: 119 | headers: 120 | Server: 121 | - Jetty(8.0.y.z-SNAPSHOT) 122 | X-Varnish: _VARNISH-REQUEST-ID_ 123 | Vary: 124 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 125 | Cache-Control: 126 | - s-maxage=1800 127 | Content-Type: 128 | - application/json 129 | x-purge-key: 130 | - /flavors 131 | Date: 132 | - Fri, 17 Jan 2014 19:13:20 GMT 133 | Via: 134 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 135 | Connection: 136 | - close 137 | Last-Modified: 138 | - Wed, 19 Sep 2007 18:25:10 GMT 139 | Age: 140 | - '0' 141 | Content-Length: 142 | - '59' 143 | body: 144 | encoding: US-ASCII 145 | string: ! '{"flavor":{"id":2,"ram":512,"disk":20,"name":"512 server"}}' 146 | http_version: 147 | recorded_at: Fri, 17 Jan 2014 19:13:20 GMT 148 | - request: 149 | method: get 150 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/3.json 151 | body: 152 | encoding: US-ASCII 153 | string: '' 154 | headers: 155 | User-Agent: 156 | - fog/1.19.0 157 | Content-Type: 158 | - application/json 159 | Accept: 160 | - application/json 161 | X-Auth-Token: _ONE-TIME-TOKEN_ 162 | response: 163 | status: 164 | code: 200 165 | message: 166 | headers: 167 | Server: 168 | - Jetty(8.0.y.z-SNAPSHOT) 169 | X-Varnish: _VARNISH-REQUEST-ID_ 170 | Vary: 171 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 172 | Cache-Control: 173 | - s-maxage=1800 174 | Content-Type: 175 | - application/json 176 | x-purge-key: 177 | - /flavors 178 | Date: 179 | - Fri, 17 Jan 2014 19:13:21 GMT 180 | Via: 181 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 182 | Connection: 183 | - close 184 | Last-Modified: 185 | - Fri, 21 Sep 2007 23:11:39 GMT 186 | Age: 187 | - '0' 188 | Content-Length: 189 | - '60' 190 | body: 191 | encoding: US-ASCII 192 | string: ! '{"flavor":{"id":3,"ram":1024,"disk":40,"name":"1GB server"}}' 193 | http_version: 194 | recorded_at: Fri, 17 Jan 2014 19:13:21 GMT 195 | - request: 196 | method: get 197 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/4.json 198 | body: 199 | encoding: US-ASCII 200 | string: '' 201 | headers: 202 | User-Agent: 203 | - fog/1.19.0 204 | Content-Type: 205 | - application/json 206 | Accept: 207 | - application/json 208 | X-Auth-Token: _ONE-TIME-TOKEN_ 209 | response: 210 | status: 211 | code: 200 212 | message: 213 | headers: 214 | Server: 215 | - Jetty(8.0.y.z-SNAPSHOT) 216 | X-Varnish: _VARNISH-REQUEST-ID_ 217 | Vary: 218 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 219 | Cache-Control: 220 | - s-maxage=1800 221 | Content-Type: 222 | - application/json 223 | x-purge-key: 224 | - /flavors 225 | Date: 226 | - Fri, 17 Jan 2014 19:13:21 GMT 227 | Via: 228 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 229 | Connection: 230 | - close 231 | Last-Modified: 232 | - Wed, 19 Sep 2007 18:25:33 GMT 233 | Age: 234 | - '0' 235 | Content-Length: 236 | - '60' 237 | body: 238 | encoding: US-ASCII 239 | string: ! '{"flavor":{"id":4,"ram":2048,"disk":80,"name":"2GB server"}}' 240 | http_version: 241 | recorded_at: Fri, 17 Jan 2014 19:13:21 GMT 242 | - request: 243 | method: get 244 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/5.json 245 | body: 246 | encoding: US-ASCII 247 | string: '' 248 | headers: 249 | User-Agent: 250 | - fog/1.19.0 251 | Content-Type: 252 | - application/json 253 | Accept: 254 | - application/json 255 | X-Auth-Token: _ONE-TIME-TOKEN_ 256 | response: 257 | status: 258 | code: 200 259 | message: 260 | headers: 261 | Server: 262 | - Jetty(8.0.y.z-SNAPSHOT) 263 | X-Varnish: _VARNISH-REQUEST-ID_ 264 | Vary: 265 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 266 | Cache-Control: 267 | - s-maxage=1800 268 | Content-Type: 269 | - application/json 270 | x-purge-key: 271 | - /flavors 272 | Date: 273 | - Fri, 17 Jan 2014 19:13:22 GMT 274 | Via: 275 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 276 | Connection: 277 | - close 278 | Last-Modified: 279 | - Tue, 18 Mar 2008 17:54:15 GMT 280 | Age: 281 | - '0' 282 | Content-Length: 283 | - '61' 284 | body: 285 | encoding: US-ASCII 286 | string: ! '{"flavor":{"id":5,"ram":4096,"disk":160,"name":"4GB server"}}' 287 | http_version: 288 | recorded_at: Fri, 17 Jan 2014 19:13:22 GMT 289 | - request: 290 | method: get 291 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/6.json 292 | body: 293 | encoding: US-ASCII 294 | string: '' 295 | headers: 296 | User-Agent: 297 | - fog/1.19.0 298 | Content-Type: 299 | - application/json 300 | Accept: 301 | - application/json 302 | X-Auth-Token: _ONE-TIME-TOKEN_ 303 | response: 304 | status: 305 | code: 200 306 | message: 307 | headers: 308 | Server: 309 | - Jetty(8.0.y.z-SNAPSHOT) 310 | X-Varnish: _VARNISH-REQUEST-ID_ 311 | Vary: 312 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 313 | Cache-Control: 314 | - s-maxage=1800 315 | Content-Type: 316 | - application/json 317 | x-purge-key: 318 | - /flavors 319 | Date: 320 | - Fri, 17 Jan 2014 19:13:22 GMT 321 | Via: 322 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 323 | Connection: 324 | - close 325 | Last-Modified: 326 | - Mon, 28 Jan 2008 13:35:30 GMT 327 | Age: 328 | - '0' 329 | Content-Length: 330 | - '61' 331 | body: 332 | encoding: US-ASCII 333 | string: ! '{"flavor":{"id":6,"ram":8192,"disk":320,"name":"8GB server"}}' 334 | http_version: 335 | recorded_at: Fri, 17 Jan 2014 19:13:22 GMT 336 | - request: 337 | method: get 338 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/7.json 339 | body: 340 | encoding: US-ASCII 341 | string: '' 342 | headers: 343 | User-Agent: 344 | - fog/1.19.0 345 | Content-Type: 346 | - application/json 347 | Accept: 348 | - application/json 349 | X-Auth-Token: _ONE-TIME-TOKEN_ 350 | response: 351 | status: 352 | code: 200 353 | message: 354 | headers: 355 | Server: 356 | - Jetty(8.0.y.z-SNAPSHOT) 357 | X-Varnish: _VARNISH-REQUEST-ID_ 358 | Vary: 359 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 360 | Cache-Control: 361 | - s-maxage=1800 362 | Content-Type: 363 | - application/json 364 | x-purge-key: 365 | - /flavors 366 | Date: 367 | - Fri, 17 Jan 2014 19:13:23 GMT 368 | Via: 369 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 370 | Connection: 371 | - close 372 | Last-Modified: 373 | - Fri, 01 Apr 2011 00:02:01 GMT 374 | Age: 375 | - '0' 376 | Content-Length: 377 | - '65' 378 | body: 379 | encoding: US-ASCII 380 | string: ! '{"flavor":{"id":7,"ram":15872,"disk":620,"name":"15.5GB server"}}' 381 | http_version: 382 | recorded_at: Fri, 17 Jan 2014 19:13:23 GMT 383 | - request: 384 | method: get 385 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/8.json 386 | body: 387 | encoding: US-ASCII 388 | string: '' 389 | headers: 390 | User-Agent: 391 | - fog/1.19.0 392 | Content-Type: 393 | - application/json 394 | Accept: 395 | - application/json 396 | X-Auth-Token: _ONE-TIME-TOKEN_ 397 | response: 398 | status: 399 | code: 200 400 | message: 401 | headers: 402 | Server: 403 | - Jetty(8.0.y.z-SNAPSHOT) 404 | X-Varnish: _VARNISH-REQUEST-ID_ 405 | Vary: 406 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 407 | Cache-Control: 408 | - s-maxage=1800 409 | Content-Type: 410 | - application/json 411 | x-purge-key: 412 | - /flavors 413 | Date: 414 | - Fri, 17 Jan 2014 19:13:23 GMT 415 | Via: 416 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 417 | Connection: 418 | - close 419 | Last-Modified: 420 | - Tue, 06 Dec 2011 17:31:55 GMT 421 | Age: 422 | - '0' 423 | Content-Length: 424 | - '64' 425 | body: 426 | encoding: US-ASCII 427 | string: ! '{"flavor":{"id":8,"ram":30720,"disk":1200,"name":"30GB server"}}' 428 | http_version: 429 | recorded_at: Fri, 17 Jan 2014 19:13:23 GMT 430 | - request: 431 | method: post 432 | uri: https://identity.api.rackspacecloud.com/v2.0/tokens 433 | body: 434 | encoding: UTF-8 435 | string: ! '{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"_RAX_USERNAME_","apiKey":"_RAX_PASSWORD_"}}}' 436 | headers: 437 | User-Agent: 438 | - fog/1.20.0 439 | Content-Type: 440 | - application/json 441 | Accept: 442 | - application/json 443 | X-Auth-Token: _ONE-TIME-TOKEN_ 444 | response: 445 | status: 446 | code: 200 447 | message: 448 | headers: 449 | Server: 450 | - nginx/0.8.55 451 | Date: 452 | - Tue, 04 Mar 2014 21:23:36 GMT 453 | Content-Type: 454 | - application/json 455 | Transfer-Encoding: 456 | - '' 457 | Connection: 458 | - close 459 | vary: 460 | - Accept, Accept-Encoding, X-Auth-Token 461 | VIA: 462 | - 1.0 Repose (Repose/2.3.5) 463 | Front-End-Https: 464 | - 'on' 465 | body: 466 | encoding: US-ASCII 467 | string: ! '{"access":{"token":{"id":"_ONE-TIME-TOKEN_","expires":"2014-03-05T06:42:51.029Z","tenant":{"id":"000000","name":"000000"},"RAX-AUTH:authenticatedBy":["APIKEY"]},"serviceCatalog":[{"name":"cloudFiles","endpoints":[{"region":"DFW","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.dfw1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.dfw1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"ORD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.ord1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.ord1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"SYD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.syd2.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.syd2.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"IAD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.iad3.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.iad3.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"HKG","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/storage101.hkg1.clouddrive.com\/v1\/_CDN-TENANT-NAME_","internalURL":"https:\/\/snet-storage101.hkg1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"}],"type":"object-store"},{"name":"cloudFilesCDN","endpoints":[{"region":"DFW","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn1.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"ORD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn2.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"SYD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn4.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"IAD","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn5.clouddrive.com\/v1\/_CDN-TENANT-NAME_"},{"region":"HKG","tenantId":"_CDN-TENANT-NAME_","publicURL":"https:\/\/cdn6.clouddrive.com\/v1\/_CDN-TENANT-NAME_"}],"type":"rax:object-cdn"},{"name":"cloudBlockStorage","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.blockstorage.api.rackspacecloud.com\/v1\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.blockstorage.api.rackspacecloud.com\/v1\/000000"}],"type":"volume"},{"name":"cloudDatabases","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.databases.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.databases.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:database"},{"name":"cloudLoadBalancers","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.loadbalancers.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:load-balancer"},{"name":"cloudServersOpenStack","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/syd.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/syd.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/ord.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/ord.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/dfw.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/dfw.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/iad.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/iad.servers.api.rackspacecloud.com\/","versionId":"2"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.servers.api.rackspacecloud.com\/v2\/000000","versionInfo":"https:\/\/hkg.servers.api.rackspacecloud.com\/v2","versionList":"https:\/\/hkg.servers.api.rackspacecloud.com\/","versionId":"2"}],"type":"compute"},{"name":"cloudQueues","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-iad.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-ord.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-dfw.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-syd.queues.api.rackspacecloud.com\/v1\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.queues.api.rackspacecloud.com\/v1\/000000","internalURL":"https:\/\/snet-hkg.queues.api.rackspacecloud.com\/v1\/000000"}],"type":"rax:queues"},{"name":"autoscale","endpoints":[{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.autoscale.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.autoscale.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:autoscale"},{"name":"cloudOrchestration","endpoints":[{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.orchestration.api.rackspacecloud.com\/v1\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.orchestration.api.rackspacecloud.com\/v1\/000000"}],"type":"orchestration"},{"name":"cloudBackup","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.backup.api.rackspacecloud.com\/v1.0\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.backup.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:backup"},{"name":"cloudImages","endpoints":[{"region":"IAD","tenantId":"000000","publicURL":"https:\/\/iad.images.api.rackspacecloud.com\/v2\/000000"},{"region":"ORD","tenantId":"000000","publicURL":"https:\/\/ord.images.api.rackspacecloud.com\/v2\/000000"},{"region":"DFW","tenantId":"000000","publicURL":"https:\/\/dfw.images.api.rackspacecloud.com\/v2\/000000"},{"region":"SYD","tenantId":"000000","publicURL":"https:\/\/syd.images.api.rackspacecloud.com\/v2\/000000"},{"region":"HKG","tenantId":"000000","publicURL":"https:\/\/hkg.images.api.rackspacecloud.com\/v2\/000000"}],"type":"image"},{"name":"cloudDNS","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/dns.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:dns"},{"name":"cloudMonitoring","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/monitoring.api.rackspacecloud.com\/v1.0\/000000"}],"type":"rax:monitor"},{"name":"cloudServers","endpoints":[{"tenantId":"000000","publicURL":"https:\/\/servers.api.rackspacecloud.com\/v1.0\/000000","versionInfo":"https:\/\/servers.api.rackspacecloud.com\/v1.0","versionList":"https:\/\/servers.api.rackspacecloud.com\/","versionId":"1.0"}],"type":"compute"}],"user":{"id":"296063","roles":[{"id":"10000150","description":"Checkmate 468 | Access role","name":"checkmate"},{"tenantId":"_CDN-TENANT-NAME_","id":"5","description":"A 469 | Role that allows a user access to keystone Service methods","name":"object-store:default"},{"tenantId":"000000","id":"6","description":"A 470 | Role that allows a user access to keystone Service methods","name":"compute:default"},{"id":"3","description":"User 471 | Admin Role.","name":"identity:user-admin"}],"name":"_RAX_USERNAME_","RAX-AUTH:defaultRegion":"DFW"}}}' 472 | http_version: 473 | recorded_at: Tue, 04 Mar 2014 21:23:37 GMT 474 | - request: 475 | method: get 476 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/detail.json 477 | body: 478 | encoding: US-ASCII 479 | string: '' 480 | headers: 481 | User-Agent: 482 | - fog/1.20.0 483 | Content-Type: 484 | - application/json 485 | Accept: 486 | - application/json 487 | X-Auth-Token: _ONE-TIME-TOKEN_ 488 | response: 489 | status: 490 | code: 200 491 | message: 492 | headers: 493 | Server: 494 | - Jetty(8.0.y.z-SNAPSHOT) 495 | X-Varnish: _VARNISH-REQUEST-ID_ 496 | Vary: 497 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 498 | Cache-Control: 499 | - s-maxage=1800 500 | Content-Type: 501 | - application/json 502 | x-purge-key: 503 | - /flavors 504 | Date: 505 | - Tue, 04 Mar 2014 21:23:37 GMT 506 | Via: 507 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 508 | Connection: 509 | - close 510 | Last-Modified: 511 | - Tue, 06 Dec 2011 17:31:55 GMT 512 | Age: 513 | - '0' 514 | Content-Length: 515 | - '422' 516 | body: 517 | encoding: US-ASCII 518 | string: ! '{"flavors":[{"id":1,"ram":256,"disk":10,"name":"256 server"},{"id":2,"ram":512,"disk":20,"name":"512 519 | server"},{"id":3,"ram":1024,"disk":40,"name":"1GB server"},{"id":4,"ram":2048,"disk":80,"name":"2GB 520 | server"},{"id":5,"ram":4096,"disk":160,"name":"4GB server"},{"id":6,"ram":8192,"disk":320,"name":"8GB 521 | server"},{"id":7,"ram":15872,"disk":620,"name":"15.5GB server"},{"id":8,"ram":30720,"disk":1200,"name":"30GB 522 | server"}]}' 523 | http_version: 524 | recorded_at: Tue, 04 Mar 2014 21:23:37 GMT 525 | - request: 526 | method: get 527 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/1.json 528 | body: 529 | encoding: US-ASCII 530 | string: '' 531 | headers: 532 | User-Agent: 533 | - fog/1.20.0 534 | Content-Type: 535 | - application/json 536 | Accept: 537 | - application/json 538 | X-Auth-Token: _ONE-TIME-TOKEN_ 539 | response: 540 | status: 541 | code: 200 542 | message: 543 | headers: 544 | Server: 545 | - Jetty(8.0.y.z-SNAPSHOT) 546 | X-Varnish: _VARNISH-REQUEST-ID_ 547 | Vary: 548 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 549 | Cache-Control: 550 | - s-maxage=1800 551 | Content-Type: 552 | - application/json 553 | x-purge-key: 554 | - /flavors 555 | Date: 556 | - Tue, 04 Mar 2014 21:23:38 GMT 557 | Via: 558 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 559 | Connection: 560 | - close 561 | Last-Modified: 562 | - Wed, 19 Sep 2007 18:24:59 GMT 563 | Age: 564 | - '0' 565 | Content-Length: 566 | - '59' 567 | body: 568 | encoding: US-ASCII 569 | string: ! '{"flavor":{"id":1,"ram":256,"disk":10,"name":"256 server"}}' 570 | http_version: 571 | recorded_at: Tue, 04 Mar 2014 21:23:38 GMT 572 | - request: 573 | method: get 574 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/2.json 575 | body: 576 | encoding: US-ASCII 577 | string: '' 578 | headers: 579 | User-Agent: 580 | - fog/1.20.0 581 | Content-Type: 582 | - application/json 583 | Accept: 584 | - application/json 585 | X-Auth-Token: _ONE-TIME-TOKEN_ 586 | response: 587 | status: 588 | code: 200 589 | message: 590 | headers: 591 | Server: 592 | - Jetty(8.0.y.z-SNAPSHOT) 593 | X-Varnish: _VARNISH-REQUEST-ID_ 594 | Vary: 595 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 596 | Cache-Control: 597 | - s-maxage=1800 598 | Content-Type: 599 | - application/json 600 | x-purge-key: 601 | - /flavors 602 | Date: 603 | - Tue, 04 Mar 2014 21:23:38 GMT 604 | Via: 605 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 606 | Connection: 607 | - close 608 | Last-Modified: 609 | - Wed, 19 Sep 2007 18:25:10 GMT 610 | Age: 611 | - '0' 612 | Content-Length: 613 | - '59' 614 | body: 615 | encoding: US-ASCII 616 | string: ! '{"flavor":{"id":2,"ram":512,"disk":20,"name":"512 server"}}' 617 | http_version: 618 | recorded_at: Tue, 04 Mar 2014 21:23:39 GMT 619 | - request: 620 | method: get 621 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/3.json 622 | body: 623 | encoding: US-ASCII 624 | string: '' 625 | headers: 626 | User-Agent: 627 | - fog/1.20.0 628 | Content-Type: 629 | - application/json 630 | Accept: 631 | - application/json 632 | X-Auth-Token: _ONE-TIME-TOKEN_ 633 | response: 634 | status: 635 | code: 200 636 | message: 637 | headers: 638 | Server: 639 | - Jetty(8.0.y.z-SNAPSHOT) 640 | X-Varnish: _VARNISH-REQUEST-ID_ 641 | Vary: 642 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 643 | Cache-Control: 644 | - s-maxage=1800 645 | Content-Type: 646 | - application/json 647 | x-purge-key: 648 | - /flavors 649 | Date: 650 | - Tue, 04 Mar 2014 21:23:39 GMT 651 | Via: 652 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 653 | Connection: 654 | - close 655 | Last-Modified: 656 | - Fri, 21 Sep 2007 23:11:39 GMT 657 | Age: 658 | - '0' 659 | Content-Length: 660 | - '60' 661 | body: 662 | encoding: US-ASCII 663 | string: ! '{"flavor":{"id":3,"ram":1024,"disk":40,"name":"1GB server"}}' 664 | http_version: 665 | recorded_at: Tue, 04 Mar 2014 21:23:39 GMT 666 | - request: 667 | method: get 668 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/4.json 669 | body: 670 | encoding: US-ASCII 671 | string: '' 672 | headers: 673 | User-Agent: 674 | - fog/1.20.0 675 | Content-Type: 676 | - application/json 677 | Accept: 678 | - application/json 679 | X-Auth-Token: _ONE-TIME-TOKEN_ 680 | response: 681 | status: 682 | code: 200 683 | message: 684 | headers: 685 | Server: 686 | - Jetty(8.0.y.z-SNAPSHOT) 687 | X-Varnish: _VARNISH-REQUEST-ID_ 688 | Vary: 689 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 690 | Cache-Control: 691 | - s-maxage=1800 692 | Content-Type: 693 | - application/json 694 | x-purge-key: 695 | - /flavors 696 | Date: 697 | - Tue, 04 Mar 2014 21:23:40 GMT 698 | Via: 699 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 700 | Connection: 701 | - close 702 | Last-Modified: 703 | - Wed, 19 Sep 2007 18:25:33 GMT 704 | Age: 705 | - '0' 706 | Content-Length: 707 | - '60' 708 | body: 709 | encoding: US-ASCII 710 | string: ! '{"flavor":{"id":4,"ram":2048,"disk":80,"name":"2GB server"}}' 711 | http_version: 712 | recorded_at: Tue, 04 Mar 2014 21:23:40 GMT 713 | - request: 714 | method: get 715 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/5.json 716 | body: 717 | encoding: US-ASCII 718 | string: '' 719 | headers: 720 | User-Agent: 721 | - fog/1.20.0 722 | Content-Type: 723 | - application/json 724 | Accept: 725 | - application/json 726 | X-Auth-Token: _ONE-TIME-TOKEN_ 727 | response: 728 | status: 729 | code: 200 730 | message: 731 | headers: 732 | Server: 733 | - Jetty(8.0.y.z-SNAPSHOT) 734 | X-Varnish: _VARNISH-REQUEST-ID_ 735 | Vary: 736 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 737 | Cache-Control: 738 | - s-maxage=1800 739 | Content-Type: 740 | - application/json 741 | x-purge-key: 742 | - /flavors 743 | Date: 744 | - Tue, 04 Mar 2014 21:23:41 GMT 745 | Via: 746 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 747 | Connection: 748 | - close 749 | Last-Modified: 750 | - Tue, 18 Mar 2008 17:54:15 GMT 751 | Age: 752 | - '0' 753 | Content-Length: 754 | - '61' 755 | body: 756 | encoding: US-ASCII 757 | string: ! '{"flavor":{"id":5,"ram":4096,"disk":160,"name":"4GB server"}}' 758 | http_version: 759 | recorded_at: Tue, 04 Mar 2014 21:23:41 GMT 760 | - request: 761 | method: get 762 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/6.json 763 | body: 764 | encoding: US-ASCII 765 | string: '' 766 | headers: 767 | User-Agent: 768 | - fog/1.20.0 769 | Content-Type: 770 | - application/json 771 | Accept: 772 | - application/json 773 | X-Auth-Token: _ONE-TIME-TOKEN_ 774 | response: 775 | status: 776 | code: 200 777 | message: 778 | headers: 779 | Server: 780 | - Jetty(8.0.y.z-SNAPSHOT) 781 | X-Varnish: _VARNISH-REQUEST-ID_ 782 | Vary: 783 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 784 | Cache-Control: 785 | - s-maxage=1800 786 | Content-Type: 787 | - application/json 788 | x-purge-key: 789 | - /flavors 790 | Date: 791 | - Tue, 04 Mar 2014 21:23:41 GMT 792 | Via: 793 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 794 | Connection: 795 | - close 796 | Last-Modified: 797 | - Mon, 28 Jan 2008 13:35:30 GMT 798 | Age: 799 | - '0' 800 | Content-Length: 801 | - '61' 802 | body: 803 | encoding: US-ASCII 804 | string: ! '{"flavor":{"id":6,"ram":8192,"disk":320,"name":"8GB server"}}' 805 | http_version: 806 | recorded_at: Tue, 04 Mar 2014 21:23:41 GMT 807 | - request: 808 | method: get 809 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/7.json 810 | body: 811 | encoding: US-ASCII 812 | string: '' 813 | headers: 814 | User-Agent: 815 | - fog/1.20.0 816 | Content-Type: 817 | - application/json 818 | Accept: 819 | - application/json 820 | X-Auth-Token: _ONE-TIME-TOKEN_ 821 | response: 822 | status: 823 | code: 200 824 | message: 825 | headers: 826 | Server: 827 | - Jetty(8.0.y.z-SNAPSHOT) 828 | X-Varnish: _VARNISH-REQUEST-ID_ 829 | Vary: 830 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 831 | Cache-Control: 832 | - s-maxage=1800 833 | Content-Type: 834 | - application/json 835 | x-purge-key: 836 | - /flavors 837 | Date: 838 | - Tue, 04 Mar 2014 21:23:42 GMT 839 | Via: 840 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 841 | Connection: 842 | - close 843 | Last-Modified: 844 | - Fri, 01 Apr 2011 00:02:01 GMT 845 | Age: 846 | - '0' 847 | Content-Length: 848 | - '65' 849 | body: 850 | encoding: US-ASCII 851 | string: ! '{"flavor":{"id":7,"ram":15872,"disk":620,"name":"15.5GB server"}}' 852 | http_version: 853 | recorded_at: Tue, 04 Mar 2014 21:23:42 GMT 854 | - request: 855 | method: get 856 | uri: https://servers.api.rackspacecloud.com/v1.0/000000/flavors/8.json 857 | body: 858 | encoding: US-ASCII 859 | string: '' 860 | headers: 861 | User-Agent: 862 | - fog/1.20.0 863 | Content-Type: 864 | - application/json 865 | Accept: 866 | - application/json 867 | X-Auth-Token: _ONE-TIME-TOKEN_ 868 | response: 869 | status: 870 | code: 200 871 | message: 872 | headers: 873 | Server: 874 | - Jetty(8.0.y.z-SNAPSHOT) 875 | X-Varnish: _VARNISH-REQUEST-ID_ 876 | Vary: 877 | - Accept-Encoding, Accept, Accept-Encoding, X-Auth-Token 878 | Cache-Control: 879 | - s-maxage=1800 880 | Content-Type: 881 | - application/json 882 | x-purge-key: 883 | - /flavors 884 | Date: 885 | - Tue, 04 Mar 2014 21:23:42 GMT 886 | Via: 887 | - 1.1 Repose (Repose/2.11.0), 1.1 varnish 888 | Connection: 889 | - close 890 | Last-Modified: 891 | - Tue, 06 Dec 2011 17:31:55 GMT 892 | Age: 893 | - '0' 894 | Content-Length: 895 | - '64' 896 | body: 897 | encoding: US-ASCII 898 | string: ! '{"flavor":{"id":8,"ram":30720,"disk":1200,"name":"30GB server"}}' 899 | http_version: 900 | recorded_at: Tue, 04 Mar 2014 21:23:43 GMT 901 | recorded_with: VCR 2.8.0 902 | --------------------------------------------------------------------------------