From: martyntaylor <mtaylor(a)redhat.com>
---
src/app/controllers/pool_controller.rb | 30 +++++-
src/app/controllers/pool_controller.rb~ | 138 ++++++++++++++++++++++++
src/app/models/instance_observer.rb | 9 +-
src/app/views/pool/new_quota.html.erb | 18 +++
src/app/views/pool/quota.html.erb | 3 +-
src/app/views/pool/show.html.erb~ | 42 +++++++
src/config/environment.rb | 2 +-
src/db/migrate/20090802000000_create_quotas.rb | 6 -
src/spec/models/instance_observer_spec.rb | 60 ++++++++---
9 files changed, 279 insertions(+), 29 deletions(-)
create mode 100644 src/app/controllers/pool_controller.rb~
create mode 100644 src/app/views/pool/new_quota.html.erb
create mode 100644 src/app/views/pool/show.html.erb~
diff --git a/src/app/controllers/pool_controller.rb
b/src/app/controllers/pool_controller.rb
index d5fc8af..632d0cb 100644
--- a/src/app/controllers/pool_controller.rb
+++ b/src/app/controllers/pool_controller.rb
@@ -143,8 +143,32 @@ class PoolController < ApplicationController
def quota
@pool = Pool.find(params[:id])
- puts @pool.id
- @quota = Quota.find(:first, :conditions => { :pool_id => @pool })
+ if Quota.exists?((a)pool.quota_id)
+ @quota = Quota.find((a)pool.quota_id)
+ end
+ require_privilege(Privilege::QUOTA_VIEW, @pool)
+ end
+
+ def new_quota
+ @pool = Pool.find(params[:id])
+ require_privilege(Privilege::POOL_MODIFY, @pool)
+ end
+
+ def create_quota
+ if !Quota.exists?((a)pool.quota_id)
+ @pool = Pool.find(params[:pool][:id])
+ require_privilege(Privilege::POOL_MODIFY, @pool)
+
+ @quota = Quota.new(params[:quota])
+ @quota.save!
+
+ @pool.quota_id = @quota
+ @pool.save!
+
+ redirect_to :action => 'quota', :id => @pool
+ else
+ errors.add("quota_id", "There already exists a quota for this
pool")
+ end
end
-end
+end
\ No newline at end of file
diff --git a/src/app/controllers/pool_controller.rb~
b/src/app/controllers/pool_controller.rb~
new file mode 100644
index 0000000..137fdd5
--- /dev/null
+++ b/src/app/controllers/pool_controller.rb~
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at
http://www.gnu.org/copyleft/gpl.html.
+
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+require 'util/taskomatic'
+
+class PoolController < ApplicationController
+ before_filter :require_user
+
+ def index
+ render :action => 'new'
+ end
+
+ def show
+ #FIXME: clean this up, many error cases here
+ @pool = Pool.find(params[:id])
+ require_privilege(Privilege::INSTANCE_VIEW,@pool)
+ # pass nil into Taskomatic as we're not working off a task here
+ Taskomatic.new(nil,logger).pool_refresh(@pool)
+ @pool.reload
+ @instances = @pool.instances
+ end
+
+ def hardware_profiles
+ @pool = Pool.find(params[:id])
+ @hardware_profiles = @pool.hardware_profiles
+ require_privilege(Privilege::POOL_VIEW, @pool)
+ end
+
+ def realms
+ @pool = Pool.find(params[:id])
+ @realm_names = @pool.realms
+ require_privilege(Privilege::POOL_VIEW,@pool)
+ end
+
+ def new
+ require_privilege(Privilege::POOL_MODIFY)
+ @pool = Pool.new
+ end
+
+ def create
+ require_privilege(Privilege::POOL_MODIFY)
+
+ #FIXME: owner is set to current user for self-service account creation,
+ # but in the more general case we need a way for the admin to pick
+ # a user
+ params[:pool][:owner_id] = @current_user.id
+
+ #FIXME: This should probably be in a transaction
+ @pool = Pool.new(params[:pool])
+ perm = Permission.new(:user => @pool.owner,
+ :role => Role.find_by_name("Instance Creator and
User"),
+ :permission_object => @pool)
+ perm.save!
+ # FIXME: do we need any more handling around save failures? What if perm
+ # creation fails?
+ flash[:notice] = "Pool added."
+ redirect_to :action => 'show', :id => @pool.id
+ end
+
+ def delete
+ end
+
+ def instances_paginate
+ @pool = Pool.find(params[:id])
+ require_privilege(Privilege::POOL_VIEW, @pool)
+
+ # datatables sends pagination in format:
+ # iDisplayStart - start index
+ # iDisplayLength - num of recs
+ # => we need to count page num
+ page = params[:iDisplayStart].to_i / Instance::per_page
+
+ order_col_rec = Instance::COLUMNS[params[:iSortCol_0].to_i]
+ order_col = Instance::COLUMNS[2] unless order_col_rec &&
order_col_rec[:opts][:searchable]
+ order = order_col[:id] + " " + (params[:sSortDir_0] == 'desc' ?
'desc' : 'asc')
+
+ @instances = Instance.search_filter(params[:sSearch],
Instance::SEARCHABLE_COLUMNS).paginate(
+ :page => page + 1,
+ :order => order,
+ :conditions => {:pool_id => @pool.id}
+ )
+
+ render :json => {
+ :sEcho => params[:sEcho],
+ :iTotalRecords => @instances.total_entries,
+ :iTotalDisplayRecords => @instances.total_entries,
+ :aaData => @instances.map {|i| [i.id, "", i.name, i.state,
i.hardware_profile.name, i.image.name]}
+ }
+ end
+
+
+ def accounts_for_pool
+ @pool = Pool.find(params[:pool_id])
+ require_privilege(Privilege::ACCOUNT_VIEW,@pool)
+ @cloud_accounts = []
+ all_accounts = CloudAccount.list_for_user(@current_user, Privilege::ACCOUNT_ADD)
+ all_accounts.each {|account|
+ @cloud_accounts << account unless @pool.cloud_accounts.map{|x|
x.id}.include?(account.id)
+ }
+ end
+
+ def add_account
+ @pool = Pool.find(params[:pool])
+ @cloud_account = CloudAccount.find(params[:cloud_account])
+ require_privilege(Privilege::ACCOUNT_ADD,@pool)
+ require_privilege(Privilege::ACCOUNT_ADD,@cloud_account)
+ Pool.transaction do
+ @pool.cloud_accounts << @cloud_account unless @pool.cloud_accounts.map{|x|
x.id}.include?((a)cloud_account.id)
+ @pool.save!
+ @pool.populate_realms_and_images([@cloud_account])
+ end
+ redirect_to :action => 'show', :id => @pool.id
+ end
+
+ def quota
+ @pool = Pool.find(params[:id])
+ puts @pool.id
+ @quota = Quota.find(:first, :conditions => { :pool_id => @pool })
+ end
+end
diff --git a/src/app/models/instance_observer.rb b/src/app/models/instance_observer.rb
index ab1a095..9b0461a 100644
--- a/src/app/models/instance_observer.rb
+++ b/src/app/models/instance_observer.rb
@@ -1,6 +1,6 @@
class InstanceObserver < ActiveRecord::Observer
- ACTIVE_STATES = [ Instance::STATE_PENDING, Instance::STATE_RUNNING,
Instance::STATE_SHUTTING_DOWN ]
+ ACTIVE_STATES = [ Instance::STATE_NEW, Instance::STATE_PENDING,
Instance::STATE_RUNNING, Instance::STATE_SHUTTING_DOWN, Instance::STATE_STOPPED ]
def before_save(an_instance)
if an_instance.changed?
@@ -34,7 +34,8 @@ class InstanceObserver < ActiveRecord::Observer
def update_quota(state_from, state_to, an_instance)
hwp = HardwareProfile.find(an_instance.hardware_profile_id)
- quota = Quota.find(:first, :conditions => { :pool_id => an_instance.pool_id })
+ pool = Pool.find(an_instance.pool_id)
+ quota = Quota.find(pool.quota_id)
if(quota)
if state_to == Instance::STATE_RUNNING
@@ -43,7 +44,7 @@ class InstanceObserver < ActiveRecord::Observer
quota.running_memory += hwp.memory
elsif state_from == Instance::STATE_RUNNING
#TODO update running cpus
- quota.running_instances --
+ quota.running_instances -= 1
quota.running_memory -= hwp.memory
end
@@ -55,7 +56,7 @@ class InstanceObserver < ActiveRecord::Observer
quota.total_instances -= 1
end
- quota.save
+ quota.save!
end
end
end
diff --git a/src/app/views/pool/new_quota.html.erb
b/src/app/views/pool/new_quota.html.erb
new file mode 100644
index 0000000..4290862
--- /dev/null
+++ b/src/app/views/pool/new_quota.html.erb
@@ -0,0 +1,18 @@
+<div class="dcloud_form">
+ <%= error_messages_for 'pool' %>
+
+ <h2>Create Quota for Pool: <%= @pool.name
%></legend></h2><br />
+
+ <% form_tag :action => 'create_quota' do -%>
+ <%=hidden_field :pool, :id %>
+ <ul>
+ <li><label>Max Running Instances</label><%= text_field :quota,
:maximum_running_instances %></li>
+ <li><label>Max Running Memory</label><%= text_field :quota,
:maximum_running_memory %></li>
+ <li><label>Max Running CPUs</label><%= text_field :quota,
:maximum_running_cpus %></li>
+ <li><label>Max Total Instances</label><%= text_field :quota,
:maximum_total_instances %></li>
+ <li><label>Max Total Storage</label><%= text_field :quota,
:maximum_total_storage %></li>
+ </ul>
+ </fieldset>
+ <%= submit_tag "Save", :class => "submit" %>
+ <% end %>
+</div>
\ No newline at end of file
diff --git a/src/app/views/pool/quota.html.erb b/src/app/views/pool/quota.html.erb
index edd4463..09b227e 100644
--- a/src/app/views/pool/quota.html.erb
+++ b/src/app/views/pool/quota.html.erb
@@ -1,5 +1,6 @@
-<% if @quota == nil %>
+<% if !@quota %>
<h1>There is no quota associated with this pool</h1>
+<%= link_to "Create a Quota", {:controller => "pool", :action
=> "new_quota", :id => @pool}, :class=>"actionlink"%>
<% else %>
<table>
<thead>
diff --git a/src/app/views/pool/show.html.erb~ b/src/app/views/pool/show.html.erb~
new file mode 100644
index 0000000..2b46781
--- /dev/null
+++ b/src/app/views/pool/show.html.erb~
@@ -0,0 +1,42 @@
+<script type="text/javascript">
+ function clickRow(ev) {
+ var box = $('input[name="image_id[]"]', ev.target.parentNode);
+ if ($(ev.target).attr('name') != "image_id[]")
+ box.attr('checked', !box.attr('checked'));
+ }
+
+ function checkAll(ev) {
+ $('input[name="image_id[]"]',
dataTable_instances_table).attr('checked', $(ev.target).attr('checked'))
+ }
+</script>
+
+<%= datatable(
+ Instance::COLUMNS.map {|c| c[:opts]},
+ {
+ :table_dom_id => 'instances_table',
+ :per_page => Instance::per_page,
+ :sort_by => "[3, 'asc']",
+ :serverside => true,
+ :ajax_source => url_for(:controller => 'pool', :action =>
'instances_paginate') + "/#{(a)pool.id}",
+ :append => ".fnSetFilteringDelay()",
+ :persist_state => false,
+ :click_callback => "function(ev) {clickRow(ev);}",
+ }
+) %>
+
+<table class="datatable display" id="instances_table">
+ <thead>
+ <tr>
+ <% Instance::COLUMNS.each do |c| %>
+ <%= "<th>#{c[:header]}</th>" %>
+ <% end %>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+</table>
+<%= link_to "Add a new instance", {:controller => "instance",
:action => "new", "instance[pool_id]" => @pool},
:class=>"actionlink"%>
+<%= link_to "User access", {:controller => "permissions",
:action => "list", :pool_id => @pool.id},
:class=>"actionlink" if has_view_perms? %>
+<%= link_to "Hardware Profiles", {:action =>
"hardware_profiles", :id => @pool.id},
:class=>"actionlink"%>
+<%= link_to "Realms", {:action => "realms", :id =>
@pool.id}, :class=>"actionlink"%>
+<%= link_to "Quota", {:action => "quota", :id => @pool},
:class=>"actionlink"%>
diff --git a/src/config/environment.rb b/src/config/environment.rb
index 1721126..9f0fa4f 100644
--- a/src/config/environment.rb
+++ b/src/config/environment.rb
@@ -43,7 +43,7 @@ Rails::Initializer.run do |config|
config.gem "gettext", :lib => "gettext_rails"
config.gem "gettext", :lib => "gettext_activerecord"
config.gem "authlogic"
- config.gem "deltacloud-client", :lib => "deltacloud"
+ config.gem "deltacloud-cliesrc/config/environment.rbnt", :lib =>
"deltacloud"
config.gem "haml"
config.gem "will_paginate"
diff --git a/src/db/migrate/20090802000000_create_quotas.rb
b/src/db/migrate/20090802000000_create_quotas.rb
index 29cc5bf..01c885d 100644
--- a/src/db/migrate/20090802000000_create_quotas.rb
+++ b/src/db/migrate/20090802000000_create_quotas.rb
@@ -20,12 +20,6 @@
class CreateQuotas < ActiveRecord::Migration
def self.up
create_table :quotas do |t|
- t.integer :running_cpus
- t.integer :running_memory
- t.integer :running_instances
- t.integer :total_storage
- t.integer :total_instances
- t.integer :pool_id
t.integer :running_cpus, :default => 0
t.integer :running_memory, :default => 0
t.integer :running_instances, :default => 0
diff --git a/src/spec/models/instance_observer_spec.rb
b/src/spec/models/instance_observer_spec.rb
index 76514e5..7051955 100644
--- a/src/spec/models/instance_observer_spec.rb
+++ b/src/spec/models/instance_observer_spec.rb
@@ -4,7 +4,10 @@ describe InstanceObserver do
before(:each) do
@timestamp = Time.now
- @instance = Factory :new_instance
+ @hwp = Factory :mock_hwp1
+ @pool = Factory :pool
+ @quota = Factory(:quota, :pool_id => @pool.id)
+ @instance = Factory(:new_instance, :pool => @pool, :hardware_profile => @hwp)
end
it "should set started at timestamp when instance goes to state pending" do
@@ -55,7 +58,7 @@ describe InstanceObserver do
sleep(1)
@instance.state = Instance::STATE_SHUTTING_DOWN
- @instance.save
+ @instance.save!
@instance.acc_running_time.should >= 1
@instance.acc_running_time.should <= 2
@@ -87,22 +90,51 @@ describe InstanceObserver do
@instance.acc_stopped_time.should <= 2
end
- it "should update a pools quota when an associated instance state goes to
running" do
- hwp = Factory :mock_hwp1
- pool = Factory :pool
- quota = Factory(:quota, :pool_id => pool.id)
- instance = Factory(:new_instance, :pool => pool, :hardware_profile => hwp)
+ it "should update quota when a new pool instance is created" do
+ @quota = Quota.find(@quota)
+
+ @quota.total_instances.should == 1
+ @quota.total_storage.should == @hwp.storage
+ end
+
+ it "should update quota when a pool instance goes into an inactive state" do
+ @quota = Quota.find(@quota)
+
+ @instance.state = Instance::STATE_CREATE_FAILED
+ @quota.total_instances.should == 0
+ @quota.total_storage.should == 0
+ end
+
+ it "should update a pools quota when an pool instance state goes to running"
do
+ @quota = Quota.find(@quota)
+
+ @instance.state = Instance::STATE_RUNNING
+ @instance.save!
- instance.state = Instance::STATE_RUNNING
- instance.save
+ @quota = Quota.find((a)quota.id)
+ @quota.running_instances.should == 1
+ @quota.running_memory.should == @hwp.memory
+ #TODO test for cpus
+
+ @quota.total_storage.should == @hwp.storage
+ @quota.total_instances.should == 1
+ end
+
+ it "should update a pools quota when an associated instance state goes from
running another active state" do
+ @quota = Quota.find(@quota)
+
+ @instance.state = Instance::STATE_RUNNING
+ @instance.save!
+
+ @instance.state = Instance::STATE_SHUTTING_DOWN
+ @instance.save!
- quota = Quota.find_by_id(quota.id)
- quota.running_instances.should == 1
- quota.running_memory.should == hwp.memory
#TODO test for cpus
+ @quota.running_instances.should == 0
+ @quota.running_memory.should == 0
- quota.total_storage.should == hwp.storage
- quota.total_instances.should == 1
+ @quota.total_storage.should == @hwp.storage
+ @quota.total_instances.should == 1
end
end
\ No newline at end of file
--
1.6.6.1