Hi all,
I'm attaching a patch for #1529, getting PoolsController#show to work with the new UI. I haven't applied the Wonder Twins' styling; my understanding is that this will be done as a separate step. Please let me know if this is incorrect and I'm submitting something hideously ugly that's not supposed to be.
I also have some scattered musings/questions about this below:
- There are a few components I haven't implemented because I don't believe they're ready / in scope yet. Namely, the "Alerts" section of the page and the Deployments / History / Properties / Permission line, including the buttons to the right of those tabs.
- Is there an existing implementation of switching between 'filter' and 'pretty' views? I suspect that multiple tasks are going to involve doing this, and want to make sure I'm not reinventing the wheel.
- I added a "statistics" method to pools, returning the data required for the partial at top. (Except for Alerts, Updates, and Quota, which I don't believe are ready to be implemented.) You'll note that I have it in a commented-out Rails.cache.fetch block. If uncommented, it'll store the result in local memory. (We don't need to pull in memcache this way.) It's commented out right now because it'll take some work to make sure we invalidate it properly, and I wanted someone else to sanity-check this idea before I implemented it. The Rails logs indicate that the queries for this section takes about 25ms; this isn't a crazy amount of time, but I suspect these sections will start to add up.
- A few sections seem to imply that we care about the state/status of a deployment, but the code has no such concept just yet. Instances have a state, but their deployments do not. Retrieving it through the association implies that we cannot (easily, at least) sort or filter on deployment state. It's also unclear to me what the state of a deployment would be if it had multiple instances in different states. Has someone already figured this out?
- You may note some deep associations being used, like "deployment.realm.provider.provider_type.name". I tried to add a few associations where they made sense, but it wouldn't hurt for someone to give a little extra scrutiny to make sure I didn't do anything too foolish.
-- Matt
Implements https://www.aeolusproject.org/redmine/issues/1529 --- src/app/controllers/pools_controller.rb | 23 ++++++++++++----------- src/app/models/deployment.rb | 3 +++ src/app/models/instance.rb | 9 ++++++++- src/app/models/pool.rb | 16 ++++++++++++++++ src/app/views/deployments/_deployment.haml | 11 +++++++++++ src/app/views/deployments/_filter_view.haml | 15 +++++++++++++++ src/app/views/deployments/_pretty_view.haml | 1 + src/app/views/pools/_statistics.haml | 21 +++++++++++++++++++++ src/app/views/pools/edit.haml | 2 +- src/app/views/pools/show.haml | 10 ++++++---- 10 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 src/app/views/deployments/_deployment.haml create mode 100644 src/app/views/deployments/_filter_view.haml create mode 100644 src/app/views/deployments/_pretty_view.haml create mode 100644 src/app/views/pools/_statistics.haml
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 1402cca..93af54e 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -3,6 +3,7 @@ class PoolsController < ApplicationController before_filter :set_params_and_header, :only => [:index, :show] before_filter :load_pools, :only => [:show] layout 'application' + helper DeploymentsHelper
def index @search_term = params[:q] @@ -20,18 +21,11 @@ class PoolsController < ApplicationController def show @pool = Pool.find(params[:id]) require_privilege(Privilege::VIEW, @pool) - @url_params = params.clone - load_instances - @tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions'] - @details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab] + @statistics = @pool.statistics + @view = params[:view] == 'filter' ? 'deployments/filter_view' : 'deployments/pretty_view' respond_to do |format| - format.js do - if @url_params.delete :details_pane - render :partial => 'layouts/details_pane' and return - end - render :partial => @details_tab and return - end - format.html { render :action => 'show'} + format.js { render :partial => @view, :locals => {:deployments => @pool.deployments} } + format.html { render :action => :show} format.json { render :json => @pool } end end @@ -165,6 +159,13 @@ class PoolsController < ApplicationController { :name => "Pool Family", :sort_attr => "pool_families.name" }, { :name => "Enabled", :sort_attr => :enabled } ] + @deployments_header = [ + { :name => "Deployment Name", :sort_attr => :name }, + { :name => "Base Deployable", :sort_attr => 'deployable.name' }, + { :name => "Uptime", :sort_attr => :created_at }, + { :name => "Instances", :sort_attr => 'instances.count' }, + { :name => "Provider", :sort_attr => :provider } + ] end
def load_pools diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb index 9f382c0..11e2b97 100644 --- a/src/app/models/deployment.rb +++ b/src/app/models/deployment.rb @@ -55,6 +55,9 @@ class Deployment < ActiveRecord::Base :order => "permissions.id ASC" belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" after_create "assign_owner_roles(owner)" + # TODO - Strictly, this should be a belongs_to, but :through seems to only work one-way, + # and we don't much care about the inverse here. + has_one :provider, :through => :realm
validates_presence_of :pool_id validates_presence_of :deployable_id diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index ef38263..4d1c5c6 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -117,6 +117,13 @@ class Instance < ActiveRecord::Base STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED, STATE_ERROR]
+ named_scope :deployed, :conditions => { :state => [STATE_RUNNING, STATE_SHUTTING_DOWN] } + # FIXME: "pending" is misleading as it doesn't just cover STATE_PENDING + named_scope :pending, :conditions => { :state => [STATE_NEW, STATE_PENDING] } + # FIXME: "failed" is misleading too... + named_scope :failed, :conditions => { :state => [STATE_CREATE_FAILED, STATE_ERROR] } + + SEARCHABLE_COLUMNS = %w(name state)
validates_inclusion_of :state, @@ -261,7 +268,7 @@ class Instance < ActiveRecord::Base }
instances = [] - pools = Pool.list_for_user(user, Privilege::VIEW, Instance) + pools = Pool.list_for_user(user, Privilege::VIEW, :target_type => Instance) pools.each{|pool| pool.instances.each {|i| instances << i}} instances.each do |i| if i.state == Instance::STATE_RUNNING diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 87f5c19..6a28794 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -60,6 +60,8 @@ class Pool < ActiveRecord::Base :include => [:role], :order => "permissions.id ASC"
+ has_many :deployments, :through => :instances + before_destroy :destroyable?
def cloud_accounts @@ -75,4 +77,18 @@ class Pool < ActiveRecord::Base instances.all? {|i| i.destroyable? } end
+ # TODO: Implement Alerts, Updates, and Quotas + def statistics + # TODO - Need to set up cache invalidation before this is safe + #Rails.cache.fetch("pool-#{id}-statistics") do + { + :cloud_providers => instances.collect{|i| i.provider_account}.uniq.count, + :deployments => deployments.count, + :instances_deployed => instances.deployed.count, + :instances_pending => instances.pending.count, + :instances_failed => instances.failed.count + } + #end + end + end diff --git a/src/app/views/deployments/_deployment.haml b/src/app/views/deployments/_deployment.haml new file mode 100644 index 0000000..669bbce --- /dev/null +++ b/src/app/views/deployments/_deployment.haml @@ -0,0 +1,11 @@ +%div.deployment_pretty + %h3 + = deployment.name + %ul + %li + = count_uptime(deployment.created_at) + %li + = deployment.instances.count + Instances + %p + = deployment.realm.provider.provider_type.name \ No newline at end of file diff --git a/src/app/views/deployments/_filter_view.haml b/src/app/views/deployments/_filter_view.haml new file mode 100644 index 0000000..33d25d6 --- /dev/null +++ b/src/app/views/deployments/_filter_view.haml @@ -0,0 +1,15 @@ +%table + -# FIXME: sortable_table_header won't actually work as-is since it sorts on Pools, not Deployments... + = sortable_table_header(@deployments_header) + - deployments.each do |deployment| + %tr + %td + = deployment.name + %td + = deployment.deployable.name + %td + = count_uptime(deployment.created_at) + %td + = deployment.instances.count + %td + = deployment.provider.name \ No newline at end of file diff --git a/src/app/views/deployments/_pretty_view.haml b/src/app/views/deployments/_pretty_view.haml new file mode 100644 index 0000000..5721367 --- /dev/null +++ b/src/app/views/deployments/_pretty_view.haml @@ -0,0 +1 @@ += render :partial => deployments \ No newline at end of file diff --git a/src/app/views/pools/_statistics.haml b/src/app/views/pools/_statistics.haml new file mode 100644 index 0000000..1d37026 --- /dev/null +++ b/src/app/views/pools/_statistics.haml @@ -0,0 +1,21 @@ +%h1 + = @pool.name + Pool + += link_to 'New Deployment', launch_new_deployments_path, :class => 'button', :id => 'new_deployment_button' += link_to 'Edit', edit_pool_path(@pool), :class => 'button', :id => 'edit_pool_button' +- form_tag do + = hidden_field(@pool, :id) + = restful_submit_tag('Delete', 'destroy', pool_url(@pool), 'DELETE') + +%div.statistics + Cloud Providers + = @statistics[:cloud_providers] +%div.statistics + Deployments + = @statistics[:deployments] +%div.instances + = @statistics[:instances_deployed] + = @statistics[:instances_pending] + = @statistics[:instances_failed] +-# TODO: Implement alerts, updates, and quota overview diff --git a/src/app/views/pools/edit.haml b/src/app/views/pools/edit.haml index d4c511f..94e486f 100644 --- a/src/app/views/pools/edit.haml +++ b/src/app/views/pools/edit.haml @@ -3,7 +3,7 @@ Edit pool = @pool.name
-- form_for [:resources, @pool] do |form| +- form_for @pool do |form| %fieldset = form.label :name, "Name:", :class => "grid_2 alpha" = form.text_field :name diff --git a/src/app/views/pools/show.haml b/src/app/views/pools/show.haml index 05eeedd..c411511 100644 --- a/src/app/views/pools/show.haml +++ b/src/app/views/pools/show.haml @@ -1,5 +1,7 @@ -- content_for :list do - = render :partial => 'list' += render :partial => 'statistics'
-- content_for :details do - = render :partial => 'layouts/details_pane' +-# TODO - Alerts aren't implemented just yet +-#= render :partial => 'alerts' + +-# TODO: %w(Deployments History Properties Permissions) links/tabs, plus filter links/icons, go here += render :partial => @view, :locals => {:deployments => @pool.deployments}
Hi Matt, some minor notes inline, but overall this looks good.
On 05/17/2011 12:05 AM, Matt Wagner wrote:
Implements https://www.aeolusproject.org/redmine/issues/1529
src/app/controllers/pools_controller.rb | 23 ++++++++++++----------- src/app/models/deployment.rb | 3 +++ src/app/models/instance.rb | 9 ++++++++- src/app/models/pool.rb | 16 ++++++++++++++++ src/app/views/deployments/_deployment.haml | 11 +++++++++++ src/app/views/deployments/_filter_view.haml | 15 +++++++++++++++ src/app/views/deployments/_pretty_view.haml | 1 + src/app/views/pools/_statistics.haml | 21 +++++++++++++++++++++ src/app/views/pools/edit.haml | 2 +- src/app/views/pools/show.haml | 10 ++++++---- 10 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 src/app/views/deployments/_deployment.haml create mode 100644 src/app/views/deployments/_filter_view.haml create mode 100644 src/app/views/deployments/_pretty_view.haml create mode 100644 src/app/views/pools/_statistics.haml
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 1402cca..93af54e 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -3,6 +3,7 @@ class PoolsController< ApplicationController before_filter :set_params_and_header, :only => [:index, :show] before_filter :load_pools, :only => [:show] layout 'application'
- helper DeploymentsHelper
It's better to move uptime helper method into application_helper, this method is general and will probably used on other places.
def index @search_term = params[:q]
@@ -20,18 +21,11 @@ class PoolsController< ApplicationController def show @pool = Pool.find(params[:id]) require_privilege(Privilege::VIEW, @pool)
- @url_params = params.clone
- load_instances
- @tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions']
- @details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
- @statistics = @pool.statistics
- @view = params[:view] == 'filter' ? 'deployments/filter_view' : 'deployments/pretty_view' respond_to do |format|
format.js do
if @url_params.delete :details_pane
render :partial => 'layouts/details_pane' and return
end
render :partial => @details_tab and return
end
format.html { render :action => 'show'}
format.js { render :partial => @view, :locals => {:deployments => @pool.deployments} }
endformat.html { render :action => :show} format.json { render :json => @pool } end
@@ -165,6 +159,13 @@ class PoolsController< ApplicationController { :name => "Pool Family", :sort_attr => "pool_families.name" }, { :name => "Enabled", :sort_attr => :enabled } ]
@deployments_header = [
{ :name => "Deployment Name", :sort_attr => :name },
{ :name => "Base Deployable", :sort_attr => 'deployable.name' },
{ :name => "Uptime", :sort_attr => :created_at },
{ :name => "Instances", :sort_attr => 'instances.count' },
{ :name => "Provider", :sort_attr => :provider }
] end
def load_pools
diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb index 9f382c0..11e2b97 100644 --- a/src/app/models/deployment.rb +++ b/src/app/models/deployment.rb @@ -55,6 +55,9 @@ class Deployment< ActiveRecord::Base :order => "permissions.id ASC" belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" after_create "assign_owner_roles(owner)"
- # TODO - Strictly, this should be a belongs_to, but :through seems to only work one-way,
- # and we don't much care about the inverse here.
- has_one :provider, :through => :realm
This is OK, but realm association is not being set yet, deployment.realm must be set in dbomatic but it's not implemented yet.
validates_presence_of :pool_id validates_presence_of :deployable_id
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index ef38263..4d1c5c6 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -117,6 +117,13 @@ class Instance< ActiveRecord::Base STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED, STATE_ERROR]
named_scope :deployed, :conditions => { :state => [STATE_RUNNING, STATE_SHUTTING_DOWN] }
# FIXME: "pending" is misleading as it doesn't just cover STATE_PENDING
named_scope :pending, :conditions => { :state => [STATE_NEW, STATE_PENDING] }
# FIXME: "failed" is misleading too...
named_scope :failed, :conditions => { :state => [STATE_CREATE_FAILED, STATE_ERROR] }
SEARCHABLE_COLUMNS = %w(name state)
validates_inclusion_of :state,
@@ -261,7 +268,7 @@ class Instance< ActiveRecord::Base }
instances = []
- pools = Pool.list_for_user(user, Privilege::VIEW, Instance)
- pools = Pool.list_for_user(user, Privilege::VIEW, :target_type => Instance) pools.each{|pool| pool.instances.each {|i| instances<< i}} instances.each do |i| if i.state == Instance::STATE_RUNNING
diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 87f5c19..6a28794 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -60,6 +60,8 @@ class Pool< ActiveRecord::Base :include => [:role], :order => "permissions.id ASC"
has_many :deployments, :through => :instances
before_destroy :destroyable?
def cloud_accounts
@@ -75,4 +77,18 @@ class Pool< ActiveRecord::Base instances.all? {|i| i.destroyable? } end
- # TODO: Implement Alerts, Updates, and Quotas
- def statistics
- # TODO - Need to set up cache invalidation before this is safe
- #Rails.cache.fetch("pool-#{id}-statistics") do
{
:cloud_providers => instances.collect{|i| i.provider_account}.uniq.count,
:deployments => deployments.count,
:instances_deployed => instances.deployed.count,
:instances_pending => instances.pending.count,
:instances_failed => instances.failed.count
}
- #end
- end
- end
diff --git a/src/app/views/deployments/_deployment.haml b/src/app/views/deployments/_deployment.haml new file mode 100644 index 0000000..669bbce --- /dev/null +++ b/src/app/views/deployments/_deployment.haml @@ -0,0 +1,11 @@ +%div.deployment_pretty
- %h3
- = deployment.name
- %ul
- %li
= count_uptime(deployment.created_at)
- %li
= deployment.instances.count
Instances
- %p
- = deployment.realm.provider.provider_type.name
deployment.realm can be nil (not implemented yet, but even if implemented the realm will be nil until at least one instance of a deployment is updated). I guess deployment.provider should be used here as you added association deployment->provider :through => realm into model.
\ No newline at end of file diff --git a/src/app/views/deployments/_filter_view.haml b/src/app/views/deployments/_filter_view.haml new file mode 100644 index 0000000..33d25d6 --- /dev/null +++ b/src/app/views/deployments/_filter_view.haml @@ -0,0 +1,15 @@ +%table
- -# FIXME: sortable_table_header won't actually work as-is since it sorts on Pools, not Deployments...
- = sortable_table_header(@deployments_header)
- deployments.each do |deployment|
- %tr
%td
= deployment.name
I would add checkbox box here too as before
%td
= deployment.deployable.name
%td
= count_uptime(deployment.created_at)
%td
= deployment.instances.count
%td
= deployment.provider.name
provider can be nil (if realm is nil)
\ No newline at end of file diff --git a/src/app/views/deployments/_pretty_view.haml b/src/app/views/deployments/_pretty_view.haml new file mode 100644 index 0000000..5721367 --- /dev/null +++ b/src/app/views/deployments/_pretty_view.haml @@ -0,0 +1 @@ += render :partial => deployments \ No newline at end of file diff --git a/src/app/views/pools/_statistics.haml b/src/app/views/pools/_statistics.haml new file mode 100644 index 0000000..1d37026 --- /dev/null +++ b/src/app/views/pools/_statistics.haml @@ -0,0 +1,21 @@ +%h1
- = @pool.name
- Pool
+= link_to 'New Deployment', launch_new_deployments_path, :class => 'button', :id => 'new_deployment_button' += link_to 'Edit', edit_pool_path(@pool), :class => 'button', :id => 'edit_pool_button' +- form_tag do
- = hidden_field(@pool, :id)
- = restful_submit_tag('Delete', 'destroy', pool_url(@pool), 'DELETE')
+%div.statistics
- Cloud Providers
- = @statistics[:cloud_providers]
+%div.statistics
- Deployments
- = @statistics[:deployments]
+%div.instances
- = @statistics[:instances_deployed]
- = @statistics[:instances_pending]
- = @statistics[:instances_failed]
+-# TODO: Implement alerts, updates, and quota overview diff --git a/src/app/views/pools/edit.haml b/src/app/views/pools/edit.haml index d4c511f..94e486f 100644 --- a/src/app/views/pools/edit.haml +++ b/src/app/views/pools/edit.haml @@ -3,7 +3,7 @@ Edit pool = @pool.name
-- form_for [:resources, @pool] do |form| +- form_for @pool do |form| %fieldset = form.label :name, "Name:", :class => "grid_2 alpha" = form.text_field :name diff --git a/src/app/views/pools/show.haml b/src/app/views/pools/show.haml index 05eeedd..c411511 100644 --- a/src/app/views/pools/show.haml +++ b/src/app/views/pools/show.haml @@ -1,5 +1,7 @@ -- content_for :list do
- = render :partial => 'list'
+= render :partial => 'statistics'
-- content_for :details do
- = render :partial => 'layouts/details_pane'
+-# TODO - Alerts aren't implemented just yet +-#= render :partial => 'alerts'
+-# TODO: %w(Deployments History Properties Permissions) links/tabs, plus filter links/icons, go here
For now, jquery tabs plugin can be used as we used it till now.
+= render :partial => @view, :locals => {:deployments => @pool.deployments}
We should also keep writing tests/update existing, I know this is pretty difficult at this point as new layout switch broke some tests and links. I'm going to send patch which enables links to other sections (design, administration) in new layout so it should be possible to have most cuke tests green.
On 05/17/2011 12:05 AM, Matt Wagner wrote:
Hi all,
I'm attaching a patch for #1529, getting PoolsController#show to work with the new UI. I haven't applied the Wonder Twins' styling; my understanding is that this will be done as a separate step. Please let me know if this is incorrect and I'm submitting something hideously ugly that's not supposed to be.
this is correct
I also have some scattered musings/questions about this below:
- There are a few components I haven't implemented because I don't
believe they're ready / in scope yet. Namely, the "Alerts" section of the page and the Deployments / History / Properties / Permission line, including the buttons to the right of those tabs.
I wouldn't bother with Alerts - we have nothing to show in this section yet. About tabs - I suggest to use jquery tabs as we do it now, this doesn't cost any extra work so nevermind if it's dropped in final design.
- Is there an existing implementation of switching between 'filter'
and 'pretty' views? I suspect that multiple tasks are going to involve doing this, and want to make sure I'm not reinventing the wheel.
Not yet, but we can start with something very simple in application controller and extend later when viewstate is in:
def pretty_view? params[:view] and params[:view] == 'pretty' end
- I added a "statistics" method to pools, returning the data required
for the partial at top. (Except for Alerts, Updates, and Quota, which I don't believe are ready to be implemented.) You'll note that I have it in a commented-out Rails.cache.fetch block. If uncommented, it'll store the result in local memory. (We don't need to pull in memcache this way.) It's commented out right now because it'll take some work to make sure we invalidate it properly, and I wanted someone else to sanity-check this idea before I implemented it. The Rails logs indicate that the queries for this section takes about 25ms; this isn't a crazy amount of time, but I suspect these sections will start to add up.
OK, sounds reasonable. Though I wouldn't spend time with caching in this iteration - we can do optimizations later.
- A few sections seem to imply that we care about the state/status of
a deployment, but the code has no such concept just yet. Instances have a state, but their deployments do not. Retrieving it through the association implies that we cannot (easily, at least) sort or filter on deployment state. It's also unclear to me what the state of a deployment would be if it had multiple instances in different states. Has someone already figured this out?
- You may note some deep associations being used, like
"deployment.realm.provider.provider_type.name". I tried to add a few associations where they made sense, but it wouldn't hurt for someone to give a little extra scrutiny to make sure I didn't do anything too foolish.
- deployment-provider through realm should work (once it's implemented in dbomatic) but provider can be nil - don't forget to add 'uniq' option to pool-deployments through instances association as there can be multiple instances in a deployment
-- Matt
Jan
This is a resend from the other day, fixing the issues Jan identified as well as a few other issues. It's also rebased against the latest state of newui.
I did not implement jQuery tabs just yet, since we only have content for the main 'Deployments' section right now.
I added a few additional tests, though the section has pretty good coverage.
Implements https://www.aeolusproject.org/redmine/issues/1529 --- src/app/controllers/pools_controller.rb | 23 +++++++++++------------ src/app/helpers/application_helper.rb | 17 +++++++++++++++++ src/app/helpers/deployments_helper.rb | 16 ---------------- src/app/models/deployment.rb | 3 +++ src/app/models/instance.rb | 9 ++++++++- src/app/models/pool.rb | 16 ++++++++++++++++ src/app/views/deployments/_deployment.haml | 11 +++++++++++ src/app/views/deployments/_filter_view.haml | 18 ++++++++++++++++++ src/app/views/deployments/_pretty_view.haml | 1 + src/app/views/pools/_statistics.haml | 21 +++++++++++++++++++++ src/app/views/pools/edit.haml | 2 +- src/app/views/pools/show.haml | 10 ++++++---- src/features/pool.feature | 12 ++++++++++-- src/features/step_definitions/pool_steps.rb | 8 ++++++++ src/features/support/paths.rb | 4 ++++ 15 files changed, 135 insertions(+), 36 deletions(-) create mode 100644 src/app/views/deployments/_deployment.haml create mode 100644 src/app/views/deployments/_filter_view.haml create mode 100644 src/app/views/deployments/_pretty_view.haml create mode 100644 src/app/views/pools/_statistics.haml
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 18688c7..a42e162 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -23,20 +23,12 @@ class PoolsController < ApplicationController def show @pool = Pool.find(params[:id]) require_privilege(Privilege::VIEW, @pool) - @url_params = params.clone - load_instances - @tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions'] - @details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab] save_breadcrumb(pool_path(@pool), @pool.name) + @statistics = @pool.statistics + @view = params[:view] == 'filter' ? 'deployments/filter_view' : 'deployments/pretty_view' respond_to do |format| - # TODO - With the new UI, the logic here will probably need to be updated - format.js do - if @url_params.delete :details_pane - render :partial => 'layouts/details_pane' and return - end - render :partial => @details_tab and return - end - format.html { render :action => 'show'} + format.js { render :partial => @view, :locals => {:deployments => @pool.deployments} } + format.html { render :action => :show} format.json { render :json => @pool } end end @@ -182,6 +174,13 @@ class PoolsController < ApplicationController { :name => "Pool Family", :sort_attr => "pool_families.name" }, { :name => "Enabled", :sort_attr => :enabled } ] + @deployments_header = [ + { :name => "Deployment Name", :sort_attr => :name }, + { :name => "Base Deployable", :sort_attr => 'deployable.name' }, + { :name => "Uptime", :sort_attr => :created_at }, + { :name => "Instances", :sort_attr => 'instances.count' }, + { :name => "Provider", :sort_attr => :provider } + ] end
def load_pools diff --git a/src/app/helpers/application_helper.rb b/src/app/helpers/application_helper.rb index c536a81..9499a35 100644 --- a/src/app/helpers/application_helper.rb +++ b/src/app/helpers/application_helper.rb @@ -194,4 +194,21 @@ module ApplicationHelper title.split(' ').join('_').downcase end
+ def count_uptime(start_time) + result_string = [] + difference = Time.now.utc - start_time + + seconds = difference % 60 + difference = (difference - seconds) / 60 + minutes = difference % 60 + difference = (difference - minutes) / 60 + hours = difference % 24 + difference = (difference - hours) / 24 + days = difference % 7 + + result_string<< pluralize(days.to_i, 'day') if days != 0 + result_string<<"#{"%02d"%hours.to_i}:#{"%02d"%minutes.to_i}:#{"%02d"%seconds.to_i}" + result_string.join(", ") + end + end diff --git a/src/app/helpers/deployments_helper.rb b/src/app/helpers/deployments_helper.rb index 620ea01..790ed45 100644 --- a/src/app/helpers/deployments_helper.rb +++ b/src/app/helpers/deployments_helper.rb @@ -1,18 +1,2 @@ module DeploymentsHelper - def count_uptime(start_time) - result_string = [] - difference = Time.now.utc - start_time - - seconds = difference % 60 - difference = (difference - seconds) / 60 - minutes = difference % 60 - difference = (difference - minutes) / 60 - hours = difference % 24 - difference = (difference - hours) / 24 - days = difference % 7 - - result_string<< pluralize(days.to_i, 'day') if days != 0 - result_string<<"#{"%02d"%hours.to_i}:#{"%02d"%minutes.to_i}:#{"%02d"%seconds.to_i}" - result_string.join(", ") - end end diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb index 9f382c0..11e2b97 100644 --- a/src/app/models/deployment.rb +++ b/src/app/models/deployment.rb @@ -55,6 +55,9 @@ class Deployment < ActiveRecord::Base :order => "permissions.id ASC" belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" after_create "assign_owner_roles(owner)" + # TODO - Strictly, this should be a belongs_to, but :through seems to only work one-way, + # and we don't much care about the inverse here. + has_one :provider, :through => :realm
validates_presence_of :pool_id validates_presence_of :deployable_id diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index ef38263..4d1c5c6 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -117,6 +117,13 @@ class Instance < ActiveRecord::Base STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED, STATE_ERROR]
+ named_scope :deployed, :conditions => { :state => [STATE_RUNNING, STATE_SHUTTING_DOWN] } + # FIXME: "pending" is misleading as it doesn't just cover STATE_PENDING + named_scope :pending, :conditions => { :state => [STATE_NEW, STATE_PENDING] } + # FIXME: "failed" is misleading too... + named_scope :failed, :conditions => { :state => [STATE_CREATE_FAILED, STATE_ERROR] } + + SEARCHABLE_COLUMNS = %w(name state)
validates_inclusion_of :state, @@ -261,7 +268,7 @@ class Instance < ActiveRecord::Base }
instances = [] - pools = Pool.list_for_user(user, Privilege::VIEW, Instance) + pools = Pool.list_for_user(user, Privilege::VIEW, :target_type => Instance) pools.each{|pool| pool.instances.each {|i| instances << i}} instances.each do |i| if i.state == Instance::STATE_RUNNING diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index 87f5c19..6209281 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -60,6 +60,8 @@ class Pool < ActiveRecord::Base :include => [:role], :order => "permissions.id ASC"
+ has_many :deployments + before_destroy :destroyable?
def cloud_accounts @@ -75,4 +77,18 @@ class Pool < ActiveRecord::Base instances.all? {|i| i.destroyable? } end
+ # TODO: Implement Alerts, Updates, and Quotas + def statistics + # TODO - Need to set up cache invalidation before this is safe + #Rails.cache.fetch("pool-#{id}-statistics") do + { + :cloud_providers => instances.collect{|i| i.provider_account}.uniq.count, + :deployments => deployments.count, + :instances_deployed => instances.deployed.count, + :instances_pending => instances.pending.count, + :instances_failed => instances.failed.count + } + #end + end + end diff --git a/src/app/views/deployments/_deployment.haml b/src/app/views/deployments/_deployment.haml new file mode 100644 index 0000000..f07cc00 --- /dev/null +++ b/src/app/views/deployments/_deployment.haml @@ -0,0 +1,11 @@ +%div.deployment_pretty + %h3 + = deployment.name + %ul + %li + = count_uptime(deployment.created_at) + %li + = deployment.instances.count + Instances + %p + = deployment.provider.provider_type.name if deployment.provider \ No newline at end of file diff --git a/src/app/views/deployments/_filter_view.haml b/src/app/views/deployments/_filter_view.haml new file mode 100644 index 0000000..ad3f1b2 --- /dev/null +++ b/src/app/views/deployments/_filter_view.haml @@ -0,0 +1,18 @@ +- form_tag do + %table + -# FIXME: sortable_table_header won't actually work as-is since it sorts on Pools, not Deployments... + -# TODO: There are no defined actions for the checkboxes yet; they'll go here + = sortable_table_header(@deployments_header) + - deployments.each do |deployment| + %tr + %td + %input{:name => "deployment_selected[]", :type => "checkbox", :value => deployment.id, :id => "deployment_checkbox_#{deployment.id}" } + = deployment.name + %td + = deployment.deployable.name + %td + = count_uptime(deployment.created_at) + %td + = deployment.instances.count + %td + = deployment.provider.provider_type.name if deployment.provider \ No newline at end of file diff --git a/src/app/views/deployments/_pretty_view.haml b/src/app/views/deployments/_pretty_view.haml new file mode 100644 index 0000000..5721367 --- /dev/null +++ b/src/app/views/deployments/_pretty_view.haml @@ -0,0 +1 @@ += render :partial => deployments \ No newline at end of file diff --git a/src/app/views/pools/_statistics.haml b/src/app/views/pools/_statistics.haml new file mode 100644 index 0000000..1d37026 --- /dev/null +++ b/src/app/views/pools/_statistics.haml @@ -0,0 +1,21 @@ +%h1 + = @pool.name + Pool + += link_to 'New Deployment', launch_new_deployments_path, :class => 'button', :id => 'new_deployment_button' += link_to 'Edit', edit_pool_path(@pool), :class => 'button', :id => 'edit_pool_button' +- form_tag do + = hidden_field(@pool, :id) + = restful_submit_tag('Delete', 'destroy', pool_url(@pool), 'DELETE') + +%div.statistics + Cloud Providers + = @statistics[:cloud_providers] +%div.statistics + Deployments + = @statistics[:deployments] +%div.instances + = @statistics[:instances_deployed] + = @statistics[:instances_pending] + = @statistics[:instances_failed] +-# TODO: Implement alerts, updates, and quota overview diff --git a/src/app/views/pools/edit.haml b/src/app/views/pools/edit.haml index ea8dd88..8e2be85 100644 --- a/src/app/views/pools/edit.haml +++ b/src/app/views/pools/edit.haml @@ -1 +1 @@ -= render :partial => 'edit' \ No newline at end of file += render :partial => 'edit' diff --git a/src/app/views/pools/show.haml b/src/app/views/pools/show.haml index 05eeedd..c411511 100644 --- a/src/app/views/pools/show.haml +++ b/src/app/views/pools/show.haml @@ -1,5 +1,7 @@ -- content_for :list do - = render :partial => 'list' += render :partial => 'statistics'
-- content_for :details do - = render :partial => 'layouts/details_pane' +-# TODO - Alerts aren't implemented just yet +-#= render :partial => 'alerts' + +-# TODO: %w(Deployments History Properties Permissions) links/tabs, plus filter links/icons, go here += render :partial => @view, :locals => {:deployments => @pool.deployments} diff --git a/src/features/pool.feature b/src/features/pool.feature index c650008..a48053d 100644 --- a/src/features/pool.feature +++ b/src/features/pool.feature @@ -132,11 +132,19 @@ Feature: Manage Pools Then I should see pool "mockpool" in JSON format
Scenario: View a pool over XHR - Given a pool "mockpool" exists + Given a pool "mockpool42" exists with deployment "mockdeployment" And I request XHR When I am viewing the pool "mockpool" Then I should get back a partial - And I should see "mockpool" + And I should see "mockdeployment" + + Scenario: View a pool in filter view over XHR + Given a pool "mockpool42" exists with deployment "mockdeployment" + And I request XHR + When I go to the "mockpool42" pool filter view page + Then I should get back a partial + And I should see "Deployment Name" + And I should see "mockdeployment"
Scenario: Create a pool and get JSON response Given I accept JSON diff --git a/src/features/step_definitions/pool_steps.rb b/src/features/step_definitions/pool_steps.rb index 11db612..91d8a6a 100644 --- a/src/features/step_definitions/pool_steps.rb +++ b/src/features/step_definitions/pool_steps.rb @@ -22,6 +22,14 @@ Given /^a pool "([^"]*)" exists$/ do |pool_name| Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota) end
+Given /^a pool "([^"]*)" exists with deployment "([^"]*)"$/ do |pool_name, deployment_name| + pool_family = PoolFamily.find_by_name('default') || Factory(:pool_family) + quota = Factory(:quota) + pool = Pool.find_by_name(pool_name) || Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota) + deployable = Deployable.create!(:name => 'deployable1', :owner => User.first) + Deployment.create!(:name => deployment_name, :pool => pool, :deployable => deployable, :owner => User.first) +end + Then /^I should have a pool named "([^"]*)"$/ do |name| Pool.find_by_name(name).should_not be_nil end diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb index 6718403..b6ee8d5 100644 --- a/src/features/support/paths.rb +++ b/src/features/support/paths.rb @@ -134,6 +134,10 @@ module NavigationHelpers when /^(.*)'s deployment page$/ deployment_path(Deployment.find_by_name($1))
+ when /^the "(.*)" pool filter view page$/ + pool = Pool.find_by_name($1) + pool_path(pool, :view => 'filter') + # Add more mappings here. # Here is an example that pulls values out of the Regexp: #
ACK, sending rebased version to current newui
From: Matt Wagner matt.wagner@redhat.com
Implements https://www.aeolusproject.org/redmine/issues/1529 --- src/app/controllers/pools_controller.rb | 23 +++++++++++------------ src/app/models/deployment.rb | 3 +++ src/app/models/instance.rb | 9 ++++++++- src/app/models/pool.rb | 16 ++++++++++++++++ src/app/views/deployments/_deployment.haml | 11 +++++++++++ src/app/views/deployments/_filter_view.haml | 18 ++++++++++++++++++ src/app/views/deployments/_pretty_view.haml | 1 + src/app/views/pools/_statistics.haml | 21 +++++++++++++++++++++ src/app/views/pools/edit.haml | 2 +- src/app/views/pools/show.haml | 10 ++++++---- src/features/pool.feature | 12 ++++++++++-- src/features/step_definitions/pool_steps.rb | 8 ++++++++ src/features/support/paths.rb | 4 ++++ 13 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 src/app/views/deployments/_deployment.haml create mode 100644 src/app/views/deployments/_filter_view.haml create mode 100644 src/app/views/deployments/_pretty_view.haml create mode 100644 src/app/views/pools/_statistics.haml
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 18688c7..a42e162 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -23,20 +23,12 @@ class PoolsController < ApplicationController def show @pool = Pool.find(params[:id]) require_privilege(Privilege::VIEW, @pool) - @url_params = params.clone - load_instances - @tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions'] - @details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab] save_breadcrumb(pool_path(@pool), @pool.name) + @statistics = @pool.statistics + @view = params[:view] == 'filter' ? 'deployments/filter_view' : 'deployments/pretty_view' respond_to do |format| - # TODO - With the new UI, the logic here will probably need to be updated - format.js do - if @url_params.delete :details_pane - render :partial => 'layouts/details_pane' and return - end - render :partial => @details_tab and return - end - format.html { render :action => 'show'} + format.js { render :partial => @view, :locals => {:deployments => @pool.deployments} } + format.html { render :action => :show} format.json { render :json => @pool } end end @@ -182,6 +174,13 @@ class PoolsController < ApplicationController { :name => "Pool Family", :sort_attr => "pool_families.name" }, { :name => "Enabled", :sort_attr => :enabled } ] + @deployments_header = [ + { :name => "Deployment Name", :sort_attr => :name }, + { :name => "Base Deployable", :sort_attr => 'deployable.name' }, + { :name => "Uptime", :sort_attr => :created_at }, + { :name => "Instances", :sort_attr => 'instances.count' }, + { :name => "Provider", :sort_attr => :provider } + ] end
def load_pools diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb index 9f382c0..11e2b97 100644 --- a/src/app/models/deployment.rb +++ b/src/app/models/deployment.rb @@ -55,6 +55,9 @@ class Deployment < ActiveRecord::Base :order => "permissions.id ASC" belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" after_create "assign_owner_roles(owner)" + # TODO - Strictly, this should be a belongs_to, but :through seems to only work one-way, + # and we don't much care about the inverse here. + has_one :provider, :through => :realm
validates_presence_of :pool_id validates_presence_of :deployable_id diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index ef38263..4d1c5c6 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -117,6 +117,13 @@ class Instance < ActiveRecord::Base STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED, STATE_ERROR]
+ named_scope :deployed, :conditions => { :state => [STATE_RUNNING, STATE_SHUTTING_DOWN] } + # FIXME: "pending" is misleading as it doesn't just cover STATE_PENDING + named_scope :pending, :conditions => { :state => [STATE_NEW, STATE_PENDING] } + # FIXME: "failed" is misleading too... + named_scope :failed, :conditions => { :state => [STATE_CREATE_FAILED, STATE_ERROR] } + + SEARCHABLE_COLUMNS = %w(name state)
validates_inclusion_of :state, @@ -261,7 +268,7 @@ class Instance < ActiveRecord::Base }
instances = [] - pools = Pool.list_for_user(user, Privilege::VIEW, Instance) + pools = Pool.list_for_user(user, Privilege::VIEW, :target_type => Instance) pools.each{|pool| pool.instances.each {|i| instances << i}} instances.each do |i| if i.state == Instance::STATE_RUNNING diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index cd7e11a..866ecce 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -60,6 +60,8 @@ class Pool < ActiveRecord::Base :include => [:role], :order => "permissions.id ASC"
+ has_many :deployments + before_destroy :destroyable?
def cloud_accounts @@ -75,4 +77,18 @@ class Pool < ActiveRecord::Base instances.all? {|i| i.destroyable? } end
+ # TODO: Implement Alerts, Updates, and Quotas + def statistics + # TODO - Need to set up cache invalidation before this is safe + #Rails.cache.fetch("pool-#{id}-statistics") do + { + :cloud_providers => instances.collect{|i| i.provider_account}.uniq.count, + :deployments => deployments.count, + :instances_deployed => instances.deployed.count, + :instances_pending => instances.pending.count, + :instances_failed => instances.failed.count + } + #end + end + end diff --git a/src/app/views/deployments/_deployment.haml b/src/app/views/deployments/_deployment.haml new file mode 100644 index 0000000..f07cc00 --- /dev/null +++ b/src/app/views/deployments/_deployment.haml @@ -0,0 +1,11 @@ +%div.deployment_pretty + %h3 + = deployment.name + %ul + %li + = count_uptime(deployment.created_at) + %li + = deployment.instances.count + Instances + %p + = deployment.provider.provider_type.name if deployment.provider \ No newline at end of file diff --git a/src/app/views/deployments/_filter_view.haml b/src/app/views/deployments/_filter_view.haml new file mode 100644 index 0000000..ad3f1b2 --- /dev/null +++ b/src/app/views/deployments/_filter_view.haml @@ -0,0 +1,18 @@ +- form_tag do + %table + -# FIXME: sortable_table_header won't actually work as-is since it sorts on Pools, not Deployments... + -# TODO: There are no defined actions for the checkboxes yet; they'll go here + = sortable_table_header(@deployments_header) + - deployments.each do |deployment| + %tr + %td + %input{:name => "deployment_selected[]", :type => "checkbox", :value => deployment.id, :id => "deployment_checkbox_#{deployment.id}" } + = deployment.name + %td + = deployment.deployable.name + %td + = count_uptime(deployment.created_at) + %td + = deployment.instances.count + %td + = deployment.provider.provider_type.name if deployment.provider \ No newline at end of file diff --git a/src/app/views/deployments/_pretty_view.haml b/src/app/views/deployments/_pretty_view.haml new file mode 100644 index 0000000..5721367 --- /dev/null +++ b/src/app/views/deployments/_pretty_view.haml @@ -0,0 +1 @@ += render :partial => deployments \ No newline at end of file diff --git a/src/app/views/pools/_statistics.haml b/src/app/views/pools/_statistics.haml new file mode 100644 index 0000000..1d37026 --- /dev/null +++ b/src/app/views/pools/_statistics.haml @@ -0,0 +1,21 @@ +%h1 + = @pool.name + Pool + += link_to 'New Deployment', launch_new_deployments_path, :class => 'button', :id => 'new_deployment_button' += link_to 'Edit', edit_pool_path(@pool), :class => 'button', :id => 'edit_pool_button' +- form_tag do + = hidden_field(@pool, :id) + = restful_submit_tag('Delete', 'destroy', pool_url(@pool), 'DELETE') + +%div.statistics + Cloud Providers + = @statistics[:cloud_providers] +%div.statistics + Deployments + = @statistics[:deployments] +%div.instances + = @statistics[:instances_deployed] + = @statistics[:instances_pending] + = @statistics[:instances_failed] +-# TODO: Implement alerts, updates, and quota overview diff --git a/src/app/views/pools/edit.haml b/src/app/views/pools/edit.haml index ea8dd88..8e2be85 100644 --- a/src/app/views/pools/edit.haml +++ b/src/app/views/pools/edit.haml @@ -1 +1 @@ -= render :partial => 'edit' \ No newline at end of file += render :partial => 'edit' diff --git a/src/app/views/pools/show.haml b/src/app/views/pools/show.haml index 05eeedd..c411511 100644 --- a/src/app/views/pools/show.haml +++ b/src/app/views/pools/show.haml @@ -1,5 +1,7 @@ -- content_for :list do - = render :partial => 'list' += render :partial => 'statistics'
-- content_for :details do - = render :partial => 'layouts/details_pane' +-# TODO - Alerts aren't implemented just yet +-#= render :partial => 'alerts' + +-# TODO: %w(Deployments History Properties Permissions) links/tabs, plus filter links/icons, go here += render :partial => @view, :locals => {:deployments => @pool.deployments} diff --git a/src/features/pool.feature b/src/features/pool.feature index 29f4098..2eae7ce 100644 --- a/src/features/pool.feature +++ b/src/features/pool.feature @@ -129,11 +129,19 @@ Feature: Manage Pools Then I should see pool "mockpool" in JSON format
Scenario: View a pool over XHR - Given a pool "mockpool" exists + Given a pool "mockpool42" exists with deployment "mockdeployment" And I request XHR When I am viewing the pool "mockpool" Then I should get back a partial - And I should see "mockpool" + And I should see "mockdeployment" + + Scenario: View a pool in filter view over XHR + Given a pool "mockpool42" exists with deployment "mockdeployment" + And I request XHR + When I go to the "mockpool42" pool filter view page + Then I should get back a partial + And I should see "Deployment Name" + And I should see "mockdeployment"
Scenario: Create a pool and get JSON response Given I accept JSON diff --git a/src/features/step_definitions/pool_steps.rb b/src/features/step_definitions/pool_steps.rb index 11db612..91d8a6a 100644 --- a/src/features/step_definitions/pool_steps.rb +++ b/src/features/step_definitions/pool_steps.rb @@ -22,6 +22,14 @@ Given /^a pool "([^"]*)" exists$/ do |pool_name| Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota) end
+Given /^a pool "([^"]*)" exists with deployment "([^"]*)"$/ do |pool_name, deployment_name| + pool_family = PoolFamily.find_by_name('default') || Factory(:pool_family) + quota = Factory(:quota) + pool = Pool.find_by_name(pool_name) || Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota) + deployable = Deployable.create!(:name => 'deployable1', :owner => User.first) + Deployment.create!(:name => deployment_name, :pool => pool, :deployable => deployable, :owner => User.first) +end + Then /^I should have a pool named "([^"]*)"$/ do |name| Pool.find_by_name(name).should_not be_nil end diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb index 6718403..b6ee8d5 100644 --- a/src/features/support/paths.rb +++ b/src/features/support/paths.rb @@ -134,6 +134,10 @@ module NavigationHelpers when /^(.*)'s deployment page$/ deployment_path(Deployment.find_by_name($1))
+ when /^the "(.*)" pool filter view page$/ + pool = Pool.find_by_name($1) + pool_path(pool, :view => 'filter') + # Add more mappings here. # Here is an example that pulls values out of the Regexp: #
pushed
On 05/19/2011 12:05 PM, jtomasek@redhat.com wrote:
From: Matt Wagnermatt.wagner@redhat.com
Implements https://www.aeolusproject.org/redmine/issues/1529
src/app/controllers/pools_controller.rb | 23 +++++++++++------------ src/app/models/deployment.rb | 3 +++ src/app/models/instance.rb | 9 ++++++++- src/app/models/pool.rb | 16 ++++++++++++++++ src/app/views/deployments/_deployment.haml | 11 +++++++++++ src/app/views/deployments/_filter_view.haml | 18 ++++++++++++++++++ src/app/views/deployments/_pretty_view.haml | 1 + src/app/views/pools/_statistics.haml | 21 +++++++++++++++++++++ src/app/views/pools/edit.haml | 2 +- src/app/views/pools/show.haml | 10 ++++++---- src/features/pool.feature | 12 ++++++++++-- src/features/step_definitions/pool_steps.rb | 8 ++++++++ src/features/support/paths.rb | 4 ++++ 13 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 src/app/views/deployments/_deployment.haml create mode 100644 src/app/views/deployments/_filter_view.haml create mode 100644 src/app/views/deployments/_pretty_view.haml create mode 100644 src/app/views/pools/_statistics.haml
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 18688c7..a42e162 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -23,20 +23,12 @@ class PoolsController< ApplicationController def show @pool = Pool.find(params[:id]) require_privilege(Privilege::VIEW, @pool)
- @url_params = params.clone
- load_instances
- @tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions']
- @details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab] save_breadcrumb(pool_path(@pool), @pool.name)
- @statistics = @pool.statistics
- @view = params[:view] == 'filter' ? 'deployments/filter_view' : 'deployments/pretty_view' respond_to do |format|
# TODO - With the new UI, the logic here will probably need to be updated
format.js do
if @url_params.delete :details_pane
render :partial => 'layouts/details_pane' and return
end
render :partial => @details_tab and return
end
format.html { render :action => 'show'}
format.js { render :partial => @view, :locals => {:deployments => @pool.deployments} }
endformat.html { render :action => :show} format.json { render :json => @pool } end
@@ -182,6 +174,13 @@ class PoolsController< ApplicationController { :name => "Pool Family", :sort_attr => "pool_families.name" }, { :name => "Enabled", :sort_attr => :enabled } ]
@deployments_header = [
{ :name => "Deployment Name", :sort_attr => :name },
{ :name => "Base Deployable", :sort_attr => 'deployable.name' },
{ :name => "Uptime", :sort_attr => :created_at },
{ :name => "Instances", :sort_attr => 'instances.count' },
{ :name => "Provider", :sort_attr => :provider }
] end
def load_pools
diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb index 9f382c0..11e2b97 100644 --- a/src/app/models/deployment.rb +++ b/src/app/models/deployment.rb @@ -55,6 +55,9 @@ class Deployment< ActiveRecord::Base :order => "permissions.id ASC" belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" after_create "assign_owner_roles(owner)"
# TODO - Strictly, this should be a belongs_to, but :through seems to only work one-way,
# and we don't much care about the inverse here.
has_one :provider, :through => :realm
validates_presence_of :pool_id validates_presence_of :deployable_id
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb index ef38263..4d1c5c6 100644 --- a/src/app/models/instance.rb +++ b/src/app/models/instance.rb @@ -117,6 +117,13 @@ class Instance< ActiveRecord::Base STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED, STATE_ERROR]
named_scope :deployed, :conditions => { :state => [STATE_RUNNING, STATE_SHUTTING_DOWN] }
# FIXME: "pending" is misleading as it doesn't just cover STATE_PENDING
named_scope :pending, :conditions => { :state => [STATE_NEW, STATE_PENDING] }
# FIXME: "failed" is misleading too...
named_scope :failed, :conditions => { :state => [STATE_CREATE_FAILED, STATE_ERROR] }
SEARCHABLE_COLUMNS = %w(name state)
validates_inclusion_of :state,
@@ -261,7 +268,7 @@ class Instance< ActiveRecord::Base }
instances = []
- pools = Pool.list_for_user(user, Privilege::VIEW, Instance)
- pools = Pool.list_for_user(user, Privilege::VIEW, :target_type => Instance) pools.each{|pool| pool.instances.each {|i| instances<< i}} instances.each do |i| if i.state == Instance::STATE_RUNNING
diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index cd7e11a..866ecce 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -60,6 +60,8 @@ class Pool< ActiveRecord::Base :include => [:role], :order => "permissions.id ASC"
has_many :deployments
before_destroy :destroyable?
def cloud_accounts
@@ -75,4 +77,18 @@ class Pool< ActiveRecord::Base instances.all? {|i| i.destroyable? } end
- # TODO: Implement Alerts, Updates, and Quotas
- def statistics
- # TODO - Need to set up cache invalidation before this is safe
- #Rails.cache.fetch("pool-#{id}-statistics") do
{
:cloud_providers => instances.collect{|i| i.provider_account}.uniq.count,
:deployments => deployments.count,
:instances_deployed => instances.deployed.count,
:instances_pending => instances.pending.count,
:instances_failed => instances.failed.count
}
- #end
- end
- end
diff --git a/src/app/views/deployments/_deployment.haml b/src/app/views/deployments/_deployment.haml new file mode 100644 index 0000000..f07cc00 --- /dev/null +++ b/src/app/views/deployments/_deployment.haml @@ -0,0 +1,11 @@ +%div.deployment_pretty
- %h3
- = deployment.name
- %ul
- %li
= count_uptime(deployment.created_at)
- %li
= deployment.instances.count
Instances
- %p
- = deployment.provider.provider_type.name if deployment.provider
\ No newline at end of file diff --git a/src/app/views/deployments/_filter_view.haml b/src/app/views/deployments/_filter_view.haml new file mode 100644 index 0000000..ad3f1b2 --- /dev/null +++ b/src/app/views/deployments/_filter_view.haml @@ -0,0 +1,18 @@ +- form_tag do
- %table
- -# FIXME: sortable_table_header won't actually work as-is since it sorts on Pools, not Deployments...
- -# TODO: There are no defined actions for the checkboxes yet; they'll go here
- = sortable_table_header(@deployments_header)
- deployments.each do |deployment|
%tr
%td
%input{:name => "deployment_selected[]", :type => "checkbox", :value => deployment.id, :id => "deployment_checkbox_#{deployment.id}" }
= deployment.name
%td
= deployment.deployable.name
%td
= count_uptime(deployment.created_at)
%td
= deployment.instances.count
%td
= deployment.provider.provider_type.name if deployment.provider
\ No newline at end of file diff --git a/src/app/views/deployments/_pretty_view.haml b/src/app/views/deployments/_pretty_view.haml new file mode 100644 index 0000000..5721367 --- /dev/null +++ b/src/app/views/deployments/_pretty_view.haml @@ -0,0 +1 @@ += render :partial => deployments \ No newline at end of file diff --git a/src/app/views/pools/_statistics.haml b/src/app/views/pools/_statistics.haml new file mode 100644 index 0000000..1d37026 --- /dev/null +++ b/src/app/views/pools/_statistics.haml @@ -0,0 +1,21 @@ +%h1
- = @pool.name
- Pool
+= link_to 'New Deployment', launch_new_deployments_path, :class => 'button', :id => 'new_deployment_button' += link_to 'Edit', edit_pool_path(@pool), :class => 'button', :id => 'edit_pool_button' +- form_tag do
- = hidden_field(@pool, :id)
- = restful_submit_tag('Delete', 'destroy', pool_url(@pool), 'DELETE')
+%div.statistics
- Cloud Providers
- = @statistics[:cloud_providers]
+%div.statistics
- Deployments
- = @statistics[:deployments]
+%div.instances
- = @statistics[:instances_deployed]
- = @statistics[:instances_pending]
- = @statistics[:instances_failed]
+-# TODO: Implement alerts, updates, and quota overview diff --git a/src/app/views/pools/edit.haml b/src/app/views/pools/edit.haml index ea8dd88..8e2be85 100644 --- a/src/app/views/pools/edit.haml +++ b/src/app/views/pools/edit.haml @@ -1 +1 @@ -= render :partial => 'edit' \ No newline at end of file += render :partial => 'edit' diff --git a/src/app/views/pools/show.haml b/src/app/views/pools/show.haml index 05eeedd..c411511 100644 --- a/src/app/views/pools/show.haml +++ b/src/app/views/pools/show.haml @@ -1,5 +1,7 @@ -- content_for :list do
- = render :partial => 'list'
+= render :partial => 'statistics'
-- content_for :details do
- = render :partial => 'layouts/details_pane'
+-# TODO - Alerts aren't implemented just yet +-#= render :partial => 'alerts'
+-# TODO: %w(Deployments History Properties Permissions) links/tabs, plus filter links/icons, go here += render :partial => @view, :locals => {:deployments => @pool.deployments} diff --git a/src/features/pool.feature b/src/features/pool.feature index 29f4098..2eae7ce 100644 --- a/src/features/pool.feature +++ b/src/features/pool.feature @@ -129,11 +129,19 @@ Feature: Manage Pools Then I should see pool "mockpool" in JSON format
Scenario: View a pool over XHR
- Given a pool "mockpool" exists
- Given a pool "mockpool42" exists with deployment "mockdeployment" And I request XHR When I am viewing the pool "mockpool" Then I should get back a partial
- And I should see "mockpool"
And I should see "mockdeployment"
Scenario: View a pool in filter view over XHR
Given a pool "mockpool42" exists with deployment "mockdeployment"
And I request XHR
When I go to the "mockpool42" pool filter view page
Then I should get back a partial
And I should see "Deployment Name"
And I should see "mockdeployment"
Scenario: Create a pool and get JSON response Given I accept JSON
diff --git a/src/features/step_definitions/pool_steps.rb b/src/features/step_definitions/pool_steps.rb index 11db612..91d8a6a 100644 --- a/src/features/step_definitions/pool_steps.rb +++ b/src/features/step_definitions/pool_steps.rb @@ -22,6 +22,14 @@ Given /^a pool "([^"]*)" exists$/ do |pool_name| Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota) end
+Given /^a pool "([^"]*)" exists with deployment "([^"]*)"$/ do |pool_name, deployment_name|
- pool_family = PoolFamily.find_by_name('default') || Factory(:pool_family)
- quota = Factory(:quota)
- pool = Pool.find_by_name(pool_name) || Pool.create!(:name => pool_name, :pool_family => pool_family, :quota => quota)
- deployable = Deployable.create!(:name => 'deployable1', :owner => User.first)
- Deployment.create!(:name => deployment_name, :pool => pool, :deployable => deployable, :owner => User.first)
+end
- Then /^I should have a pool named "([^"]*)"$/ do |name| Pool.find_by_name(name).should_not be_nil end
diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb index 6718403..b6ee8d5 100644 --- a/src/features/support/paths.rb +++ b/src/features/support/paths.rb @@ -134,6 +134,10 @@ module NavigationHelpers when /^(.*)'s deployment page$/ deployment_path(Deployment.find_by_name($1))
- when /^the "(.*)" pool filter view page$/
pool = Pool.find_by_name($1)
pool_path(pool, :view => 'filter')
# Add more mappings here. # Here is an example that pulls values out of the Regexp: #
aeolus-devel@lists.fedorahosted.org