rightscale_provisioner 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: