diff --git a/Gemfile b/Gemfile index 0153879..3c746e2 100644 --- a/Gemfile +++ b/Gemfile @@ -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. diff --git a/Gemfile.lock b/Gemfile.lock index 70504c2..7dcd633 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -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) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index eee8b12..05105de 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -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 diff --git a/app/helpers/servers_helper.rb b/app/helpers/servers_helper.rb index 6c7d267..d00e5aa 100644 --- a/app/helpers/servers_helper.rb +++ b/app/helpers/servers_helper.rb @@ -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" diff --git a/app/models/account.rb b/app/models/account.rb index c6c8b13..ce621a3 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -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 diff --git a/app/models/image.rb b/app/models/image.rb index aa6bc5b..218c2c9 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -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 = [] diff --git a/app/models/linux_server.rb b/app/models/linux_server.rb index 463d215..f827293 100644 --- a/app/models/linux_server.rb +++ b/app/models/linux_server.rb @@ -1,5 +1,4 @@ require 'logger' -require 'cloud_servers_util' require 'async_exec' require 'openvpn_config/server' require 'openvpn_config/client' @@ -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 @@ -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 @@ -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 diff --git a/app/models/server.rb b/app/models/server.rb index 0233b9f..636c67f 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -1,6 +1,5 @@ require 'logger' require 'async_exec' -require 'cloud_servers_util' require 'timeout' require 'util/ip_validator' require 'base64' @@ -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)." @@ -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 @@ -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 @@ -213,6 +217,7 @@ def create_cloud_server(schedule_client_openvpn=false) save! sleep 10 AsyncExec.run_job(CreateCloudServer, self.id, false) + end end @@ -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 @@ -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) diff --git a/app/models/user.rb b/app/models/user.rb index c2875a6..385c853 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,4 @@ require 'digest/sha1' -require 'cloud_servers_util' class User < ActiveRecord::Base @@ -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 diff --git a/app/models/windows_server.rb b/app/models/windows_server.rb index 9b7018c..f52a005 100644 --- a/app/models/windows_server.rb +++ b/app/models/windows_server.rb @@ -1,6 +1,5 @@ require 'logger' require 'async_exec' -require 'cloud_servers_util' require 'openvpn_config/server' require 'openvpn_config/client' require 'util/ssh' @@ -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 @@ -188,11 +186,11 @@ 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 @@ -200,9 +198,9 @@ def loop_until_server_online 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 diff --git a/app/views/auth/index.html.erb b/app/views/auth/index.html.erb index 94db4ea..1d353c1 100644 --- a/app/views/auth/index.html.erb +++ b/app/views/auth/index.html.erb @@ -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(); } } diff --git a/app/views/help/index.html.erb b/app/views/help/index.html.erb index 5e92130..b004151 100644 --- a/app/views/help/index.html.erb +++ b/app/views/help/index.html.erb @@ -104,21 +104,21 @@ Create an XML file containing the following example data. Name the file example. <server> <name>boot1</name> <description>Boot 1</description> - <flavor-id type="integer">2</flavor-id> - <image-id type="integer">14</image-id> + <flavor-id>2</flavor-id> + <image-id>14</image-id> <openvpn-server type="boolean">true</openvpn-server> </server> <server> <name>gate1</name> <description>Gate 1</description> - <flavor-id type="integer">2</flavor-id> - <image-id type="integer">14</image-id> + <flavor-id>2</flavor-id> + <image-id>14</image-id> </server> <server> <name>relay1</name> <description>Gate 1</description> - <flavor-id type="integer">2</flavor-id> - <image-id type="integer">14</image-id> + <flavor-id>2</flavor-id> + <image-id>14</image-id> </server> </servers> <ssh-public-keys type="array"> diff --git a/app/views/images/edit.html.erb b/app/views/images/edit.html.erb index a45de92..c0ca420 100644 --- a/app/views/images/edit.html.erb +++ b/app/views/images/edit.html.erb @@ -30,7 +30,7 @@ $(document).ready(function() {
<%= f.label :image_ref %>
- <%= f.text_field :image_ref, :class => "image_edit" %>
+ <%= f.text_field :image_ref, :class => "image_edit", :size => 60 %>
diff --git a/app/views/server_groups/_table.html.erb b/app/views/server_groups/_table.html.erb index 8fc5551..fc0b39c 100644 --- a/app/views/server_groups/_table.html.erb +++ b/app/views/server_groups/_table.html.erb @@ -26,8 +26,8 @@
- <%= f.label :cloud_servers_username %>
- <%= f.text_field :cloud_servers_username, :class => "myaccount" %>
- <%= f.label :cloud_servers_api_key %>
- <%= f.text_field :cloud_servers_api_key, :class => "myaccount" %>
+ <%= f.label :connection_type %>: <%= f.radio_button :connection_type, 'rackspace', :checked => true %>Rackspace / <%= f.radio_button :connection_type, 'openstack' %>OpenStack
+
+ <%= f.label :username %>:
+ <%= f.text_field :username, :class => "myaccount" %>
+ <%= f.label :api_key %>:
+ <%= f.text_field(:api_key, {:class => "myaccount", :size => 60}) %>
+ <%= f.label :auth_url %>: (required for OpenStack/optional for Rackspace)
+ <%= f.text_field(:auth_url, {:class => "myaccount", :size => 80}) %>
<%= f.submit 'Update Account' %>