Skip to content

Commit

Permalink
Merge pull request #24 from dprince/openstack
Browse files Browse the repository at this point in the history
Support OpenStack Accounts.
  • Loading branch information
Dan Prince committed Jan 7, 2012
2 parents 734b4f0 + 8fe6654 commit 1c5ec95
Show file tree
Hide file tree
Showing 48 changed files with 459 additions and 276 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 1c5ec95

Please sign in to comment.