right_api_helper 1.0.0 → 1.1.0
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.
- data/CHANGELOG.md +3 -0
- data/lib/right_api_helper/provisioner.rb +226 -0
- data/lib/right_api_helper/version.rb +1 -1
- data/lib/right_api_helper.rb +1 -0
- data/spec/provisioner_spec.rb +18 -0
- metadata +6 -2
data/CHANGELOG.md
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
#
|
2
|
+
# Author: cary@rightscale.com
|
3
|
+
# Copyright 2014 RightScale, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
# Basic helper gem for provisioning IaaS servers using the RightScale API.
|
19
|
+
#
|
20
|
+
# It is intended to be used by ruby applications that need to launch servers.
|
21
|
+
#
|
22
|
+
# ## Usage
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# require "right_api_helper"
|
27
|
+
#
|
28
|
+
# # initialize rightscale provisioner
|
29
|
+
# @rightscale =
|
30
|
+
# RightApiHelper::Provisioner.new("my_user@somewhere.com", // user
|
31
|
+
# "my_rightscale_password", // password
|
32
|
+
# 12345) // rightscale account ID
|
33
|
+
#
|
34
|
+
# # setup some inputs
|
35
|
+
# server_inputs = {
|
36
|
+
# # open up port 8000
|
37
|
+
# "sys_firewall/rule/enable" => "text:enable",
|
38
|
+
# "sys_firewall/rule/port" => "text:8000",
|
39
|
+
# "sys_firewall/rule/ip_address" => "text:any",
|
40
|
+
# "sys_firewall/rule/protocol" => "text:tcp"
|
41
|
+
# }
|
42
|
+
#
|
43
|
+
# # provision a RightScale managed server from a ServerTemplate
|
44
|
+
# @rightscale.provision("My Cool Server",
|
45
|
+
# "ServerTemplate for Linux (v13.5)", // name or ID
|
46
|
+
# "AWS US-East",
|
47
|
+
# "My Deployment",
|
48
|
+
# server_inputs)
|
49
|
+
#
|
50
|
+
# # wait for server to be ready
|
51
|
+
# state = @rightscale.wait_for_operational
|
52
|
+
#
|
53
|
+
# # Do stuff with your brand new server...
|
54
|
+
|
55
|
+
|
56
|
+
module RightApiHelper
|
57
|
+
|
58
|
+
#
|
59
|
+
# This is the main class to use to create a server on the RightScale platform.
|
60
|
+
# Use the {#provision} method to create and launch
|
61
|
+
# the server.
|
62
|
+
#
|
63
|
+
# The other methods are for checking server state and gathering information
|
64
|
+
# once the server is operational.
|
65
|
+
#
|
66
|
+
class Provisioner < Base
|
67
|
+
|
68
|
+
RETRY_DELAY = 10 # seconds
|
69
|
+
BAD_STATES_UP = [ "stranded", "terminated"]
|
70
|
+
|
71
|
+
def initialize(right_api_client)
|
72
|
+
super(right_api_client)
|
73
|
+
@api_shim = RightApiHelper::API15.new(right_api_client)
|
74
|
+
end
|
75
|
+
|
76
|
+
def connection_url
|
77
|
+
raise "No server provisioned. No connection URL available." unless @server
|
78
|
+
unless @data_request_url
|
79
|
+
user_data = @server.current_instance.show(:view => "full").user_data
|
80
|
+
@data_request_url = @api_shim.data_request_url(user_data)
|
81
|
+
@logger.debug "Data Request URL: #{@data_request_url}"
|
82
|
+
end
|
83
|
+
@data_request_url
|
84
|
+
end
|
85
|
+
|
86
|
+
# Provision a server using RightScale
|
87
|
+
#
|
88
|
+
# @param server_name [String] the name to give the server that will be
|
89
|
+
# created.
|
90
|
+
# @param server_template [String] the name or ID of the ServerTemplate to
|
91
|
+
# create the server from.
|
92
|
+
# @param cloud_name [String] name of cloud to provision on.
|
93
|
+
# @param deployment_name [String] name of deployment to add the server to.
|
94
|
+
# This will be created if it does not exist.
|
95
|
+
# @param inputs [Array] An array of {Input} objects.
|
96
|
+
# @param ssh_key_id [String] The resource_uuid of an ssh key from the
|
97
|
+
# RightScale dashboard. Only required on EC2 and Eucalyptus.
|
98
|
+
# @param secgroup_id [Array] An array of security group IDs to place the
|
99
|
+
# server in.
|
100
|
+
#
|
101
|
+
# @raise {RightApiProvisionException} if anything
|
102
|
+
# goes wrong
|
103
|
+
def provision(servertemplate,
|
104
|
+
server_name = "default",
|
105
|
+
cloud_name = "ec2",
|
106
|
+
deployment_name = "default",
|
107
|
+
inputs = nil,
|
108
|
+
multi_cloud_image_name = nil,
|
109
|
+
ssh_key_uuid = nil,
|
110
|
+
security_groups = nil)
|
111
|
+
|
112
|
+
# fail if the requested cloud is not registered with RightScale account
|
113
|
+
@cloud = @api_shim.find_cloud_by_name(cloud_name)
|
114
|
+
unless @cloud
|
115
|
+
clouds = @client.list_clouds.inject("") { |str, c| str == "" ? c.name : "#{str}, #{c.name}" }
|
116
|
+
raise RightScaleError, "ERROR: cannot find a cloud named: '#{cloud_name}'. " +
|
117
|
+
"Please check the spelling of the 'cloud_name' parameter in " +
|
118
|
+
"your Vagrant file and verify the cloud is registered with " +
|
119
|
+
"your RightScale account? Supported clouds: #{clouds}"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Verify ssh key uuid, if required by cloud
|
123
|
+
if @api_shim.requires_ssh_keys?(@cloud)
|
124
|
+
@ssh_key = @api_shim.find_ssh_key_by_uuid_or_first(@cloud, ssh_key_uuid)
|
125
|
+
raise "ERROR: cannot find an ssh_key named: #{ssh_key_uuid}" unless @ssh_key
|
126
|
+
end
|
127
|
+
|
128
|
+
# Verify security group, if required by cloud
|
129
|
+
if @api_shim.requires_security_groups?(@cloud)
|
130
|
+
@sec_groups = []
|
131
|
+
security_groups ||= ["default"]
|
132
|
+
security_groups.each do |name|
|
133
|
+
group = @api_shim.find_security_group_by_name(@cloud, name)
|
134
|
+
raise "ERROR: cannot find an security group named: #{name}" unless group
|
135
|
+
@sec_groups << group
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# check for existing deployment and server in RightScale account
|
140
|
+
@deployment = @api_shim.find_deployment_by_name(deployment_name)
|
141
|
+
@logger.info "Deployment '#{deployment_name}' #{@deployment ? "found." : "not found."}"
|
142
|
+
@server = @api_shim.find_server_by_name(server_name) if @deployment
|
143
|
+
@logger.info "Server '#{server_name}' #{@server ? "found." : "not found."}"
|
144
|
+
|
145
|
+
if @server
|
146
|
+
# verify existing server is on the cloud we are requesting, if not fail.
|
147
|
+
actual_cloud_name = @api_shim.server_cloud_name(@server)
|
148
|
+
raise "ERROR: the server is in the '#{actual_cloud_name}' cloud, " +
|
149
|
+
"and not in the requested '#{cloud_name}' cloud.\n" +
|
150
|
+
"Please delete the server or pick and new server name." if cloud_name != actual_cloud_name
|
151
|
+
end
|
152
|
+
|
153
|
+
unless @deployment && @server
|
154
|
+
# we need to create a server, can we find the servertemplate?
|
155
|
+
begin
|
156
|
+
@servertemplate = @client.find_servertemplate(server_template)
|
157
|
+
rescue
|
158
|
+
raise RightScaleError, "ERROR: cannot find ServerTemplate '#{server_template}'. Did you import it?\n" +
|
159
|
+
"Visit http://bit.ly/VnOiA7 for more info.\n\n"
|
160
|
+
end
|
161
|
+
|
162
|
+
# We need to find the to be used in the server if the MCI name is given
|
163
|
+
begin
|
164
|
+
@mci =
|
165
|
+
if multi_cloud_image_name.nil? || multi_cloud_image_name.empty?
|
166
|
+
nil
|
167
|
+
else
|
168
|
+
@client.find_mci_by_name(multi_cloud_image_name)
|
169
|
+
end
|
170
|
+
rescue Exception => e
|
171
|
+
raise RightScaleError, "ERROR: Cannot find the mci '#{multi_cloud_image_name}'. Please make sure" +
|
172
|
+
" that you have the MCI under the server template selected." +
|
173
|
+
" Exception: #{e.inspect}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# create deployment and server as needed
|
178
|
+
unless @deployment
|
179
|
+
@deployment = @api_shim.create_deployment(deployment_name)
|
180
|
+
@logger.info "Created deployment."
|
181
|
+
end
|
182
|
+
|
183
|
+
unless @server
|
184
|
+
@server = @api_shim.create_server(@deployment, @servertemplate, @mci, @cloud, server_name, @ssh_key, @sec_groups)
|
185
|
+
@logger.info "Created server."
|
186
|
+
end
|
187
|
+
|
188
|
+
unless @api_shim.is_provisioned?(@server)
|
189
|
+
|
190
|
+
# setup any inputs
|
191
|
+
begin
|
192
|
+
@client.set_server_inputs(@server, inputs) if inputs && ! inputs.empty?
|
193
|
+
rescue Exception => e
|
194
|
+
raise RightScaleError, "Problem setting inputs. \n #{e.message}\n\n"
|
195
|
+
end
|
196
|
+
|
197
|
+
# launch server
|
198
|
+
@logger.info "Launching server..."
|
199
|
+
@server = @api_shim.launch_server(@server, inputs)
|
200
|
+
@api_shim.set_bad_states(BAD_STATES_UP)
|
201
|
+
@api_shim.server_wait_for_state(@server, "booting", 30)
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
def server_ready?
|
207
|
+
@api_shim.server_ready?(@server)
|
208
|
+
end
|
209
|
+
|
210
|
+
def wait_for_operational
|
211
|
+
@api_shim.set_bad_states(BAD_STATES_UP)
|
212
|
+
@api_shim.server_wait_for_state(@server, "operational", 30)
|
213
|
+
end
|
214
|
+
|
215
|
+
def server_info
|
216
|
+
info = @api_shim.server_info(@server)
|
217
|
+
while info.private_ip_addresses.empty?
|
218
|
+
@logger.info "Waiting for cloud to provide IP address..."
|
219
|
+
sleep 30
|
220
|
+
info = @api_shim.server_info(@server)
|
221
|
+
end
|
222
|
+
info
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
end
|
data/lib/right_api_helper.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightApiHelper::Provisioner do
|
4
|
+
|
5
|
+
it "initializes" do
|
6
|
+
VCR.use_cassette('right_api_session') do
|
7
|
+
session = RightApiHelper::Session.new
|
8
|
+
session.should_receive(:setup_client_logging)
|
9
|
+
@right_api_client = session.create_client_from_file("~/.right_api_client/login.yml")
|
10
|
+
end
|
11
|
+
VCR.use_cassette('right_api_general') do
|
12
|
+
@helper = RightApiHelper::Provisioner.new(@right_api_client)
|
13
|
+
@logger = stub("Logger")
|
14
|
+
@helper.logger(@logger)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_api_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-05-
|
12
|
+
date: 2014-05-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: right_api_client
|
@@ -149,6 +149,7 @@ extra_rdoc_files: []
|
|
149
149
|
files:
|
150
150
|
- .gitignore
|
151
151
|
- .rspec
|
152
|
+
- CHANGELOG.md
|
152
153
|
- Gemfile
|
153
154
|
- LICENSE
|
154
155
|
- README.md
|
@@ -178,6 +179,7 @@ files:
|
|
178
179
|
- lib/right_api_helper/cache.rb
|
179
180
|
- lib/right_api_helper/deployments.rb
|
180
181
|
- lib/right_api_helper/instances.rb
|
182
|
+
- lib/right_api_helper/provisioner.rb
|
181
183
|
- lib/right_api_helper/scripts/deployments_creator.rb
|
182
184
|
- lib/right_api_helper/session.rb
|
183
185
|
- lib/right_api_helper/version.rb
|
@@ -187,6 +189,7 @@ files:
|
|
187
189
|
- spec/data/deployments.json
|
188
190
|
- spec/deployments_spec.rb
|
189
191
|
- spec/instances_spec.rb
|
192
|
+
- spec/provisioner_spec.rb
|
190
193
|
- spec/scripts/deployments_creator_spec.rb
|
191
194
|
- spec/session_spec.rb
|
192
195
|
- spec/spec_helper.rb
|
@@ -221,6 +224,7 @@ test_files:
|
|
221
224
|
- spec/data/deployments.json
|
222
225
|
- spec/deployments_spec.rb
|
223
226
|
- spec/instances_spec.rb
|
227
|
+
- spec/provisioner_spec.rb
|
224
228
|
- spec/scripts/deployments_creator_spec.rb
|
225
229
|
- spec/session_spec.rb
|
226
230
|
- spec/spec_helper.rb
|