diff --git a/.travis.yml b/.travis.yml index 2075783..7da452f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,33 @@ language: ruby -rvm: - - 1.9.3 - - 2.0.0 - - 2.1.0 -script: "appraisal rake" -gemfile: - - Gemfile - - gemfiles/latest_stable.gemfile - - gemfiles/oldest_current.gemfile - - gemfiles/previous_release.gemfile - +before_install: + - rvm @global do gem uninstall bundler --all --force --executables + - gem uninstall bundler --all --force --executables + - gem install bundler -v "$BUNDLER_VERSION" +bundler_args: --without development +matrix: + include: + - gemfile: Gemfile + rvm: 2.1.1 # Just to make sure we're ready... + env: + BUNDLER_VERSION='>= 1.5.2, < 1.8.0' + - gemfile: Gemfile + rvm: 2.0.0 + env: + BUNDLER_VERSION='>= 1.5.2, < 1.8.0' + - gemfile: gemfiles/vagrant_1.7.gemfile + rvm: 2.0.0 + env: + BUNDLER_VERSION='>= 1.5.2, < 1.8.0' + - gemfile: gemfiles/vagrant_1.6.gemfile + rvm: 2.0.0 + env: + BUNDLER_VERSION='>= 1.5.2, < 1.7.0' + - gemfile: gemfiles/vagrant_1.5.gemfile + rvm: 2.0.0 + env: + BUNDLER_VERSION='= 1.5.2' + # The oldest Vagrant/Ruby/Bundler we support + - gemfile: gemfiles/vagrant_1.5.0.gemfile + rvm: 2.0.0 + env: + BUNDLER_VERSION='= 1.5.2' diff --git a/Appraisals b/Appraisals index 9ea31d3..188d771 100644 --- a/Appraisals +++ b/Appraisals @@ -1,14 +1,36 @@ -appraise "latest-stable" do - gem "vagrant", :git => 'git://github.com/mitchellh/vagrant.git', :branch => 'v1.4.2' +# Note: You may need to use bundler 1.5.2 to run `appraisal install` +appraise "vagrant-1.7" do + group :plugins do + gem 'bundler', '>= 1.5.2', '< 1.8.0' + gem "vagrant", :git => 'https://github.com/mitchellh/vagrant', :tag => 'v1.7.1' + end end -# Oldest (current release) -appraise "oldest-current" do - gem "vagrant", :git => 'git://github.com/mitchellh/vagrant.git', :branch => 'v1.4.0' +appraise "vagrant-1.6" do + gem 'bundler', '>= 1.5.2', '< 1.7.0' + group :plugins do + gem "vagrant", :git => 'https://github.com/mitchellh/vagrant', :tag => 'v1.6.5' + end end -# Latest patch (previous release) -appraise "previous-release" do - gem "vagrant", :git => 'git://github.com/mitchellh/vagrant.git', :branch => 'v1.3.5' +appraise "vagrant-1.5" do + gem 'bundler', '= 1.5.2' + group :plugins do + gem "vagrant", :git => 'https://github.com/mitchellh/vagrant', :tag => 'v1.5.4' + end +end + +# Oldest supported +appraise "vagrant-1.5.0" do + gem 'bundler', '= 1.5.2' + group :plugins do + gem "vagrant", :git => 'https://github.com/mitchellh/vagrant', :tag => 'v1.5.4' + end +end + +appraise "windows-wip" do + group :plugins do + gem "vagrant", :git => 'https://github.com/maxlinc/vagrant', :branch => 'winrm-1.3' + end end diff --git a/Gemfile b/Gemfile index c77e9a5..b6b3312 100644 --- a/Gemfile +++ b/Gemfile @@ -1,19 +1,18 @@ source 'https://rubygems.org' - -group :plugins do - gemspec - gem 'vagrant', :git => 'https://github.com/mitchellh/vagrant' +# This group will not be installed on Travis +group :development do + gem 'pry' + # My branch contains a fix for https://github.com/thoughtbot/appraisal/issues/76 + gem 'appraisal', '~> 1.0', git: 'https://github.com/maxlinc/appraisal', branch: 'gemspec_in_group' end -gem "appraisal", "1.0.0.beta2" - -group :development do - # We depend on Vagrant for development, but we don't add it as a - # gem dependency because we expect to be installed within the - # Vagrant environment itself using `vagrant plugin`. +group :test do gem 'coveralls', require: false - gem 'pry' end - \ No newline at end of file +group :plugins do + gem "vagrant", git: "https://github.com/mitchellh/vagrant.git", :branch => 'master' + gemspec +end + diff --git a/README.md b/README.md index bffbdb8..8ebe4e5 100644 --- a/README.md +++ b/README.md @@ -1,127 +1,300 @@ # Vagrant Rackspace Cloud Provider -This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds a +This is a [Vagrant](http://www.vagrantup.com) 1.5+ plugin that adds a [Rackspace Cloud](http://www.rackspace.com/cloud) provider to Vagrant, allowing Vagrant to control and provision machines within Rackspace cloud. -**Note:** This plugin requires Vagrant 1.1+. +**Note:** This plugin requires Vagrant 1.5+. Windows support requires Vagrant 1.6+. ## Features * Boot Rackspace Cloud instances. * SSH into the instances. * Provision the instances with any built-in Vagrant provisioner. -* Minimal synced folder support via `rsync`. +* Sync folders with any built-in Vagrant synchronized folder plugin (e.g. `rsync`) +* Create Rackspace images from a running Vagrant box -## Usage +## Installation -Install using standard Vagrant 1.1+ plugin installation methods. After -installing, `vagrant up` and specify the `rackspace` provider. An example is -shown below. +Install using standard Vagrant plugin installation methods. ``` $ vagrant plugin install vagrant-rackspace -... -$ vagrant up --provider=rackspace -... ``` -Of course prior to doing this, you'll need to obtain an Rackspace-compatible -box file for Vagrant. +## Usage -### CentOS / RHEL (sudo: sorry, you must have a tty to run sudo) +Once the plugin is installed, you use it with `vagrant up` by specifing +the `rackspace` provider: +``` +$ vagrant up --provider=rackspace +``` -The default configuration of the RHEL family of Linux distributions requires a tty in order to run sudo. Vagrant does not connect with a tty by default, so you may experience the error: -> sudo: sorry, you must have a tty to run sudo +You'll need a Vagrantfile in order to test it out. You can generate a sample +Vagrantfile with `vagrant init`. Here's an example with Rackspace configuration: -The best way to deal with this error is to upgrade to Vagrant 1.4 or later, and enable: ```ruby -config.ssh.pty = true +Vagrant.configure("2") do |config| + # The box is optional in newer versions of Vagrant + # config.vm.box = "dummy" + + config.vm.provider :rackspace do |rs| + rs.username = "your-rackspace-user-name" + rs.api_key = "your-rackspace-api-key" + rs.rackspace_region = :ord + rs.flavor = /1 GB Performance/ + rs.image = /Ubuntu/ + rs.metadata = {"key" => "value"} # optional + end +end ``` -## Quick Start +Set up environment variables on your shell, for frequently used parameters, +especially your username and api key, if you plan to share your vagrant files. this +will prevent accidentally divulging your keys. -After installing the plugin (instructions above), the quickest way to get -started is to actually use a dummy Rackspace box and specify all the details -manually within a `config.vm.provider` block. So first, add the dummy -box using any name you want: +```tcsh + .tcshrc: + setenv RAX_USERNAME "your-rackspace-user-name" + setenv RAX_REG ":region" + setenv API_KEY "your-rackspace-api-key" +``` + +```bash + .bashrc or .zshrc + export RAX_USERNAME="your-rackspace-user-name" + export RAX_REG=":region" + export API_KEY="your-rackspace-api-key" +``` + +Change your vagrant file to source your environment. It should look like this: + +```ruby +Vagrant.configure("2") do |config| + # The box is optional in newer versions of Vagrant + # config.vm.box = "dummy" + + config.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] + rs.rackspace_region = ENV['RAX_REG'] + rs.flavor = /1 GB Performance/ + rs.image = /Ubuntu/ + rs.metadata = {"key" => "value"} # optional + end +end +``` +You may be required to use a box, depending on your version of Vagrant. If necessary you can +add the "dummy" box with the command: ``` $ vagrant box add dummy https://github.com/mitchellh/vagrant-rackspace/raw/master/dummy.box -... ``` -And then make a Vagrantfile that looks like the following, filling in -your information where necessary. +Then uncomment the line containing `config.vm.box = "dummy"`. +### RackConnect + +If you are using RackConnect with vagrant, you will need to add the following line to the `config.vm.provider` section to prevent timeouts. + + ``` + rs.rackconnect = true + ``` + +### CentOS / RHEL / Fedora + +The default configuration of the RHEL family of Linux distributions requires a tty in order to run sudo. Vagrant does not connect with a tty by default, so you may experience the error: +> sudo: sorry, you must have a tty to run sudo + +You can tell Vagrant it should use a pseudo-terminal (pty) to get around this issue with the option: +```ruby + config.ssh.pty = true +``` + +However, Vagrant does not always work well with the pty. In particular, rsync may not work. So we recommend +using this configuration for a workaround which will reconfigure the server so a tty is not required to run sudo: + +The following settings show an example of how you can workaround the issue: ```ruby Vagrant.configure("2") do |config| config.vm.box = "dummy" + config.ssh.pty = true config.vm.provider :rackspace do |rs| - rs.username = "YOUR USERNAME" - rs.api_key = "YOUR API KEY" + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] rs.flavor = /1 GB Performance/ - rs.image = /Ubuntu/ - rs.metadata = {"key" => "value"} # optional + rs.image = /^CentOS/ + rs.init_script = 'sed -i\'.bk\' -e \'s/^\(Defaults\s\+requiretty\)/# \1/\' /etc/sudoers' end end ``` -And then run `vagrant up --provider=rackspace`. +### Windows (enabling WinRM) -This will start an Ubuntu 12.04 instance in the DFW datacenter region within -your account. And assuming your SSH information was filled in properly -within your Vagrantfile, SSH and provisioning will work as well. +Vagrant 1.6 and later support WinRM as an alternative to SSH for communicating with Windows machines, though secure WinRM connections at this time. They are expected to be added in a 1.7.x release of Vagrant. -Note that normally a lot of this boilerplate is encoded within the box -file, but the box file used for the quick start, the "dummy" box, has -no preconfigured defaults. +Be aware of the security limitations: +- Vagrant's WinRM support is not as secure as SSH. You should only use it for testing purposes where these warnings are acceptible. If you require a more secure setup you'll need to either configure SSH on Windows, or to wait until for future Vagrant releases with better WinRM security. + - The current Vagrant release (v1.7.0) only supports WinRM as plaintext over HTTP, but [SSL support is in progress](https://github.com/mitchellh/vagrant/pull/4236) and should hopefully be released in the near future. + - The default setup, even with SSL support, uses self-signed certificates. If you want to use a real Certificate Authority you'll need to customize your Windows images or `init_script -### Flavors / Images +If you still choose to use Vagrant and WinRM for development and testing, then you'll need a Windows image with WinRM enabled. WinRM is not enabled by default for the Rackspace images, but you can use the `init_script` configuration option to enable and secure it so Vagrant will be able to connect. This example enables WinRM for both HTTP and HTTPS traffic: - To determine what flavors and images are avliable in your region refer to the [Custom Commands](#custom-commands) section. +```ruby +Vagrant.configure("2") do |config| + config.vm.box = "dummy" -### RackConnect + config.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] + rs.flavor = /1 GB Performance/ + rs.image = 'Windows Server 2012' + rs.init_script = File.read 'bootstrap.cmd' + end +end +``` -If you are using RackConnect with vagrant, you will need to add the following line to the `config.vm.provider` section to prevent timeouts. +You can get a sample [bootstrap.cmd](bootstrap.cmd) file from this repo. - ``` - rs.rackconnect = true - ``` +### Parallel, multi-machine setup + +You can define multiple machines in a single Vagrant file, sourcing +common parameters from your shell environment, for example: + +*Environment* +```tcsh + .tcshrc: + setenv RAX_USERNAME "your-rackspace-user-name" + setenv RAX_REG ":region" + setenv API_KEY "your-rackspace-api-key" + setenv VAGRANT_ADMIN_PASSWORD "your-vagrant-admin-password" +``` + +```bash + .bashrc or .zshrc + export RAX_USERNAME="your-rackspace-user-name" + export RAX_REG=":region" + export API_KEY="your-rackspace-api-key" + export VAGRANT_ADMIN_PASSWORD="your-vagrant-admin-password" +``` + + +*Vagrantfile:* +```ruby +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "dummy" + + config.vm.define :ubuntu do |ubuntu| + ubuntu.ssh.private_key_path = '~/.ssh/id_rsa' + ubuntu.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.api_key = ENV['RAX_API_KEY'] + rs.flavor = /1 GB Performance/ + rs.image = /Ubuntu/ + rs.rackspace_region = :iad + rs.public_key_path = '~/.ssh/id_rsa.pub' + end + end + + config.vm.define :centos do |centos| + centos.ssh.private_key_path = '~/.ssh/id_rsa' + centos.ssh.pty = true + centos.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.api_key = ENV['RAX_API_KEY'] + rs.flavor = /1 GB Performance/ + rs.image = /^CentOS/ # Don't match OnMetal - CentOS + rs.rackspace_region = :iad + rs.public_key_path = '~/.ssh/id_rsa.pub' + rs.init_script = 'sed -i\'.bk\' -e \'s/^\(Defaults\s\+requiretty\)/# \1/\' /etc/sudoers' + end + end + + config.vm.define :windows do |windows| + windows.vm.provision :shell, :inline => 'Write-Output "WinRM is working!"' + windows.vm.communicator = :winrm + windows.winrm.username = 'Administrator' + windows.winrm.password = ENV['VAGRANT_ADMIN_PASSWORD'] + begin + windows.winrm.transport = :ssl + windows.winrm.ssl_peer_verification = false + rescue + puts "Warning: Vagrant #{Vagrant::VERSION} does not support WinRM over SSL." + end + windows.vm.synced_folder ".", "/vagrant", disabled: true + windows.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.flavor = /2 GB Performance/ + rs.image = 'Windows Server 2012' + rs.rackspace_region = ENV['RAX_REG'] ||= 'dfw' + rs.init_script = File.read 'bootstrap.cmd' + end + end +end +``` + +You than can then launch them all with `vagrant up --provider rackspace`, or a specific server +with `vagrant up --provider rackspace `. + +Vagrant will create all machines simultaneously when you have multi-machine setup. If you want to +create them one at a time or have any trouble, you can use the `--no-parallel` option. ## Custom Commands -The plugin includes several Rackspace-specific vagrant commands. You can get the +The plugin includes several Rackspace-specific vagrant commands. You can get the list of available commands with `vagrant rackspace -h`. -If you want to know what images or flavors are available for a machine, you can use: +### Flavors / Images + +You can list all available images with the command: ``` $ vagrant rackspace images +``` + +``` $ vagrant rackspace flavors ``` -In a multi-machine Vagrantfile you can also query for a single machine: +If you have a multi-machine setup than this will show the images/flavors for each machine. This seems +a bit repetitive, but since machines can be configured for different regions or even accounts they may +have a different set of available images or flavors. You can also get the list for a specific machine by specifying it's name as an argument: + ``` $ vagrant rackspace images $ vagrant rackspace flavors ``` -These command will connect to Rackspace using the settings associated with the machine, -and query the region to get the list of available images or flavors. +## Custom Commands -## Box Format +The plugin includes several Rackspace-specific vagrant commands. You can get the +list of available commands with `vagrant rackspace -h`. -Every provider in Vagrant must introduce a custom box format. This -provider introduces `rackspace` boxes. You can view an example box in -the [example_box/ directory](https://github.com/mitchellh/vagrant-rackspace/tree/master/example_box). -That directory also contains instructions on how to build a box. +For example to list all available images for a machine you can use: -The box format is basically just the required `metadata.json` file -along with a `Vagrantfile` that does default settings for the -provider-specific configuration for this provider. +``` +$ vagrant rackspace images +``` + +In a multi-machine Vagrantfile you can also query for a single machine: + +``` +$ vagrant rackspace images +``` + +These commands will connect to Rackspace using the settings associated with the machine, +and query the region to get the list of available flavors, images, keypairs, networks and servers. ## Configuration @@ -134,16 +307,16 @@ This provider exposes quite a few provider-specific configuration options: * `image` - The server image to boot. This can be a string matching the exact ID or name of the image, or this can be a regular expression to partially match some image. -* `rackspace_region` - The region to hit. By default this is :dfw. Valid options are: -:dfw, :ord, :lon, :iad, :syd. Users should preference using this setting over `rackspace_compute_url` setting. -* `rackspace_compute_url` - The compute_url to hit. This is good for custom endpoints. +* `rackspace_region` - The region to hit. By default this is :dfw. Valid options are: +:dfw, :ord, :lon, :iad, :syd. Users should preference using this setting over `rackspace_compute_url` setting. +* `rackspace_compute_url` - The compute_url to hit. This is good for custom endpoints. * `rackspace_auth_url` - The endpoint to authentication against. By default, vagrant will use the global rackspace authentication endpoint for all regions with the exception of :lon. IF :lon region is specified vagrant will authenticate against the UK authentication endpoint. * `public_key_path` - The path to a public key to initialize with the remote server. This should be the matching pair for the private key configured with `config.ssh.private_key_path` on Vagrant. -* `key_name` - If a public key has been [uploaded to the account already](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ServersKeyPairs-d1e2545.html), the uploaded key can be used to initialize the remote server by providing its name. The uploaded public key should be the matching pair for the private key configured +* `key_name` - If a public key has been [uploaded to the account already](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ServersKeyPairs-d1e2545.html), the uploaded key can be used to initialize the remote server by providing its name. The uploaded public key should be the matching pair for the private key configured with `config.ssh.private_key_path` on Vagrant. * `server_name` - The name of the server within RackSpace Cloud. This defaults to the name of the Vagrant machine (via `config.vm.define`), but @@ -160,13 +333,15 @@ Vagrant.configure("2") do |config| # ... other stuff config.vm.provider :rackspace do |rs| - rs.username = "mitchellh" - rs.api_key = "foobarbaz" + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] end end ``` -## Networks +You can find a more complete list the documentation for the [Config class](http://www.rubydoc.info/gems/vagrant-rackspace/VagrantPlugins/Rackspace/Config). + +### Networks Networking features in the form of `config.vm.network` are not supported with `vagrant-rackspace`, currently. If any of these are @@ -177,23 +352,21 @@ However, you may attach a VM to an isolated [Cloud Network](http://www.rackspace ```ruby config.vm.provider :rackspace do |rs| - rs.username = "mitchellh" - rs.api_key = "foobarbaz" + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] rs.network '443aff42-be57-effb-ad30-c097c1e4503f' rs.network '5e738e11-def2-4a75-ad1e-05bbe3b49efe' rs.network :service_net, :attached => false end ``` -## Synced Folders +### Synced Folders + +You can use this provider with the Vagrant [synced folders](https://docs.vagrantup.com/v2/synced-folders/basic_usage.html). The default type should be `rsync` for most images, with the possible exception of Windows. -There is minimal support for synced folders. Upon `vagrant up`, -`vagrant reload`, and `vagrant provision`, the Rackspace provider will use -`rsync` (if available) to uni-directionally sync the folder to -the remote machine over SSH. +### Plugins -This is good enough for all built-in Vagrant provisioners (shell, -chef, and puppet) to work! +Vagrant has great support for plugins and many of them should work alongside `vagrant-rackspace`. See the list of [Available Vagrant Plugins](https://github.com/mitchellh/vagrant/wiki/Available-Vagrant-Plugins). ## Development diff --git a/Vagrantfile b/Vagrantfile index 5edc089..5b41e31 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -4,125 +4,68 @@ # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" +%w{RAX_USERNAME RAX_API_KEY VAGRANT_ADMIN_PASSWORD}.each do |var| + abort "Please set the environment variable #{var} in order to run the test" unless ENV.key? var +end + Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - Vagrant.require_plugin "vagrant-rackspace" # All Vagrant configuration is done here. The most common configuration # options are documented and commented below. For a complete reference, # please see the online documentation at vagrantup.com. # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "dummy" - config.vm.provider :rackspace do |rs| - rs.username = ENV['RAX_USERNAME'] - rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] - rs.api_key = ENV['RAX_API_KEY'] - rs.flavor = /1 GB Performance/ - rs.image = /Ubuntu/ - rs.rackspace_region = :iad - # rs.rsync_include 'PATTERN' # per man page for rsync + config.vm.define :ubuntu do |ubuntu| + ubuntu.ssh.private_key_path = '~/.ssh/id_rsa' + ubuntu.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.api_key = ENV['RAX_API_KEY'] + rs.flavor = /1 GB Performance/ + rs.image = /Ubuntu/ + rs.rackspace_region = :iad + rs.public_key_path = '~/.ssh/id_rsa.pub' + end end - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - # config.vm.box_url = "http://domain.com/path/to/above.box" - - # Create a forwarded port mapping which allows access to a specific port - # within the machine from a port on the host machine. In the example below, - # accessing "localhost:8080" will access port 80 on the guest machine. - # config.vm.network :forwarded_port, guest: 80, host: 8080 - - # Create a private network, which allows host-only access to the machine - # using a specific IP. - # config.vm.network :private_network, ip: "192.168.33.10" - - # Create a public network, which generally matched to bridged network. - # Bridged networks make the machine appear as another physical device on - # your network. - # config.vm.network :public_network - - # If true, then any SSH connections made will enable agent forwarding. - # Default value: false - # config.ssh.forward_agent = true - # Share an additional folder to the guest VM. The first argument is - # the path on the host to the actual folder. The second argument is - # the path on the guest to mount the folder. And the optional third - # argument is a set of non-required options. - # config.vm.synced_folder "../data", "/vagrant_data" - - # Provider-specific configuration so you can fine-tune various - # backing providers for Vagrant. These expose provider-specific options. - # Example for VirtualBox: - # - # config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - # end - # - # View the documentation for the provider you're using for more - # information on available options. - - # Enable provisioning with Puppet stand alone. Puppet manifests - # are contained in a directory path relative to this Vagrantfile. - # You will need to create the manifests directory and a manifest in - # the file base.pp in the manifests_path directory. - # - # An example Puppet manifest to provision the message of the day: - # - # # group { "puppet": - # # ensure => "present", - # # } - # # - # # File { owner => 0, group => 0, mode => 0644 } - # # - # # file { '/etc/motd': - # # content => "Welcome to your Vagrant-built virtual machine! - # # Managed by Puppet.\n" - # # } - # - # config.vm.provision :puppet do |puppet| - # puppet.manifests_path = "manifests" - # puppet.manifest_file = "init.pp" - # end - - # Enable provisioning with chef solo, specifying a cookbooks path, roles - # path, and data_bags path (all relative to this Vagrantfile), and adding - # some recipes and/or roles. - # - # config.vm.provision :chef_solo do |chef| - # chef.cookbooks_path = "../my-recipes/cookbooks" - # chef.roles_path = "../my-recipes/roles" - # chef.data_bags_path = "../my-recipes/data_bags" - # chef.add_recipe "mysql" - # chef.add_role "web" - # - # # You may also specify custom JSON attributes: - # chef.json = { :mysql_password => "foo" } - # end + config.vm.define :centos do |centos| + centos.ssh.private_key_path = '~/.ssh/id_rsa' + centos.ssh.pty = true + centos.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.api_key = ENV['RAX_API_KEY'] + rs.flavor = /1 GB Performance/ + rs.image = /^CentOS/ # Don't match OnMetal - CentOS + rs.rackspace_region = :iad + rs.public_key_path = '~/.ssh/id_rsa.pub' + rs.init_script = 'sed -i\'.bk\' -e \'s/^\(Defaults\s\+requiretty\)/# \1/\' /etc/sudoers' + end + end - # Enable provisioning with chef server, specifying the chef server URL, - # and the path to the validation key (relative to this Vagrantfile). - # - # The Opscode Platform uses HTTPS. Substitute your organization for - # ORGNAME in the URL and validation key. - # - # If you have your own Chef Server, use the appropriate URL, which may be - # HTTP instead of HTTPS depending on your configuration. Also change the - # validation key to validation.pem. - # - # config.vm.provision :chef_client do |chef| - # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" - # chef.validation_key_path = "ORGNAME-validator.pem" - # end - # - # If you're using the Opscode platform, your validator client is - # ORGNAME-validator, replacing ORGNAME with your organization name. - # - # If you have your own Chef Server, the default validation client name is - # chef-validator, unless you changed the configuration. - # - # chef.validation_client_name = "ORGNAME-validator" + if Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new('1.6.0') + config.vm.define :windows do |windows| + windows.vm.provision :shell, :inline => 'Write-Output "WinRM is working!"' + windows.vm.communicator = :winrm + windows.winrm.username = 'Administrator' + windows.winrm.password = ENV['VAGRANT_ADMIN_PASSWORD'] + begin + windows.winrm.transport = :ssl + windows.winrm.ssl_peer_verification = false + rescue + puts "Warning: Vagrant #{Vagrant::VERSION} does not support WinRM over SSL." + end + windows.vm.synced_folder ".", "/vagrant", disabled: true + windows.vm.provider :rackspace do |rs| + rs.username = ENV['RAX_USERNAME'] + rs.api_key = ENV['RAX_API_KEY'] + rs.admin_password = ENV['VAGRANT_ADMIN_PASSWORD'] + rs.flavor = /2 GB Performance/ + rs.image = 'Windows Server 2012' + rs.rackspace_region = ENV['RAX_REGION'] ||= 'dfw' + rs.init_script = File.read 'bootstrap.cmd' + end + end + end end diff --git a/bootstrap.cmd b/bootstrap.cmd new file mode 100644 index 0000000..a443a29 --- /dev/null +++ b/bootstrap.cmd @@ -0,0 +1,16 @@ +Function SetupWinRM +{ + Param( + [String]$hostname, + [String]$thumbprint + ) + netsh advfirewall firewall set rule group="remote administration" new enable=yes + netsh advfirewall firewall add rule name="WinRM HTTP" dir=in action=allow protocol=TCP localport=5985 + netsh advfirewall firewall add rule name="WinRM HTTPS" dir=in action=allow protocol=TCP localport=5986 + winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"${hostname}`"; CertificateThumbprint=`"${thumbprint}`"}" +} + +$hostname = $env:COMPUTERNAME +$cert = New-SelfSignedCertificate -CertStoreLocation cert:\LocalMachine\My -DnsName $hostname +$thumbprint = $cert.Thumbprint +SetupWinRM -hostname $hostname -thumbprint $thumbprint diff --git a/gemfiles/latest_stable.gemfile b/gemfiles/latest_stable.gemfile deleted file mode 100644 index 0ea0a09..0000000 --- a/gemfiles/latest_stable.gemfile +++ /dev/null @@ -1,12 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "1.0.0.beta2" -gem "vagrant", :git=>"git://github.com/mitchellh/vagrant.git", :branch=>"v1.4.2" - -group :development do - gem "coveralls", :require=>false -end - -gemspec :path=>".././" diff --git a/gemfiles/oldest_current.gemfile b/gemfiles/oldest_current.gemfile deleted file mode 100644 index aa6121a..0000000 --- a/gemfiles/oldest_current.gemfile +++ /dev/null @@ -1,12 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "1.0.0.beta2" -gem "vagrant", :git=>"git://github.com/mitchellh/vagrant.git", :branch=>"v1.4.0" - -group :development do - gem "coveralls", :require=>false -end - -gemspec :path=>".././" diff --git a/gemfiles/previous_release.gemfile b/gemfiles/previous_release.gemfile deleted file mode 100644 index 1403ac8..0000000 --- a/gemfiles/previous_release.gemfile +++ /dev/null @@ -1,12 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "appraisal", "1.0.0.beta2" -gem "vagrant", :git=>"git://github.com/mitchellh/vagrant.git", :branch=>"v1.3.5" - -group :development do - gem "coveralls", :require=>false -end - -gemspec :path=>".././" diff --git a/gemfiles/vagrant_1.5.0.gemfile b/gemfiles/vagrant_1.5.0.gemfile new file mode 100644 index 0000000..485ca82 --- /dev/null +++ b/gemfiles/vagrant_1.5.0.gemfile @@ -0,0 +1,20 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "bundler", "= 1.5.2" + +group :development do + gem "pry" + gem "appraisal", "~> 1.0", :git => "https://github.com/maxlinc/appraisal", :branch => "gemspec_in_group" +end + +group :test do + gem "coveralls", :require => false +end + +group :plugins do + gem "vagrant", :git => "https://github.com/mitchellh/vagrant", :tag => "v1.5.4" + + gemspec :path => "../" +end diff --git a/gemfiles/vagrant_1.5.gemfile b/gemfiles/vagrant_1.5.gemfile new file mode 100644 index 0000000..485ca82 --- /dev/null +++ b/gemfiles/vagrant_1.5.gemfile @@ -0,0 +1,20 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "bundler", "= 1.5.2" + +group :development do + gem "pry" + gem "appraisal", "~> 1.0", :git => "https://github.com/maxlinc/appraisal", :branch => "gemspec_in_group" +end + +group :test do + gem "coveralls", :require => false +end + +group :plugins do + gem "vagrant", :git => "https://github.com/mitchellh/vagrant", :tag => "v1.5.4" + + gemspec :path => "../" +end diff --git a/gemfiles/vagrant_1.6.gemfile b/gemfiles/vagrant_1.6.gemfile new file mode 100644 index 0000000..3190222 --- /dev/null +++ b/gemfiles/vagrant_1.6.gemfile @@ -0,0 +1,20 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "bundler", ">= 1.5.2", "< 1.7.0" + +group :development do + gem "pry" + gem "appraisal", "~> 1.0", :git => "https://github.com/maxlinc/appraisal", :branch => "gemspec_in_group" +end + +group :test do + gem "coveralls", :require => false +end + +group :plugins do + gem "vagrant", :git => "https://github.com/mitchellh/vagrant", :tag => "v1.6.5" + + gemspec :path => "../" +end diff --git a/gemfiles/vagrant_1.7.gemfile b/gemfiles/vagrant_1.7.gemfile new file mode 100644 index 0000000..e86471e --- /dev/null +++ b/gemfiles/vagrant_1.7.gemfile @@ -0,0 +1,19 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +group :development do + gem "pry" + gem "appraisal", "~> 1.0", :git => "https://github.com/maxlinc/appraisal", :branch => "gemspec_in_group" +end + +group :test do + gem "coveralls", :require => false +end + +group :plugins do + gem "vagrant", :git => "https://github.com/mitchellh/vagrant", :tag => "v1.7.1" + gem "bundler", ">= 1.5.2", "< 1.8.0" + + gemspec :path => "../" +end diff --git a/gemfiles/windows_wip.gemfile b/gemfiles/windows_wip.gemfile new file mode 100644 index 0000000..be24b6b --- /dev/null +++ b/gemfiles/windows_wip.gemfile @@ -0,0 +1,18 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +group :development do + gem "pry" + gem "appraisal", "~> 1.0", :git => "https://github.com/maxlinc/appraisal", :branch => "gemspec_in_group" +end + +group :test do + gem "coveralls", :require => false +end + +group :plugins do + gem "vagrant", :git => "https://github.com/maxlinc/vagrant", :branch => "winrm-1.3" + + gemspec :path => "../" +end diff --git a/lib/vagrant-rackspace/action.rb b/lib/vagrant-rackspace/action.rb index 3ee07a4..dee9d01 100644 --- a/lib/vagrant-rackspace/action.rb +++ b/lib/vagrant-rackspace/action.rb @@ -12,15 +12,22 @@ module Action def self.action_destroy Vagrant::Action::Builder.new.tap do |b| b.use ConfigValidate - b.use Call, IsCreated do |env, b2| + b.use Call, IsCreated do |env, b1| if !env[:result] - b2.use MessageNotCreated + b1.use MessageNotCreated next end - b2.use ConnectRackspace - b2.use DeleteServer - b2.use ProvisionerCleanup if defined?(ProvisionerCleanup) + b1.use Call, DestroyConfirm do |env1, b2| + if env1[:result] + b2.use ConnectRackspace + b2.use DeleteServer + b2.use ProvisionerCleanup if defined?(ProvisionerCleanup) + else + b2.use Message, I18n.t("vagrant_rackspace.will_not_destroy") + next + end + end end end end @@ -36,11 +43,7 @@ def self.action_provision end b2.use Provision - if defined?(SyncedFolders) - b2.use SyncedFolders - else - b2.use SyncFolders - end + b2.use SyncedFolders end end end @@ -106,12 +109,10 @@ def self.action_up b2.use ConnectRackspace b2.use Provision - if defined?(SyncedFolders) - b2.use SyncedFolders - else - b2.use SyncFolders - end + b2.use SyncedFolders + b2.use RunInitScript b2.use CreateServer + b2.use WaitForCommunicator end end end @@ -121,7 +122,7 @@ def self.action_create_image b.use ConfigValidate b.use Call, IsCreated do |env, b2| created = env[:result] - + if !created b2.use MessageNotCreated next @@ -150,6 +151,27 @@ def self.action_list_flavors end end + def self.action_list_keypairs + Vagrant::Action::Builder.new.tap do |b| + b.use ConnectRackspace + b.use ListKeyPairs + end + end + + def self.action_list_networks + Vagrant::Action::Builder.new.tap do |b| + b.use ConnectRackspace + b.use ListNetworks + end + end + + def self.action_list_servers + Vagrant::Action::Builder.new.tap do |b| + b.use ConnectRackspace + b.use ListServers + end + end + # The autoload farm action_root = Pathname.new(File.expand_path("../action", __FILE__)) autoload :ConnectRackspace, action_root.join("connect_rackspace") @@ -160,10 +182,13 @@ def self.action_list_flavors autoload :MessageNotCreated, action_root.join("message_not_created") autoload :ReadSSHInfo, action_root.join("read_ssh_info") autoload :ReadState, action_root.join("read_state") - autoload :SyncFolders, action_root.join("sync_folders") + autoload :RunInitScript, action_root.join("run_init_script") autoload :CreateImage, action_root.join("create_image") autoload :ListImages, action_root.join("list_images") autoload :ListFlavors, action_root.join("list_flavors") + autoload :ListKeyPairs, action_root.join("list_keypairs") + autoload :ListNetworks, action_root.join("list_networks") + autoload :ListServers, action_root.join("list_servers") end end end diff --git a/lib/vagrant-rackspace/action/create_server.rb b/lib/vagrant-rackspace/action/create_server.rb index 7aa10e3..5c76362 100644 --- a/lib/vagrant-rackspace/action/create_server.rb +++ b/lib/vagrant-rackspace/action/create_server.rb @@ -16,8 +16,14 @@ def initialize(app, env) end def call(env) - # Get the configs - config = env[:machine].provider_config + # Get the Rackspace configs + config = env[:machine].provider_config + machine_config = env[:machine].config + begin + communicator = machine_config.vm.communicator ||= :ssh + rescue NoMethodError + communicator = :ssh + end # Find the flavor env[:ui].info(I18n.t("vagrant_rackspace.finding_flavor")) @@ -32,14 +38,19 @@ def call(env) # Figure out the name for the server server_name = config.server_name || env[:machine].name - # If we are using a key name, can ignore the public key path - if not config.key_name - # If we're using the default keypair, then show a warning - default_key_path = Vagrant.source_root.join("keys/vagrant.pub").to_s - public_key_path = File.expand_path(config.public_key_path, env[:root_path]) - - if default_key_path == public_key_path - env[:ui].warn(I18n.t("vagrant_rackspace.warn_insecure_ssh")) + if communicator == :winrm + env[:ui].warn(I18n.t("vagrant_rackspace.warn_insecure_winrm")) if !winrm_secure?(machine_config) + env[:ui].warn(I18n.t("vagrant_rackspace.warn_winrm_password")) if config.admin_password != machine_config.winrm.password + else # communicator == :ssh + # If we are using a key name, can ignore the public key path + if not config.key_name + # If we're using the default keypair, then show a warning + default_key_path = Vagrant.source_root.join("keys/vagrant.pub").to_s + public_key_path = File.expand_path(config.public_key_path, env[:root_path]) + + if default_key_path == public_key_path + env[:ui].warn(I18n.t("vagrant_rackspace.warn_insecure_ssh")) + end end end @@ -71,14 +82,26 @@ def call(env) options[:config_drive] = config.config_drive end - if config.key_name - options[:key_name] = config.key_name - env[:ui].info(" -- Key Name: #{config.key_name}") - else + if communicator == :ssh + if config.key_name + options[:key_name] = config.key_name + env[:ui].info(" -- Key Name: #{config.key_name}") + else + options[:personality] = [ + { + :path => "/root/.ssh/authorized_keys", + :contents => encode64(File.read(public_key_path)) + } + ] + end + end + + if config.init_script && communicator == :winrm + # Might want to check init_script against known limits options[:personality] = [ { - :path => "/root/.ssh/authorized_keys", - :contents => Base64.encode64(File.read(public_key_path)) + :path => 'C:\\cloud-automation\\bootstrap.cmd', + :contents => encode64(config.init_script, :crlf_newline => true) } ] end @@ -99,8 +122,7 @@ def call(env) next if env[:interrupted] # Set the progress - env[:ui].clear_line - env[:ui].report_progress(server.progress, 100, false) + report_server_progress(env[:machine], server.progress, 100, false) # Wait for the server to be ready begin @@ -131,8 +153,6 @@ def call(env) end end - # Wait for SSH to become available - env[:ui].info(I18n.t("vagrant_rackspace.waiting_for_ssh")) while true # If we're interrupted then just back out break if env[:interrupted] @@ -174,7 +194,32 @@ def find_matching(collection, name) item end + def encode64(content, options = nil) + content = content.encode options if options + encoded = Base64.encode64 content + encoded.strip + end + + # This method checks to see if WinRM over SSL is supported and used + def winrm_secure?(machine_config) + machine_config.winrm.transport == :ssl + rescue NoMethodError + false + end + # Ported from Vagrant::UI, but scoped to the machine's UI + def report_server_progress(machine, progress, total, show_parts) + machine.ui.clear_line + if total && total > 0 + percent = (progress.to_f / total.to_f) * 100 + line = "Progress: #{percent.to_i}%" + line << " (#{progress} / #{total})" if show_parts + else + line = "Progress: #{progress}" + end + + machine.ui.info(line, new_line: false) + end end end end diff --git a/lib/vagrant-rackspace/action/list_keypairs.rb b/lib/vagrant-rackspace/action/list_keypairs.rb new file mode 100644 index 0000000..0ba77d5 --- /dev/null +++ b/lib/vagrant-rackspace/action/list_keypairs.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module Rackspace + module Action + class ListKeyPairs + def initialize(app, env) + @app = app + end + + def call(env) + compute_service = env[:rackspace_compute] + env[:ui].info ('%s' % ['KeyPair Name']) + compute_service.key_pairs.sort_by(&:name).each do |keypair| + env[:ui].info ('%s' % [keypair.name]) + end + @app.call(env) + end + end + end + end +end diff --git a/lib/vagrant-rackspace/action/list_networks.rb b/lib/vagrant-rackspace/action/list_networks.rb new file mode 100644 index 0000000..6e7d98a --- /dev/null +++ b/lib/vagrant-rackspace/action/list_networks.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module Rackspace + module Action + class ListNetworks + def initialize(app, env) + @app = app + end + + def call(env) + compute_service = env[:rackspace_compute] + env[:ui].info ('%-36s %-24s %s' % ['Network Name', 'Network CIDR', 'Network ID']) + compute_service.networks.sort_by(&:label).each do |network| + env[:ui].info ('%-36s %-24s %s' % [network.label, network.cidr, network.id]) + end + @app.call(env) + end + end + end + end +end diff --git a/lib/vagrant-rackspace/action/list_servers.rb b/lib/vagrant-rackspace/action/list_servers.rb new file mode 100644 index 0000000..a4ea87b --- /dev/null +++ b/lib/vagrant-rackspace/action/list_servers.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module Rackspace + module Action + class ListServers + def initialize(app, env) + @app = app + end + + def call(env) + compute_service = env[:rackspace_compute] + env[:ui].info ('%-20s %-20s %s' % ['Server Name', 'State', 'IPv4 address']) + compute_service.servers.sort_by(&:name).each do |server| + env[:ui].info ('%-20s %-20s %s' % [server.name, server.state, server.access_ipv4_address]) + end + @app.call(env) + end + end + end + end +end diff --git a/lib/vagrant-rackspace/action/run_init_script.rb b/lib/vagrant-rackspace/action/run_init_script.rb new file mode 100644 index 0000000..eb9c08f --- /dev/null +++ b/lib/vagrant-rackspace/action/run_init_script.rb @@ -0,0 +1,28 @@ +require "log4r" + +module VagrantPlugins + module Rackspace + module Action + class RunInitScript + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new("vagrant_rackspace::action::run_init_script") + end + + def call(env) + config = env[:machine].provider_config + machine_config = env[:machine].config + begin + communicator = machine_config.vm.communicator ||= :ssh + rescue NoMethodError + communicator = :ssh + end + + # Can we handle Windows config here? + @app.call(env) + env[:machine].communicate.sudo config.init_script if config.init_script && communicator == :ssh + end + end + end + end +end diff --git a/lib/vagrant-rackspace/action/sync_folders.rb b/lib/vagrant-rackspace/action/sync_folders.rb deleted file mode 100644 index 2d31068..0000000 --- a/lib/vagrant-rackspace/action/sync_folders.rb +++ /dev/null @@ -1,96 +0,0 @@ -require "log4r" -require 'rbconfig' -require "vagrant/util/subprocess" - -module VagrantPlugins - module Rackspace - module Action - # This middleware uses `rsync` to sync the folders over to the - # remote instance. - class SyncFolders - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new("vagrant_rackspace::action::sync_folders") - @host_os = RbConfig::CONFIG['host_os'] - end - - def call(env) - @app.call(env) - env[:ui].warn(I18n.t("vagrant_rackspace.sync_folders")) - - ssh_info = env[:machine].ssh_info - - config = env[:machine].provider_config - rsync_includes = config.rsync_includes.to_a - - env[:machine].config.vm.synced_folders.each do |id, data| - hostpath = File.expand_path(data[:hostpath], env[:root_path]) - guestpath = data[:guestpath] - - # Make sure there is a trailing slash on the host path to - # avoid creating an additional directory with rsync - hostpath = "#{hostpath}/" if hostpath !~ /\/$/ - - # If on Windows, modify the path to work with cygwin rsync - if @host_os =~ /mswin|mingw|cygwin/ - hostpath = hostpath.sub(/^([A-Za-z]):\//) { "/cygdrive/#{$1.downcase}/" } - end - - env[:ui].info(I18n.t("vagrant_rackspace.rsync_folder", - :hostpath => hostpath, - :guestpath => guestpath)) - - # Create the guest path - env[:machine].communicate.sudo("mkdir -p '#{guestpath}'") - env[:machine].communicate.sudo( - "chown -R #{ssh_info[:username]} '#{guestpath}'") - - # Generate rsync include commands - includes = rsync_includes.each_with_object([]) { |incl, incls| - incls << "--include" - incls << incl - } - - # Rsync over to the guest path using the SSH info. add - # .hg/ to exclude list as that isn't covered in - # --cvs-exclude - command = [ - "rsync", "--verbose", "--archive", "-z", "-L", - "--cvs-exclude", - "--exclude", ".hg/", - *includes, - "-e", "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no #{ssh_key_options(ssh_info)}", - hostpath, - "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"] - command.compact! - - # during rsync, ignore files specified in .hgignore and - # .gitignore traditional .gitignore or .hgignore files - ignore_files = [".hgignore", ".gitignore"] - ignore_files.each do |ignore_file| - abs_ignore_file = env[:root_path].to_s + "/" + ignore_file - if File.exist?(abs_ignore_file) - command = command + ["--exclude-from", abs_ignore_file] - end - end - - r = Vagrant::Util::Subprocess.execute(*command) - if r.exit_code != 0 - raise Errors::RsyncError, - :guestpath => guestpath, - :hostpath => hostpath, - :stderr => r.stderr - end - end - end - - private - - def ssh_key_options(ssh_info) - # Ensure that `private_key_path` is an Array (for Vagrant < 1.4) - Array(ssh_info[:private_key_path]).map { |path| "-i '#{path}' " }.join - end - end - end - end -end diff --git a/lib/vagrant-rackspace/command/keypairs.rb b/lib/vagrant-rackspace/command/keypairs.rb new file mode 100644 index 0000000..336ed7b --- /dev/null +++ b/lib/vagrant-rackspace/command/keypairs.rb @@ -0,0 +1,21 @@ +module VagrantPlugins + module Rackspace + module Command + class KeyPairs < Vagrant.plugin("2", :command) + def execute + options = {} + opts = OptionParser.new do |o| + o.banner = "Usage: vagrant rackspace keypairs [options]" + end + + argv = parse_options(opts) + return if !argv + + with_target_vms(argv, :provider => :rackspace) do |machine| + machine.action('list_keypairs') + end + end + end + end + end +end diff --git a/lib/vagrant-rackspace/command/networks.rb b/lib/vagrant-rackspace/command/networks.rb new file mode 100644 index 0000000..9405e7e --- /dev/null +++ b/lib/vagrant-rackspace/command/networks.rb @@ -0,0 +1,21 @@ +module VagrantPlugins + module Rackspace + module Command + class Networks < Vagrant.plugin("2", :command) + def execute + options = {} + opts = OptionParser.new do |o| + o.banner = "Usage: vagrant rackspace networks [options]" + end + + argv = parse_options(opts) + return if !argv + + with_target_vms(argv, :provider => :rackspace) do |machine| + machine.action('list_networks') + end + end + end + end + end +end diff --git a/lib/vagrant-rackspace/command/root.rb b/lib/vagrant-rackspace/command/root.rb index 2fb584f..71fe963 100644 --- a/lib/vagrant-rackspace/command/root.rb +++ b/lib/vagrant-rackspace/command/root.rb @@ -20,6 +20,18 @@ def initialize(argv, env) require File.expand_path("../flavors", __FILE__) Flavors end + @subcommands.register(:keypairs) do + require File.expand_path("../keypairs", __FILE__) + KeyPairs + end + @subcommands.register(:networks) do + require File.expand_path("../networks", __FILE__) + Networks + end + @subcommands.register(:servers) do + require File.expand_path("../servers", __FILE__) + Servers + end super(argv, env) end diff --git a/lib/vagrant-rackspace/command/servers.rb b/lib/vagrant-rackspace/command/servers.rb new file mode 100644 index 0000000..c780271 --- /dev/null +++ b/lib/vagrant-rackspace/command/servers.rb @@ -0,0 +1,21 @@ +module VagrantPlugins + module Rackspace + module Command + class Servers < Vagrant.plugin("2", :command) + def execute + options = {} + opts = OptionParser.new do |o| + o.banner = "Usage: vagrant rackspace servers [options]" + end + + argv = parse_options(opts) + return if !argv + + with_target_vms(argv, :provider => :rackspace) do |machine| + machine.action('list_servers') + end + end + end + end + end +end diff --git a/lib/vagrant-rackspace/config.rb b/lib/vagrant-rackspace/config.rb index e1aa526..b1f4ba6 100644 --- a/lib/vagrant-rackspace/config.rb +++ b/lib/vagrant-rackspace/config.rb @@ -119,6 +119,17 @@ class Config < Vagrant.plugin("2", :config) # @return [String] attr_accessor :admin_password + # A initialization script to run on the target machine before + # Vagrant connects. It should generally be used only for enabling + # or securing shell connection transport protocols, like SSH or WinRM. + # Use normal Vagrant provisioners for other purposes. + # + # This script may be subject to the limits for Server Personality. + # + # @return [String] + # @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Personality-d1e2543.html Server Personality + attr_accessor :init_script + # Default Rackspace Cloud Network IDs SERVICE_NET_ID = '11111111-1111-1111-1111-111111111111' PUBLIC_NET_ID = '00000000-0000-0000-0000-000000000000' @@ -139,6 +150,7 @@ def initialize @disk_config = UNSET_VALUE @networks = [] @rsync_includes = [] + @init_script = UNSET_VALUE end def finalize! @@ -157,6 +169,7 @@ def finalize! @disk_config = nil if @disk_config == UNSET_VALUE @networks = nil if @networks.empty? @rsync_includes = nil if @rsync_includes.empty? + @init_script = nil if @init_script == UNSET_VALUE if @public_key_path == UNSET_VALUE @public_key_path = Vagrant.source_root.join("keys/vagrant.pub") diff --git a/lib/vagrant-rackspace/plugin.rb b/lib/vagrant-rackspace/plugin.rb index e40b6b3..6f0c433 100644 --- a/lib/vagrant-rackspace/plugin.rb +++ b/lib/vagrant-rackspace/plugin.rb @@ -23,7 +23,7 @@ class Plugin < Vagrant.plugin("2") Config end - provider(:rackspace) do + provider(:rackspace, { :box_optional => true, parallel: true}) do # Setup some things Rackspace.init_i18n Rackspace.init_logging diff --git a/lib/vagrant-rackspace/version.rb b/lib/vagrant-rackspace/version.rb index 2a02b47..38d0b75 100644 --- a/lib/vagrant-rackspace/version.rb +++ b/lib/vagrant-rackspace/version.rb @@ -1,5 +1,5 @@ module VagrantPlugins module Rackspace - VERSION = "0.1.10dev" + VERSION = "0.1.11dev" end end diff --git a/locales/en.yml b/locales/en.yml index ee5022f..3159040 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -24,21 +24,32 @@ en: Waiting for the server to be built... waiting_for_rackconnect: |- Waiting for RackConnect to complete... - waiting_for_ssh: |- - Waiting for SSH to become available... + waiting_for_communicator: |- + Waiting for %{communicator} to become available at %{address}... warn_insecure_ssh: |- Warning! By not specifying a custom public/private keypair, Vagrant is defaulting to use the insecure keypair that ships with Vagrant. While this isn't much of a big deal for local development, this is quite insecure for remote servers. Please specify a custom public/private keypair. + warn_insecure_winrm: |- + Warning! Vagrant is using plaintext communication for WinRM. While + this isn't much of a big deal for local development, this is quite + insecure for remote servers. Please configure WinRM to use SSL. + warn_winrm_password: |- + Warning! Vagrant has no way to store the Administrator password generated + by Rackspace for later use with WinRM. Please configure Vagrant to use + the same value for the winrm password and the Rackspace admin_password so + Vagrant will be able to connect via WinRM. warn_networks: |- Warning! The Rackspace provider doesn't support any of the Vagrant high-level network configurations (`config.vm.network`). They will be silently ignored. + will_not_destroy: |- + The server will not be deleted. sync_folders: |- Rackspace support for Vagrant 1.3 has been deprecated. Please - upgrade to the latest version of vagrant for continued support. + upgrade to the latest version of vagrant for continued support. config: api_key_required: |- diff --git a/spec/vagrant-rackspace/config_spec.rb b/spec/vagrant-rackspace/config_spec.rb index a5f3239..d36dfa5 100644 --- a/spec/vagrant-rackspace/config_spec.rb +++ b/spec/vagrant-rackspace/config_spec.rb @@ -25,6 +25,7 @@ its(:networks) { should be_nil } its(:rsync_includes) { should be_nil } its(:admin_password) { should be_nil } + its(:init_script) { should be_nil } end describe "overriding defaults" do @@ -39,7 +40,8 @@ :server_name, :disk_config, :username, - :admin_password].each do |attribute| + :admin_password, + :init_script].each do |attribute| it "should not default #{attribute} if overridden" do subject.send("#{attribute}=".to_sym, "foo") subject.finalize! @@ -56,7 +58,7 @@ subject.send(:networks).should include(VagrantPlugins::Rackspace::Config::SERVICE_NET_ID) end - it "should not default rsync_includes if overridden" do + it "should not default rsync_includes if overridden" do inc = "core" subject.send(:rsync_include, inc) subject.finalize!