rightscale_provisioner 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Njc1ZWQ0ODcxNWQyMWQxOGYzMTZiOWE1M2NhNGVhZjUyN2Y2YTllMg==
5
+ data.tar.gz: !binary |-
6
+ ODEwMjBiMmU2ZmVjNjk3ZWJmNWEyYjRiZTYyOTZjYzI2ZWFjZWY4Mw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZDczNDBjMWJhMTI5Nzg1YjkxYjU1NTdiNGNlYzUwYmFhMTc4ZDlhYzI2Yzgx
10
+ OTcxNDEwNjg5YzI1MTY4ZTI2NDk1ZWEyZTI5YWRhODYwMGY1MzNhYjhiZGE3
11
+ ODdhNmYzNzhkMjM2ZTAyYTU2MzQzZmNlZDRlNWQ2Y2JkM2RlMzY=
12
+ data.tar.gz: !binary |-
13
+ OTlmMzdhOGYyMDVlMmRjZDFhZDZmODY4ZWNkNDBmODk1NzY3NDU4YzEzZTIz
14
+ NmU1N2I5MTZjNGVkZDczY2EwNmJiMzk2ZjE2Y2RhZGUxNmIzYTBkMWNiZjM4
15
+ NGRiODU5ZTBiYzZkZGQwYTQzZjg4OWFiZjU3MjljNDg4OTU3YWE=
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.tmproj
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rightscale_provisioner.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright (C) 2013 caryp
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,62 @@
1
+ # RightscaleProvisoner
2
+
3
+ Provision your vagrant boxes using the RightScale ServerTemplates.
4
+
5
+ ## Requirement
6
+
7
+ You must have VirtualBox installed, ruby 1.9 and the bundler gem.
8
+
9
+ NOTE: this is the initial release and does not yet support the new vagrant 1.1+ plugin interface. This currently only works with Vagrant 1.0.x.
10
+
11
+ ## Installation
12
+
13
+ Copy the configuration file into your home dir and secure it:
14
+
15
+ > cp config/rightscale_provisioner.cfg.example ~/.rightscale_provisioner.cfg
16
+ > chmod 600 ~/.rightscale_provisioner.cfg
17
+
18
+ Then edit ```~/.rightscale_provisioner.cfg``` and add your RightScale dashboard credentials.
19
+
20
+ Copy the ```config/Vagrantfile``` and ```config/Gemfile``` into your project
21
+ directory:
22
+
23
+ > mkdir ~/my_dev_project
24
+ > cp config/Gemfile ~/my_dev_project
25
+ > cp config/Vagrantfile ~/my_dev_project
26
+
27
+ Then edit ```~/my_dev_project/Vagrantfile``` to point to the ServerTemplate you
28
+ want and setup any inputs.
29
+
30
+ ## Usage
31
+
32
+ Launch a local VM:
33
+
34
+ > cd ~/my_dev_project
35
+ > bundle install
36
+ > bundle exec vagrant up
37
+
38
+ Once your vagrant VM is provisioned, you can login to your VM using:
39
+
40
+ > bundle exec vagrant ssh
41
+
42
+ Shutdown your VM:
43
+
44
+ > bundle exec vagrant destroy
45
+
46
+ ## Bugs and Known Limitations
47
+ * Cannot have duplicate server names in account -- should only search for servers within specified deployment
48
+ * does not yet select correct MCI on the ST. Your default MCI must have blueskies cloud settings in it. Add support for multi_cloud_image_name to fix.
49
+ * does not terminate servers in dashboard or do any cleanup -- you must login and manually delete servers.
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
58
+
59
+ # Authors
60
+
61
+ Author:: caryp (<cary@rightscale.com>)
62
+ Author:: sumner (<sumner@rightscale.com>)
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ RSpec::Core::RakeTask.new("spec")
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gem "vagrant"
4
+ gem "rightscale_provisioner", :path => ".."
@@ -0,0 +1,79 @@
1
+ require 'rightscale_provisioner'
2
+ require 'json'
3
+
4
+ user_secrets_json = File.read(ENV['HOME']+'/.rightscale_provisioner.cfg')
5
+ user_secrets = JSON.parse(user_secrets_json)
6
+
7
+ Vagrant::Config.run do |config|
8
+ config.vm.host_name = "rightscale-provisioner-example"
9
+
10
+ config.vm.box = "RightImage_Ubuntu_12.04_x64_v5.8.8_Vagrant_Dev9_8557fee0fd2d0d"
11
+ config.vm.box_url = "https://rightscale-vagrant-dev.s3.amazonaws.com/virtualbox/ubuntu/12.04/RightImage_Ubuntu_12.04_x64_v5.8.8_Vagrant_Dev9_8557fee0fd2d0d.box"
12
+
13
+ # Boot with a GUI so you can see the screen. (Default is headless)
14
+ # config.vm.boot_mode = :gui
15
+
16
+ # Assign this VM to a host-only network IP, allowing you to access it
17
+ # via the IP. Host-only networks can talk to the host machine as well as
18
+ # any other machines on the same network, but cannot be accessed (through this
19
+ # network interface) by any external networks.
20
+ config.vm.network :hostonly, "33.33.33.10"
21
+
22
+ # Assign this VM to a bridged network, allowing you to connect directly to a
23
+ # network using the host's network device. This makes the VM appear as another
24
+ # physical device on your network.
25
+
26
+ # config.vm.network :bridged
27
+
28
+ # Forward a port from the guest to the host, which allows for outside
29
+ # computers to access the VM, whereas host only networking does not.
30
+ # config.vm.forward_port 3000, 3000
31
+
32
+ # Share an additional folder to the guest VM. The first argument is
33
+ # an identifier, the second is the path on the guest to mount the
34
+ # folder, and the third is the path on the host to the actual folder.
35
+
36
+ # Shared folder for the developer_tool.json file. see README.
37
+ config.vm.share_folder "v-data", "/home/webapps", "."
38
+
39
+ config.ssh.max_tries = 40
40
+ config.ssh.timeout = 120
41
+
42
+ config.vm.provision RightscaleProvisoner::RightscaleProvisoner do |rightscale|
43
+
44
+ rightscale.email = user_secrets['email']
45
+ rightscale.password = user_secrets['password']
46
+ rightscale.account_id = user_secrets['account_id']
47
+ rightscale.api_url = user_secrets['api_url'] # default: https://www.rightscale.com
48
+
49
+ # rightscale.cloud_name = "BlueSkies"
50
+ rightscale.servertemplate = "PHP App Server (v13.2)"
51
+ rightscale.deployment_name = "Vagrant Deployment Test" #unique name!
52
+ rightscale.server_name = "Vagrant Server Test" #unique name!
53
+
54
+ rightscale.server_inputs = {
55
+
56
+ # database connection
57
+ "app/database_name" => "text:app_test",
58
+ "db/dns/master/fqdn" => "text:www.mydomain.com",
59
+
60
+ # application code respository
61
+ "repo/default/account" => "text:github_user@mail.com",
62
+ "repo/default/credential" => "cred:github_private_key",
63
+ "repo/default/repository" => "text:git://github.com/rightscale/examples.git",
64
+ "repo/default/revision" => "text:unified_php",
65
+
66
+ # open up port 8000
67
+ "sys_firewall/rule/enable" => "text:enable",
68
+ "sys_firewall/rule/port" => "text:8000",
69
+ "sys_firewall/rule/ip_address" => "text:any",
70
+ "sys_firewall/rule/protocol" => "text:tcp"
71
+ }
72
+
73
+ # scripts to run after boot list is completed
74
+ rightscale.operational_scripts = [
75
+ "sys_firewall::setup_rule"
76
+ ]
77
+
78
+ end
79
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "email" : "<rs email>",
3
+ "password" : "<rs password>",
4
+ "account_id" : 12345,
5
+ "api_url" : "https://my.rightscale.com"
6
+ }
@@ -0,0 +1,165 @@
1
+ require "vagrant"
2
+ require "vagrant/errors"
3
+
4
+ require "rightscale_provisioner/version"
5
+ require "rightscale_provisioner/api15"
6
+
7
+ module RightscaleProvisoner
8
+ class RightscaleProvisoner < Vagrant::Provisioners::Base
9
+
10
+ VAGRANT_CLOUD_NAME = "BlueSkies"
11
+
12
+ class Config < Vagrant::Config::Base
13
+ attr_accessor :email
14
+ attr_accessor :password
15
+ attr_accessor :account_id
16
+ attr_accessor :api_url
17
+ attr_accessor :servertemplate # name or id
18
+ attr_accessor :deployment_name
19
+ attr_accessor :multi_cloud_image_name
20
+ attr_accessor :cloud_name
21
+ attr_accessor :server_name
22
+ attr_accessor :server_inputs
23
+ attr_accessor :operational_scripts
24
+ end
25
+
26
+ def self.config_class
27
+ Config
28
+ end
29
+
30
+ class RightScaleError < Vagrant::Errors::VagrantError
31
+ # overrider i18n support for now
32
+ def translate_error(opts)
33
+ return nil if !opts[:_key]
34
+ opts[:_key]
35
+ end
36
+ end
37
+
38
+ def prepare
39
+ # open RightScale API connection
40
+ @conn = API15.new
41
+ @conn.connection(config.email, config.password, config.account_id, config.api_url)
42
+
43
+ # fail if the requested cloud is not registered with RightScale account
44
+ config.cloud_name ||= VAGRANT_CLOUD_NAME
45
+ @cloud = @conn.find_cloud_by_name(config.cloud_name)
46
+ raise "ERROR: cannot find a cloud named: '#{config.cloud_name}'. " +
47
+ "Please check the spelling of the 'cloud_name' parameter in " +
48
+ "your Vagrant file and verify the cloud is registered with " +
49
+ "your RightScale account?" unless @cloud
50
+
51
+ if config.operational_scripts
52
+ raise "ERROR: operational_scripts must be an array of strings" unless config.operational_scripts.kind_of?(Array)
53
+ end
54
+
55
+ # check for existing deployment and server in RightScale account
56
+ @deployment = @conn.find_deployment_by_name(config.deployment_name)
57
+ puts "Deployment '#{config.deployment_name}' #{@deployment ? "found." : "not found."}"
58
+ @server = @conn.find_server_by_name(config.server_name) if @deployment
59
+ puts "Server '#{config.server_name}' #{@server ? "found." : "not found."}"
60
+
61
+ # XXX: fails if the server is not running -- fix me!
62
+ # if @server
63
+ # # verify existing server is on the cloud we are requesting, if not fail.
64
+ # config.cloud_name ||= VAGRANT_CLOUD_NAME
65
+ # actual_cloud_name = @conn.server_cloud_name(@server)
66
+ # raise "ERROR: the server is in the '#{actual_cloud_name}' cloud, " +
67
+ # "and not in the requested '#{config.cloud_name}' cloud.\n" +
68
+ # "Please delete the server or pick and new server name." if config.cloud_name != actual_cloud_name
69
+ # end
70
+
71
+ unless @deployment && @server
72
+ # we need to create a server, can we find the servertemplate?
73
+ @servertemplate = @conn.find_servertemplate(config.servertemplate)
74
+ raise "ERROR: cannot find ServerTemplate '#{config.servertemplate}'. Did you import it?\n" +
75
+ "Visit http://bit.ly/VnOiA7 for more info.\n\n" unless @servertemplate
76
+ # can we find the MCI?
77
+ #TODO: @mci = @conn.find_multicloudimage_by_name(@servertemplate, config.multi_cloud_image_name)
78
+ end
79
+
80
+ # create deployment and server as needed
81
+ unless @deployment
82
+ @deployment = @conn.create_deployment(config.deployment_name)
83
+ puts "Created deployment."
84
+ end
85
+
86
+ unless @server
87
+ @server = @conn.create_server(@deployment, @servertemplate, @mci, @cloud, config.server_name)
88
+ puts "Created server."
89
+ end
90
+
91
+ unless @conn.is_provisioned?(@server)
92
+
93
+ # setup any inputs
94
+ @conn.set_server_inputs(@server, config.server_inputs) if config.server_inputs
95
+
96
+ # launch server
97
+ puts "Launching server..."
98
+ @server = @conn.launch_server(@server, config.server_inputs)
99
+ @conn.server_wait_for_state(@server, "booting")
100
+ end
101
+
102
+ if config.cloud_name == VAGRANT_CLOUD_NAME
103
+ # Vagrant box: grab "Data request URL" from UserData
104
+ user_data = @server.current_instance.show(:view => "full").user_data
105
+ puts user_data.inspect
106
+ @data_request_url = @conn.data_request_url(user_data)
107
+ puts "Data Request URL: #{@data_request_url}"
108
+ else
109
+ @conn.server_wait_for_state(config.server_name, "operational", 30)
110
+ end
111
+
112
+ end
113
+
114
+ def provision!
115
+ if config.cloud_name.nil? || config.cloud_name == VAGRANT_CLOUD_NAME
116
+ # check for rightimage
117
+ begin
118
+ env[:vm].channel.execute("which rs_connect") # TODO: figure out how to test for failure
119
+ rescue Exception => e
120
+ msg = "ERROR: This vagrant box does not have RightLink properly installed. Cannot continue."
121
+ raise RightScaleError.new(msg)
122
+ end
123
+
124
+ # run rs_connect
125
+ enroll_cmd = "sudo rs_connect --attach #{@data_request_url} --force"
126
+ puts "Running #{enroll_cmd}"
127
+ puts env[:vm].channel.execute(enroll_cmd)
128
+
129
+ if config.operational_scripts
130
+ # wait for operational
131
+ @conn.server_wait_for_state(@server, "operational", 30)
132
+
133
+ # run operational scripts
134
+ puts "Running operational recipes..." if config.operational_scripts
135
+ config.operational_scripts.each do |script_name|
136
+
137
+ # run recipe or rightscript
138
+ exec = script_name.include?("::") ? "rs_run_recipe" : "rs_run_rightscript"
139
+ cmd = "sudo #{exec} --name #{script_name}"
140
+ puts " #{cmd}"
141
+ puts env[:vm].channel.execute(cmd)
142
+ end
143
+ end
144
+
145
+ else
146
+ puts "RightScale provisioning server on config.cloud_name cloud..."
147
+ end
148
+ end
149
+
150
+ def cleanup
151
+ begin
152
+ if @server
153
+ # server terminate
154
+ @conn.terminate_server(@server)
155
+ # server delete
156
+ @conn.destroy_server(@server)
157
+ end
158
+ rescue Exception => e
159
+ puts "WARNING: unable to cleanup server."
160
+ puts "Message: #{e.message}"
161
+ end
162
+ end
163
+
164
+ end
165
+ end
@@ -0,0 +1,201 @@
1
+ module RightscaleProvisoner
2
+ class API15
3
+
4
+ attr_reader :client
5
+
6
+ def initialize
7
+ require "right_api_client"
8
+ end
9
+
10
+ def connection(email, password, account_id, api_url = nil)
11
+ begin
12
+ args = { :email => email, :password => password, :account_id => account_id }
13
+ @url = api_url
14
+ args[:api_url] = @url if @url
15
+ @connection ||= RightApi::Client.new(args)
16
+ @client = @connection
17
+ rescue Exception => e
18
+ args.delete(:password) # don't log password
19
+ puts "ERROR: could not connect to RightScale API. Params: #{args.inspect}"
20
+ puts e.message
21
+ puts e.backtrace
22
+ raise e
23
+ end
24
+ end
25
+
26
+ def user_data
27
+ @user_data ||= @server.show.current_instance(:view=>"extended").show.user_data
28
+ end
29
+
30
+ def data_request_url(userdata)
31
+ data_hash = {}
32
+ entry = userdata.split('&').select { |entry| entry =~ /RS_rn_auth/i }
33
+ raise "ERROR: user data token not found. " +
34
+ "Does your MCI have a provides:rs_agent_type=right_link tag?" unless entry
35
+ token = entry.first.split('=')[1]
36
+ "#{@url}/servers/data_injection_payload/#{token}"
37
+ end
38
+
39
+ def find_server_by_name(name)
40
+ server_list = @connection.servers.index(:filter => ["name==#{name}"])
41
+ raise "More than one server with the name of '#{name}'. " +
42
+ "Please fix via the RightScale dashboard and retry." if server_list.size > 1
43
+ server_list.first
44
+ end
45
+
46
+ def find_deployment_by_name(name)
47
+ deployment = nil
48
+ deployments_list = @connection.deployments.index(:filter => ["name==#{name}"])
49
+ raise "More than one deployment with the name of '#{name}'. " +
50
+ "Please fix via the RightScale dashboard and retry." if deployments_list.size > 1
51
+ deployment = deployments_list.first unless deployments_list.empty?
52
+ deployment
53
+ end
54
+
55
+ # returns:: String if cloud is found, nil if not found
56
+ def find_cloud_by_name(name)
57
+ cloud = nil
58
+ cloud_list = @connection.clouds.index(:filter => ["name==#{name}"])
59
+ raise "More than one cloud with the name of '#{name}'. " +
60
+ "Please fix via the RightScale dashboard and retry." if cloud_list.size > 1
61
+ cloud = cloud_list.first unless cloud_list.empty?
62
+ cloud
63
+ end
64
+
65
+ def find_mci_by_name(server_template, mci_name)
66
+ mci = nil
67
+ mci_list = @connection.mcis.index(:filter => ["name==#{name}"])
68
+ raise "More than one MultiCloud image with the name of '#{name}'. " +
69
+ "Please fix via the RightScale dashboard and retry." if mci_list.size > 1
70
+ mci = mci_list.first unless mci_list.empty?
71
+ mci
72
+ end
73
+
74
+ def find_servertemplate(name_or_id)
75
+ server_template = nil; id = nil; name = nil
76
+
77
+ # detect if user passed in a name or an id
78
+ # there is probably a cleaner way to do this, but I am lazy ATM.
79
+ begin
80
+ id = Integer(name_or_id)
81
+ rescue Exception => e
82
+ name = name_or_id # Cannot be case to integer, assume a name was passed
83
+ end
84
+
85
+ if name
86
+ # find ServerTemplate by name
87
+ st_list = @connection.server_templates.index(:filter => ["name==#{name}"])
88
+ num_matching_sts = 0
89
+ st_list.each do |st|
90
+ if st.name == name
91
+ server_template = st
92
+ num_matching_sts += 1
93
+ end
94
+ end
95
+ raise "ERROR: Unable to find ServerTemplate with the name of '#{name}' found " unless server_template
96
+ raise "ERROR: More than one ServerTemplate with the name of '#{name}' found " +
97
+ "in account. Please fix via the RightScale dashboard and retry." if num_matching_sts > 1
98
+
99
+ else
100
+ # find ServerTemplate by id
101
+ server_template = @connection.server_templates.index(:id => id)
102
+ end
103
+
104
+ server_template
105
+ end
106
+
107
+ def create_deployment(name)
108
+ @connection.deployments.create(:deployment => { :name => name, :decription => "Created by the Vagrant"})
109
+ end
110
+
111
+ def destroy_deployment(deployment)
112
+ deployment.destroy
113
+ end
114
+
115
+ def create_server(deployment, server_template, mci, cloud, name)
116
+
117
+ #TODO: mci param not used yet
118
+
119
+ # check params
120
+ unless st_href = server_template.show.href
121
+ raise "ERROR: ServerTemplate parameter not initialized properly"
122
+ end
123
+
124
+ unless d_href = deployment.show.href
125
+ raise "ERROR: Deployment parameter not initialized properly"
126
+ end
127
+
128
+ unless c_href = cloud.show.href
129
+ raise "ERROR: Deployment parameter not initialized properly"
130
+ end
131
+
132
+ # create server in deployment using specfied ST
133
+ server =
134
+ @connection.servers.create({
135
+ :server => {
136
+ :name => name,
137
+ :decription => "Created by the Vagrant",
138
+ :deployment_href => d_href,
139
+ :instance => {
140
+ :cloud_href => c_href,
141
+ :server_template_href => st_href
142
+ }
143
+ }
144
+ })
145
+ end
146
+
147
+ def is_provisioned?(server)
148
+ server.show.api_methods.include?(:current_instance)
149
+ end
150
+
151
+ # @param(Hash) inputs Hash input name/value pairs i.e. { :name => "text:dummy"}
152
+ def launch_server(server, inputs = { :name => "text:dummy"})
153
+ server_name = server.show.name
154
+ server.launch(inputs) # TODO: parse inputs from Vagrantfile
155
+ # XXX: need to create a new server object after launch -- why? API bug?
156
+ find_server_by_name(server_name)
157
+ end
158
+
159
+ def terminate_server(server)
160
+ server.terminate
161
+ end
162
+
163
+ # Only use this *before* you launch the server
164
+ def set_server_inputs(server, inputs)
165
+ server.show.next_instance.show.inputs.multi_update({"inputs" => inputs})
166
+ end
167
+
168
+ def server_wait_for_state(server, state, delay = 1)
169
+ while instance_from_server(server).show.state != state
170
+ puts "Waiting for instance to be in #{state} state..."
171
+ sleep delay
172
+ end
173
+ end
174
+
175
+ def server_cloud_name(server)
176
+ instance = instance_from_server(server)
177
+ cloud = cloud_from_instance(instance)
178
+ cloud.show.name
179
+ end
180
+
181
+ private
182
+
183
+ def server_state(server)
184
+ instance_from_server(server)
185
+ end
186
+
187
+ def instance_from_server(server)
188
+ server_data = server.show
189
+ if is_provisioned?(server)
190
+ server_data.current_instance
191
+ else
192
+ server_data.next_instance
193
+ end
194
+ end
195
+
196
+ def cloud_from_instance(instance)
197
+ instance.show.cloud
198
+ end
199
+
200
+ end
201
+ end
@@ -0,0 +1,3 @@
1
+ module RightscaleProvisoner
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rightscale_provisioner/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "rightscale_provisioner"
8
+ gem.version = RightscaleProvisoner::VERSION
9
+ gem.authors = ["caryp", "sumner"]
10
+ gem.email = ["cary@rightscale.com", "sumner@rightscale.com"]
11
+ gem.description = %q{Enables the provisioning of local VMs using RightScale}
12
+ gem.summary = %q{RightScale provisioner for Vagrant}
13
+ gem.homepage = "http://github.com/caryp/rightscale_provisioner"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency('right_api_client', '>= 1.5.9')
21
+ gem.add_dependency('vagrant', '~> 1.0.0')
22
+
23
+ gem.add_development_dependency('rspec', '~> 2.5')
24
+ gem.add_development_dependency('rake', '~> 10.0.3')
25
+ end
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+ require 'right_api_client'
4
+
5
+ describe "API15 object" do
6
+
7
+ before(:each) do
8
+ @api = RightscaleProvisoner::API15.new()
9
+ apiStub = double("RightApi::Client")
10
+ RightApi::Client.should_receive(:new).and_return(apiStub)
11
+ @api.connection("someemail", "somepasswd", "someaccountid", "https://my.rightscale.com")
12
+ end
13
+
14
+ it "should find deployment by name" do
15
+ deploymentsStub = stub("deployments", :index => [ :name => "my_fake_deployment" ])
16
+ @api.instance_variable_get("@connection").should_receive(:deployments).and_return(deploymentsStub)
17
+ @api.find_deployment_by_name("my_fake_deployment")
18
+ end
19
+
20
+ it "should raise error if deployment not found by name" do
21
+ deploymentsStub = stub("deployments", :index => nil)
22
+ @api.instance_variable_get("@connection").should_receive(:deployments).and_return(deploymentsStub)
23
+ lambda{@api.find_deployment_by_name("my_fake_deployment")}.should raise_error
24
+ end
25
+
26
+ it "should raise error if multiple deployments found by name" do
27
+ deploymentsStub = stub("deployments", :index => [ {:name => "my_fake_deployment"}, {:name => "my_fake_deployment2"} ])
28
+ @api.instance_variable_get("@connection").should_receive(:deployments).and_return(deploymentsStub)
29
+ lambda{@api.find_deployment_by_name("my_fake_deployment")}.should raise_error
30
+ end
31
+
32
+ it "should find server by name" do
33
+ serversStub = stub("servers", :index => [ :name => "my_fake_server" ])
34
+ @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
35
+ @api.find_server_by_name("my_fake_server")
36
+ end
37
+
38
+ it "should raise error if multiple servers found by name" do
39
+ serversStub = stub("servers", :index => [ {:name => "my_fake_server"}, {:name => "my_fake_server2"} ])
40
+ @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
41
+ lambda{@api.find_server_by_name("my_fake_server")}.should raise_error
42
+ end
43
+
44
+ it "should find MCI by name" do
45
+ pending ("TODO: add support for multi_cloud_image_name")
46
+ mcisStub = stub("mcis", :index => [ :name => "my_fake_mci" ])
47
+ @api.instance_variable_get("@connection").should_receive(:mcis).and_return(mcisStub)
48
+ @api.find_mci_by_name("my_fake_mci")
49
+ end
50
+
51
+ it "should raise error if multiple MCI found by name" do
52
+ pending ("TODO: add support for multi_cloud_image_name")
53
+ mcisStub = stub("mcis", :index => [ {:name => "my_fake_mci"}, {:name => "my_fake_mci2"} ])
54
+ @api.instance_variable_get("@connection").should_receive(:mcis).and_return(mcisStub)
55
+ lambda{@api.find_mci_by_name("my_fake_mci")}.should raise_error
56
+ end
57
+
58
+ it "should find servertemplate by name" do
59
+ servertemplatesStub = stub("servertemplates", :index => [ stub("servertemplate", :name => "my_fake_servertemplate") ])
60
+ @api.instance_variable_get("@connection").should_receive(:server_templates).and_return(servertemplatesStub)
61
+ @api.find_servertemplate("my_fake_servertemplate")
62
+ end
63
+
64
+ it "should raise error if no servertemplates found by name" do
65
+ servertemplatesStub = stub("servertemplates", :index => [])
66
+ @api.instance_variable_get("@connection").should_receive(:server_templates).and_return(servertemplatesStub)
67
+ lambda{@api.find_servertemplate("my_fake_servertemplate")}.should raise_error
68
+ end
69
+
70
+ it "should raise error if multiple servertemplates found by name" do
71
+ servertemplatesStub = stub("servertemplates", :index => [ stub("servertemplate", :name => "my_fake_servertemplate"), stub("servertemplate", :name => "my_fake_servertemplate") ])
72
+ @api.instance_variable_get("@connection").should_receive(:server_templates).and_return(servertemplatesStub)
73
+ lambda{@api.find_servertemplate("my_fake_servertemplate")}.should raise_error
74
+ end
75
+
76
+ it "should find servertemplate by id" do
77
+ servertemplatesStub = stub("servertemplates", :index => [ :name => "my_fake_servertemplate" ])
78
+ @api.instance_variable_get("@connection").should_receive(:server_templates).and_return(servertemplatesStub)
79
+ @api.find_servertemplate(1234)
80
+ end
81
+
82
+ it "should create deployment" do
83
+ deploymentsStub = stub("deployments", :create => [ {:name => "my_fake_deployment"} ])
84
+ @api.instance_variable_get("@connection").should_receive(:deployments).and_return(deploymentsStub)
85
+ deploymentsStub.should_receive(:create)
86
+ @api.create_deployment("my_deployment")
87
+ end
88
+
89
+ it "should create server" do
90
+ dStub = stub("deployment", :href => "/some/fake/path")
91
+ dsStub = stub("deployments", :show => dStub)
92
+ @api.should_receive(:create_deployment).and_return(dsStub)
93
+ deployment = @api.create_deployment("my_deployment")
94
+
95
+ stStub = stub("servertemplate", :href => "/some/fake/path", :show => "")
96
+ stsStub = stub("servertemplates", :show => stStub)
97
+ @api.should_receive(:find_servertemplate).and_return(stsStub)
98
+ server_template = @api.find_servertemplate(1234)
99
+
100
+ cStub = stub("cloud", :href => "/some/fake/path")
101
+ csStub = stub("clouds", :show => cStub)
102
+ @api.should_receive(:find_cloud_by_name).and_return(csStub)
103
+ cloud = @api.find_cloud_by_name(1234)
104
+
105
+ serversStub = stub("servers", :create => [ :name => "my_fake_server" ])
106
+ @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
107
+ @api.create_server(deployment, server_template, nil, cloud, "my_fake_server")
108
+ end
109
+
110
+ it "should launch server with inputs" do
111
+ serverStub = stub("server", :name => "foo")
112
+ serversStub = stub("servers", :launch => true, :show => serverStub, :index => [ :name => "my_fake_server" ])
113
+ @api.should_receive(:create_server).and_return(serversStub)
114
+ server = @api.create_server("foo", "bar", "my_fake_server")
115
+ @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
116
+ @api.launch_server(server, [ {:name => "input1", :value => 1} ])
117
+ end
118
+
119
+ it "should launch server without inputs" do
120
+ serverStub = stub("server", :name => "foo")
121
+ serversStub = stub("servers", :launch => true, :show => serverStub, :index => [ :name => "my_fake_server" ])
122
+ @api.should_receive(:create_server).and_return(serversStub)
123
+ server = @api.create_server("foo", "bar", "my_fake_server")
124
+ @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
125
+ @api.launch_server(server)
126
+ end
127
+
128
+ it "returns data_request_url for instance" do
129
+ @user_data = "RS_rn_url=amqp://b915586461:278a854748@orange2-broker.test.rightscale.com/right_net&RS_rn_id=4985249009&RS_server=orange2-moo.test.rightscale.com&RS_rn_auth=d98106775832c174ffd55bd7b7cb175077574adf&RS_token=b233a57d1d24f27bd8650d0f9b6bfd54&RS_sketchy=sketchy1-145.rightscale.com&RS_rn_host=:0"
130
+ @request_data_url = "https://my.rightscale.com/servers/data_injection_payload/d98106775832c174ffd55bd7b7cb175077574adf"
131
+
132
+ @api.data_request_url(@user_data).should == @request_data_url
133
+ end
134
+
135
+ it "waits for state to change from booting state" do
136
+ pending "TODO"
137
+ end
138
+
139
+ it "fails if the server's cloud is not the requested cloud" do
140
+ pending "TODO"
141
+ end
142
+
143
+ it "sets inputs on the next instance" do
144
+ pending "TODO"
145
+ end
146
+
147
+ it "terminates a server" do
148
+ pending "TODO"
149
+ serverStub = stub("server", :name => "foo")
150
+ # serversStub = stub("servers", :launch => true, :show => serverStub, :index => [ :name => "my_fake_server" ])
151
+ # @api.should_receive(:create_server).and_return(serversStub)
152
+ # server = @api.create_server("foo", "bar", "my_fake_server")
153
+ # @api.instance_variable_get("@connection").should_receive(:servers).and_return(serversStub)
154
+ @api.terminate_server(serverStub)
155
+ end
156
+
157
+
158
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+ require 'right_api_client'
4
+
5
+ describe "RightccaleProvisioner object" do
6
+
7
+ before(:each) do
8
+ # @api = RightscaleProvisoner::API15.new()
9
+ # apiStub = double("RightApi::Client")
10
+ # RightApi::Client.should_receive(:new).and_return(apiStub)
11
+ # @api.connection("someemail", "somepasswd", "someaccountid", "https://my.rightscale.com")
12
+ end
13
+
14
+ it "should find deployment by name" do
15
+ pending "TODO"
16
+ end
17
+
18
+ it "should fail if cloud is not found" do
19
+ pending "TODO"
20
+ end
21
+
22
+ it "should fail if ServerTemplate is not found" do
23
+ pending "TODO"
24
+ end
25
+
26
+
27
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'rspec/mocks'
3
+
4
+ require 'rightscale_provisioner'
5
+
6
+ RSpec.configure do |config|
7
+ config.color_enabled = true
8
+ config.formatter = 'documentation'
9
+ end
10
+
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rightscale_provisioner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - caryp
8
+ - sumner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: right_api_client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 1.5.9
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 1.5.9
28
+ - !ruby/object:Gem::Dependency
29
+ name: vagrant
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: 1.0.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '2.5'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '2.5'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 10.0.3
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 10.0.3
70
+ description: Enables the provisioning of local VMs using RightScale
71
+ email:
72
+ - cary@rightscale.com
73
+ - sumner@rightscale.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - .gitignore
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - config/Gemfile
84
+ - config/Vagrantfile
85
+ - config/rightscale_provisioner.cfg.example
86
+ - lib/rightscale_provisioner.rb
87
+ - lib/rightscale_provisioner/api15.rb
88
+ - lib/rightscale_provisioner/version.rb
89
+ - rightscale_provisoner.gemspec
90
+ - spec/api15_spec.rb
91
+ - spec/rightscale_provisioner_spec.rb
92
+ - spec/spec_helper.rb
93
+ homepage: http://github.com/caryp/rightscale_provisioner
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.0.3
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: RightScale provisioner for Vagrant
116
+ test_files:
117
+ - spec/api15_spec.rb
118
+ - spec/rightscale_provisioner_spec.rb
119
+ - spec/spec_helper.rb
120
+ has_rdoc: