[PATCH 1/2] RM3509 re-establish providers/ index page, with useful statistics and graphs

Tzu-Mainn Chen tzumainn at redhat.com
Thu Jul 19 17:30:31 UTC 2012


---
 src/app/controllers/providers_controller.rb |  201 ++++++++++++++++++++++++---
 src/app/views/providers/index.html.haml     |   73 +++++++++-
 src/config/locales/en.yml                   |    5 +
 src/config/routes.rb                        |    1 +
 src/features/provider.feature               |   11 --
 5 files changed, 258 insertions(+), 33 deletions(-)

diff --git a/src/app/controllers/providers_controller.rb b/src/app/controllers/providers_controller.rb
index 81ac69f..5142997 100644
--- a/src/app/controllers/providers_controller.rb
+++ b/src/app/controllers/providers_controller.rb
@@ -21,27 +21,28 @@ class ProvidersController < ApplicationController
   before_filter :parse_provider_type, :only => [:create, :update]
 
   def index
-    @params = params
-    begin
-      @provider = Provider.find(session[:current_provider_id]) if session[:current_provider_id]
-    rescue ActiveRecord::RecordNotFound => exc
-      logger.error(exc.message)
-    ensure
-      @provider ||= @providers.first
-    end
+    @from_date = params[:from_date].nil? ? Date.today - 7.days :
+      Date.civil(params[:from_date][:year].to_i,
+                 params[:from_date][:month].to_i,
+                 params[:from_date][:day].to_i)
+    @to_date = params[:to_date].nil? ? Date.today :
+      Date.civil(params[:to_date][:year].to_i,
+                 params[:to_date][:month].to_i,
+                 params[:to_date][:day].to_i)
+
+    load_headers
+    statistics
 
     respond_to do |format|
-      format.html do
-        if @providers.present?
-          flash.keep
-          redirect_to edit_provider_path(@provider)
-        else
-          render :action => :index
-        end
-      end
+      format.html
+      format.js { render :partial => 'list' }
       format.xml { render :partial => 'list.xml' }
     end
+  end
 
+  def filter
+    redirect_to_original({ "from_date" => params[:from_date],
+                           "to_date" => params[:to_date] })
   end
 
   def new
@@ -221,8 +222,8 @@ class ProvidersController < ApplicationController
   end
 
   def load_providers
-    @providers = Provider.list_for_user(current_session, current_user,
-                                        Privilege::VIEW)
+    @providers = Provider.includes(:provider_type).list_for_user(current_session, current_user,
+                                        Privilege::VIEW).order("name")
   end
 
   def disable_provider
@@ -322,4 +323,168 @@ class ProvidersController < ApplicationController
 
     @view = @details_tab[:view]
   end
+
+  def load_headers
+    @header = [
+      { :name => t('providers.index.provider_name'), :sortable => false },
+      { :name => t('providers.index.provider_type'), :sortable => false },
+      { :name => t('providers.index.running_instances'), :sortable => false },
+      { :name => t('providers.index.pending_instances'), :sortable => false },
+      { :name => t('providers.index.error_instances'), :sortable => false },
+      { :name => t('providers.index.historical_running_instances'), :sortable => false },
+      { :name => t('providers.index.historical_error_instances'), :sortable => false },
+    ]
+  end
+
+  def statistics
+    @statistics = Hash.new
+    @providers.each do |provider|
+      @statistics[provider.id] = {
+        "running_instances" => 0,
+        "pending_instances" => 0,
+        "error_instances" => 0,
+        "historical_running_instances" => 0,
+        "historical_error_instances" => 0,
+      }
+    end
+
+    # Queries are NOT permissioned by instance, as info is
+    # used purely for statistical purposes.
+
+    # current instances
+    provider_counts = ProviderAccount.joins(:instances).
+      merge(Instance.scoped).
+      select("provider_id, state, count(*) as count").
+      where(:provider_id => @providers.map{|provider| provider.id}).
+      group("provider_id, state")
+
+    provider_counts.each do |provider_count|
+      provider_id = provider_count["provider_id"]
+      state = provider_count["state"]
+      count = provider_count["count"]
+
+      if Instance::FAILED_STATES.include?(state)
+        @statistics[provider_id]["error_instances"] += count.to_i
+      elsif [Instance::STATE_RUNNING, Instance::STATE_SHUTTING_DOWN].
+               include?(state)
+        @statistics[provider_id]["running_instances"] += count.to_i
+      elsif [Instance::STATE_NEW, Instance::STATE_PENDING].
+               include?(state)
+        @statistics[provider_id]["pending_instances"] += count.to_i
+      end
+    end
+
+    # instances that were running between historical date range
+    historical_running_provider_counts = ProviderAccount.joins(:instances).
+      merge(Instance.unscoped).
+      select("provider_id, state, count(*) as count").
+      where(:provider_id => @providers.map{|provider| provider.id}).
+      where("time_last_running <= :to_date and 
+             (time_last_stopped is null
+              or time_last_stopped >= :from_date)",
+            :to_date => @to_date.to_datetime.end_of_day,
+            :from_date => @from_date.to_datetime.beginning_of_day
+            ).
+      group("provider_id, state")
+
+    historical_running_provider_counts.each do |provider_count|
+      provider_id = provider_count["provider_id"]
+      count = provider_count["count"]
+
+      @statistics[provider_id]["historical_running_instances"] += count.to_i
+    end
+
+    # instances that threw an error between historical date range
+    historical_error_provider_counts = ProviderAccount.joins(:instances).
+      merge(Instance.unscoped).
+      select("provider_id, count(*) as count").
+      where(:provider_id => @providers.map{|provider| provider.id}).
+      where("instances.state" => Instance::FAILED_STATES).
+      where("instances.updated_at between :from_date and :to_date",
+            :states => Instance::FAILED_STATES,
+            :to_date => @to_date.to_datetime.end_of_day,
+            :from_date => @from_date.to_datetime.beginning_of_day
+            ).
+      group("provider_id")
+
+    historical_error_provider_counts.each do |provider_count|
+      provider_id = provider_count["provider_id"]
+      count = provider_count["count"]
+
+      @statistics[provider_id]["historical_error_instances"] += count.to_i
+    end
+
+    # all running instances during historical date range
+    historical_instances = Instance.unscoped.
+      find(:all,
+           :conditions => ["time_last_running <= ? and 
+                             (time_last_stopped is null
+                              or time_last_stopped >= ?)",
+                           @to_date.to_datetime.end_of_day,
+                           @from_date.to_datetime.beginning_of_day],
+           :include => {:provider_account => [:provider]}
+           )
+
+    @datasets = Hash.new
+    counts = Hash.new
+    events = Array.new
+
+    counts["All"] = 0
+
+    historical_instances.each do |instance|
+      provider_account = instance.provider_account
+
+      if check_privilege(Privilege::VIEW, provider_account)
+        label = provider_account.nil? ?
+                  'Unknown' :
+                  provider_account.provider.name +
+                  " (" + provider_account.name + ")"
+
+        if !counts.has_key?(label)
+          counts[label] = 0
+        end
+        
+        # see if instance started before from_date
+        if instance.time_last_running <= @from_date.to_datetime.beginning_of_day
+          counts[label] = counts[label] + 1
+          counts["All"] = counts["All"] + 1
+        else
+          events << {
+            "time" => instance.time_last_running,
+            "label" => label,
+            "increment" => 1
+          }          
+        end
+        
+        if !instance.time_last_stopped.nil? &&
+            instance.time_last_stopped <= @to_date.to_datetime.end_of_day
+          events << {
+            "time" => instance.time_last_stopped,
+            "label" => label,
+            "increment" => -1
+          }          
+        end
+      end
+    end
+
+    counts.each.map{ |label,count|
+      @datasets[label] = [[@from_date.to_datetime.beginning_of_day.to_i * 1000,
+                           count]]
+    }
+
+    events.sort_by {|event| event["time"]}.each do |event|
+      timestamp = event["time"].to_i * 1000
+      increment = event["increment"]
+
+      [ event["label"], "All" ].each { |label|
+        @datasets[label] << [timestamp - 1, counts[label]]
+        counts[label] = counts[label] + increment
+        @datasets[label] << [timestamp, counts[label]]
+      }
+    end
+
+    counts.each.map{ |label,count|
+      @datasets[label] << [@to_date.to_datetime.end_of_day.to_i * 1000, count]
+    }
+  end
 end
diff --git a/src/app/views/providers/index.html.haml b/src/app/views/providers/index.html.haml
index c45d064..9939656 100644
--- a/src/app/views/providers/index.html.haml
+++ b/src/app/views/providers/index.html.haml
@@ -1,6 +1,71 @@
 = render :partial => 'layouts/admin_nav'
 %section.content-section.provider
-  = t("providers.index.no_providers_available")
-  - if check_privilege(Privilege::CREATE, Provider)
-    = t("providers.index.create_one")
-    = link_to t("providers.index.create_new_provider"), new_provider_path, :class => 'button', :id => "create_new_provider"
+  - content_for :form_header do
+    - if check_privilege(Privilege::CREATE, Provider)
+      %li= link_to t("providers.index.create_new_provider"), new_provider_path, :class => 'button', :id => "create_new_provider"
+
+  - content_for :filter_controls do
+    %li
+      = hidden_field_tag :current_path, request.fullpath
+      = t('filter_table.from')
+      = select_date @from_date, :prefix => :from_date
+      = t('filter_table.to')
+      = select_date @to_date, :prefix => :to_date
+      = restful_submit_tag t("filter_table.apply_filters"), "index", filter_providers_path, 'POST', :class => 'button', :id => 'apply_provider_index_filter'
+      %span.label.badge.dark= @providers.count
+  = filter_table(@header, @providers) do |provider|
+    - statistics = @statistics[provider.id]
+    %tr{:class => cycle('nostripe','stripe')}
+      %td= link_to provider.name, edit_provider_path(provider)
+      %td= provider.provider_type.name
+      %td
+        - if statistics["running_instances"] > 0
+          %font{:color => 'green'}= statistics["running_instances"]
+        - else
+          = statistics["running_instances"]
+      %td
+        - if statistics["pending_instances"] > 0
+          %font{:color => 'brown'}= statistics["pending_instances"]
+        - else
+          = statistics["pending_instances"]
+      %td
+        - if statistics["error_instances"] > 0
+          %font{:color => 'red'}= statistics["error_instances"]
+        - else
+          = statistics["error_instances"]
+      %td
+        - if statistics["historical_running_instances"] > 0
+          %font{:color => 'green'}= statistics["historical_running_instances"]
+        - else
+          = statistics["historical_running_instances"]
+      %td
+        - if statistics["historical_error_instances"] > 0
+          %font{:color => 'red'}= statistics["historical_error_instances"]
+        - else
+          = statistics["historical_error_instances"]
+
+  %br
+  %div{:id => 'provider-history-graph', :style => 'width:925px;height:250px;'}
+
+:javascript
+  $(function () {
+    var datasets = [
+      {
+        label: "All",
+        data: [#{ @datasets["All"].each.map{ |p| "[#{p[0]}, #{p[1]}]"}.join(", ") }]
+      },
+      #{ @datasets.reject{|label,data| label == "All"}.each.map{ |label,data| "{
+        label: \"" + label + "\",
+        data: [#{ data.each.map{ |p| "[#{p[0]}, #{p[1]}]"}.join(", ") }]
+      }" }.join(",
+      ") }
+    ];
+
+    $.plot($("#provider-history-graph"), datasets, {
+      xaxis: {
+        mode: "time",
+        min: #{@from_date.to_datetime.beginning_of_day.to_i * 1000},
+        max: #{@to_date.to_datetime.end_of_day.to_i * 1000}
+      }
+    });
+  });
diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
index 42b15f5..aede674 100644
--- a/src/config/locales/en.yml
+++ b/src/config/locales/en.yml
@@ -1111,6 +1111,11 @@ en:
       provider_name: Provider Name
       provider_url: Provider URL
       provider_type: Provider Type
+      running_instances: Running Instances (Current)
+      pending_instances: Pending (Current)
+      error_instances: Errors (Current)
+      historical_running_instances: Running (Historical)
+      historical_error_instances: Errors (Historical)
       x_deltacloud_driver: X-Deltacloud-Driver
       x_deltacloud_provider: X-Deltacloud-Provider
       no_providers_available: No providers available.
diff --git a/src/config/routes.rb b/src/config/routes.rb
index e7f26c5..3e81885 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
@@ -139,6 +139,7 @@ Conductor::Application.routes.draw do
 
   resources :providers do
     delete 'multi_destroy', :on => :collection
+    post :filter, :on => :collection
 
     resources :provider_accounts do
       collection do
diff --git a/src/features/provider.feature b/src/features/provider.feature
index 2ba7081..e5ca8dc 100644
--- a/src/features/provider.feature
+++ b/src/features/provider.feature
@@ -92,17 +92,6 @@ Feature: Manage Providers
     And I should see "Provider is disabled."
     And provider "provider1" should have all instances stopped
 
-  Scenario: Persist selected provider
-    Given there is a provider named "provider1"
-    And there is a provider named "provider2"
-    When I am on the provider1's edit provider page
-    And I click on the Providers icon in the menu
-    Then I should be on the provider1's edit provider page
-    When I am on the provider2's edit provider page
-    And I click on the Providers icon in the menu
-    Then I should be on the provider2's edit provider page
-
-
 #  Scenario: Search for hardware profiles
 #    Given there are these providers:
 #    | name          | url                         |
-- 
1.7.6.5




More information about the aeolus-devel mailing list