Skip to content

Commit

Permalink
Add support for OpenStack.
Browse files Browse the repository at this point in the history
Added support for OpenStack in addition to the existing Rackspace Cloud.

Changes include:
 -Now requires openstack-compute gem.
 -Image, Flavor, Server Ids are now tracked as strings.
 -Remove old Rails 2 files from the scripts directory.
 -Rename account table columns to make them more generic.
  • Loading branch information
Dan Prince committed Jan 7, 2012
1 parent 979ddf5 commit 8fe6654
Show file tree
Hide file tree
Showing 47 changed files with 457 additions and 274 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gem 'mysql'
gem 'resque', '~> 1.19'
gem 'will_paginate', '~> 3.0'
gem 'cloudservers'
gem 'openstack-compute'

# Gems used only for assets and not required
# in production environments by default.
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ GEM
mime-types (1.17.2)
multi_json (1.0.4)
mysql (2.8.1)
openstack-compute (1.1.5)
json
polyglot (0.3.3)
rack (1.3.6)
rack-cache (1.1)
Expand Down Expand Up @@ -125,6 +127,7 @@ DEPENDENCIES
cloudservers
coffee-rails (~> 3.1.1)
mysql
openstack-compute
rails (= 3.1.1)
resque (~> 1.19)
sass-rails (~> 3.1.4)
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def update
def limits

@account = Account.find(params[:id])
cs=CloudServersUtil.new(@account.cloud_servers_username, @account.cloud_servers_api_key)
render :text => cs.account_limits.to_json, :status => "200"
conn = @account.get_connection
render :text => conn.account_limits.to_json, :status => "200"

end

Expand Down
14 changes: 7 additions & 7 deletions app/helpers/servers_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ def image_name(id)

def flavor_name(id)
return case id
when 1
when "1"
"256MB"
when 2
when "2"
"512MB"
when 3
when "3"
"1GB"
when 4
when "4"
"2GB"
when 5
when "5"
"4GB"
when 6
when "6"
"8GB"
when 7
when "7"
"15.5GB"
else
"Unknown"
Expand Down
14 changes: 13 additions & 1 deletion app/models/account.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
require 'rackspace_connection'

class Account < ActiveRecord::Base

belongs_to :user
belongs_to :user

def get_connection
if self.connection_type == 'rackspace' then
return RackspaceConnection.new(self.username, self.api_key, self.auth_url)
elsif self.connection_type == 'openstack' then
return OpenstackConnection.new(self.username, self.api_key, self.auth_url)
else
raise "Unsupported account connection type."
end
end

end
2 changes: 1 addition & 1 deletion app/models/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Image < ActiveRecord::Base

def self.sync(user)
acct=user.account
conn = CloudServersUtil.new(acct.cloud_servers_username, acct.cloud_servers_api_key)
conn = acct.get_connection

image_refs = []

Expand Down
18 changes: 8 additions & 10 deletions app/models/linux_server.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require 'logger'
require 'cloud_servers_util'
require 'async_exec'
require 'openvpn_config/server'
require 'openvpn_config/client'
Expand Down Expand Up @@ -70,8 +69,7 @@ def create_openvpn_client

# server is online but can't ping OpenVPN servers .10 IP
if not ping_test(vpn_server.internal_ip_addr) then
cs_conn=self.cloud_server_init
cs_conn.reboot_server(self.cloud_server_id_number)
self.account_connection.reboot_server(self.cloud_server_id_number)
self.add_error_message("Server failed ping test.")
self.retry_count += 1
self.save
Expand Down Expand Up @@ -127,20 +125,20 @@ def create_openvpn_client

# method to block until a server is online
def loop_until_server_online
cs_conn=self.cloud_server_init
conn = self.account_connection

error_message="Failed to build server."
error_message = "Failed to build server."

timeout=self.server_online_timeout-(Time.now-self.updated_at).to_i
timeout = self.server_online_timeout-(Time.now-self.updated_at).to_i
timeout = 120 if timeout < 120

begin
Timeout::timeout(timeout) do

# poll the server until progress is 100%
cs=cs_conn.find_server("#{self.cloud_server_id_number}")
until cs.progress == 100 and cs.status == "ACTIVE" do
cs=cs_conn.find_server("#{self.cloud_server_id_number}")
cs = conn.get_server(self.cloud_server_id_number)
until cs[:progress] == 100 and cs[:status] == "ACTIVE" do
cs = conn.get_server(self.cloud_server_id_number)
sleep 1
end

Expand All @@ -149,7 +147,7 @@ def loop_until_server_online
if ! system(%{
COUNT=0
while ! ssh -o "StrictHostKeyChecking no" -T -i #{self.server_group.ssh_key_basepath} root@#{cs.addresses[:public][0]} /bin/true > /dev/null 2>&1; do
while ! ssh -o "StrictHostKeyChecking no" -T -i #{self.server_group.ssh_key_basepath} root@#{cs[:public_ip]} /bin/true > /dev/null 2>&1; do
if (($COUNT > 23)); then
exit 1
fi
Expand Down
34 changes: 19 additions & 15 deletions app/models/server.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'logger'
require 'async_exec'
require 'cloud_servers_util'
require 'timeout'
require 'util/ip_validator'
require 'base64'
Expand All @@ -19,8 +18,6 @@ class Server < ActiveRecord::Base
belongs_to :server_group
belongs_to :account
validates_presence_of :name, :description, :flavor_id, :image_id, :server_group_id, :account_id
validates_numericality_of :flavor_id, :image_id, :server_group_id
validates_numericality_of :cloud_server_id_number, :if => :cloud_server_id_number
has_many :vpn_network_interfaces, :as => :interfacable, :dependent => :destroy
has_many :server_errors
validates_format_of :name, :with => /^[A-Za-z0-9\-\.]+$/, :message => "Server name must use valid hostname characters (A-Z, a-z, 0-9, dash)."
Expand Down Expand Up @@ -172,16 +169,23 @@ def create_cloud_server(schedule_client_openvpn=false)
server_name_prefix=ENV['RACKSPACE_CLOUD_SERVER_NAME_PREFIX']
end

cs_conn=self.cloud_server_init
conn = self.account_connection

retry_suffix=self.retry_count > 0 ? "#{rand(10)}-#{self.retry_count}" : "#{rand(10)}"
cs=cs_conn.create_cloud_server("#{server_name_prefix}#{self.name}-#{self.server_group_id}-#{retry_suffix}", self.image_id, self.flavor_id, generate_personalities)
server_id, admin_password = conn.create_server("#{server_name_prefix}#{self.name}-#{self.server_group_id}-#{retry_suffix}", self.image_id, self.flavor_id, generate_personalities)
@tmp_files.each {|f| f.close(true)} #Remove tmp personalities files
#harvest server ID and IP information
self.cloud_server_id_number = cs.id
self.external_ip_addr = cs.addresses[:public][0]
self.internal_ip_addr = cs.addresses[:private][0]
self.admin_password = cs.adminPass if is_windows
self.cloud_server_id_number = server_id
self.admin_password = admin_password if is_windows
save!

server = conn.get_server(server_id)
until server[:public_ip] and server[:private_ip] do
server = conn.get_server(server_id)
sleep 1
end
self.external_ip_addr = server[:public_ip]
self.internal_ip_addr = server[:private_ip]
save!

# if this server is an OpenVPN server create it now
Expand All @@ -196,13 +200,13 @@ def create_cloud_server(schedule_client_openvpn=false)
rescue Exception => e
self.retry_count += 1
self.status = "Pending" # keep status set to pending

#
long_error_message=nil
begin
long_error_message="#{e.message}: #{e.response_body}"
rescue
end

#
if e and e.message and long_error_message then
self.add_error_message("Failed to create cloud server: #{e.message}", long_error_message)
elsif e and e.message then
Expand All @@ -213,6 +217,7 @@ def create_cloud_server(schedule_client_openvpn=false)
save!
sleep 10
AsyncExec.run_job(CreateCloudServer, self.id, false)

end

end
Expand All @@ -224,8 +229,7 @@ def delete_cloud_server(cloud_server_id)
until deleted or retry_count >= 3 do
begin
retry_count += 1
cs_conn=self.cloud_server_init
cs_conn.destroy_server(cloud_server_id)
self.account_connection.destroy_server(cloud_server_id)
deleted = true
rescue
# ignore all exceptions on delete
Expand Down Expand Up @@ -255,9 +259,9 @@ def rebuild
end
end

def cloud_server_init
def account_connection
acct=Account.find(self.account_id)
CloudServersUtil.new(acct.cloud_servers_username, acct.cloud_servers_api_key)
acct.get_connection
end

def add_error_message(message, long_error_message=message)
Expand Down
5 changes: 2 additions & 3 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require 'digest/sha1'
require 'cloud_servers_util'

class User < ActiveRecord::Base

Expand Down Expand Up @@ -33,9 +32,9 @@ def handle_validate_on_create
else
begin
acct=self.account
CloudServersUtil.new(acct.cloud_servers_username, acct.cloud_servers_api_key)
acct.get_connection
rescue Exception => e
errors[:base] << "Invalid cloud servers username or api key specified: #{e.message}"
errors[:base] << "Unable to connect with cloud account credentials: #{e.message}"
end
end

Expand Down
16 changes: 7 additions & 9 deletions app/models/windows_server.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'logger'
require 'async_exec'
require 'cloud_servers_util'
require 'openvpn_config/server'
require 'openvpn_config/client'
require 'util/ssh'
Expand Down Expand Up @@ -38,8 +37,7 @@ def create_openvpn_client

# server is online but can't ping OpenVPN servers .10 IP
if not ping_test(vpn_server.internal_ip_addr) then
cs_conn=self.cloud_server_init
cs_conn.reboot_server(self.cloud_server_id_number)
self.account_connection.reboot_server(self.cloud_server_id_number)
self.add_error_message("Server failed ping test.")
self.retry_count += 1
self.save
Expand Down Expand Up @@ -188,21 +186,21 @@ def configure_openvpn_client(client_key, client_cert, ca_cert)

# method to block until a server is online
def loop_until_server_online
cs_conn=self.cloud_server_init
conn = self.account_connection

error_message="Failed to build server."
error_message = "Failed to build server."

timeout=self.windows_server_online_timeout-(Time.now-self.updated_at).to_i
timeout = self.windows_server_online_timeout-(Time.now-self.updated_at).to_i
timeout = 2000 if self.image_id == 58 # FIXME remove this when image customization support and settings are added
timeout = 120 if timeout < 120

begin
Timeout::timeout(timeout) do

# poll the server until progress is 100%
cs=cs_conn.find_server("#{self.cloud_server_id_number}")
until cs.progress == 100 and cs.status == "ACTIVE" do
cs=cs_conn.find_server("#{self.cloud_server_id_number}")
cs = conn.get_server(self.cloud_server_id_number)
until cs[:progress] == 100 and cs[:status] == "ACTIVE" do
cs = conn.get_server(self.cloud_server_id_number)
sleep 1
end

Expand Down
4 changes: 2 additions & 2 deletions app/views/auth/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ $(document).ready(function() {

$("#user-dialog").dialog({
modal: true,
height: 500,
width: 600,
height: $(window).height()-50,
width: $(window).width()-50,
buttons: {
"Create": function() { user_create(); }
}
Expand Down
12 changes: 6 additions & 6 deletions app/views/help/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,21 @@ Create an XML file containing the following example data. Name the file example.
&lt;server&gt;
&lt;name&gt;boot1&lt;/name&gt;
&lt;description&gt;Boot 1&lt;/description&gt;
&lt;flavor-id type="integer"&gt;2&lt;/flavor-id&gt;
&lt;image-id type="integer"&gt;14&lt;/image-id&gt;
&lt;flavor-id&gt;2&lt;/flavor-id&gt;
&lt;image-id&gt;14&lt;/image-id&gt;
&lt;openvpn-server type="boolean"&gt;true&lt;/openvpn-server&gt;
&lt;/server&gt;
&lt;server&gt;
&lt;name&gt;gate1&lt;/name&gt;
&lt;description&gt;Gate 1&lt;/description&gt;
&lt;flavor-id type="integer"&gt;2&lt;/flavor-id&gt;
&lt;image-id type="integer"&gt;14&lt;/image-id&gt;
&lt;flavor-id&gt;2&lt;/flavor-id&gt;
&lt;image-id&gt;14&lt;/image-id&gt;
&lt;/server&gt;
&lt;server&gt;
&lt;name&gt;relay1&lt;/name&gt;
&lt;description&gt;Gate 1&lt;/description&gt;
&lt;flavor-id type="integer"&gt;2&lt;/flavor-id&gt;
&lt;image-id type="integer"&gt;14&lt;/image-id&gt;
&lt;flavor-id&gt;2&lt;/flavor-id&gt;
&lt;image-id&gt;14&lt;/image-id&gt;
&lt;/server&gt;
&lt;/servers&gt;
&lt;ssh-public-keys type="array"&gt;
Expand Down
2 changes: 1 addition & 1 deletion app/views/images/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ $(document).ready(function() {

<p>
<%= f.label :image_ref %><br />
<%= f.text_field :image_ref, :class => "image_edit" %>
<%= f.text_field :image_ref, :class => "image_edit", :size => 60 %>
</p>

<p>
Expand Down
4 changes: 2 additions & 2 deletions app/views/server_groups/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
<td><%= server_group.id %></td>
<td><%= raw chop_for_html(server_group.name) %></td>
<td><%= raw chop_for_html(server_group.description) %></td>
<% if server_group.user.account.cloud_servers_username then %>
<td><%= raw chop_for_html(server_group.user.account.cloud_servers_username) %></td>
<% if server_group.user.account.username then %>
<td><%= raw chop_for_html(server_group.user.account.username) %></td>
<% else %>
<td>&nbsp;</td>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/server_groups/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ $(document).ready(function() {
}
);

<% if @account.cloud_servers_api_key.blank? then %>
<% if @account.api_key.blank? then %>
$("#server-group-error-messages").css("display", "inline");
$("#server-group-error-messages-content").html("Please enter your cloud servers account credentials under 'settings'.");
<% end %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/servers/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
<tr class="<%= cycle "tr0", "tr1" %>">
<td><%= raw chop_for_html(server.server_group.name, 20) %>(<%= server.server_group.id %>)</td>
<td><%= raw chop_for_html(server.server_group.owner_name) %></td>
<td><%= raw chop_for_html(server.account.cloud_servers_username) %></td>
<td><%= raw chop_for_html(server.account.username) %></td>
<td><%= raw chop_for_html(server.name) %></td>
<% if server.external_ip_addr or server.internal_ip_addr %>
<td><%= server.external_ip_addr %>/<%= server.internal_ip_addr %></td>
<% else %>
<td>N/A</td>
<% end %>
<td><%= server.cloud_server_id_number %></td>
<td><%= raw chop_for_html(server.cloud_server_id_number, 15) %></td>
<td><%= flavor_name(server.flavor_id) %></td>
<td><%= raw chop_for_html(image_name(server.image_id), 15) %></td>
<td align="center"><%= raw check_or_blank(server.openvpn_server) %></td>
Expand Down
4 changes: 2 additions & 2 deletions app/views/servers/_table_history.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
<tr class="<%= cycle "tr0", "tr1" %>">
<td><%= raw chop_for_html(server.server_group.name, 20) %>(<%= server.server_group.id %>)</td>
<td><%= raw chop_for_html(server.server_group.owner_name) %></td>
<td><%= raw chop_for_html(server.account.cloud_servers_username) %></td>
<td><%= raw chop_for_html(server.account.username) %></td>
<td><%= raw chop_for_html(server.name) %></td>
<td><%= timestamp(server.created_at.in_time_zone) %></td>
<td><%= server.cloud_server_id_number %></td>
<td><%= raw chop_for_html(server.cloud_server_id_number, 15) %></td>
<td><%= flavor_name(server.flavor_id) %></td>
<td><%= raw chop_for_html(image_name(server.image_id), 15) %></td>
<td align="center"><%= raw check_or_blank(server.openvpn_server) %></td>
Expand Down
Loading

0 comments on commit 8fe6654

Please sign in to comment.