Firewalling v2 - plus prototype for terremark
by marios@redhat.com
Appologies for previous email with the huge subject line - i try again:
These patches implement a second version of firewalling for the terremark driver.
This is still a prototype - we will try and see if this model 'fits' for ec2 before
committing to using this (terremark and ec2 are the only clouds that require
management of firewall rules in order to gain access to a given instance).
Currently a firewall_rule consists of:
public_ip, public_port, protocol, private_ip, private_port (think NAT).
--marios
13 years, 11 months
[PATCH aggregator] instances index/list view and backend
by Mo Morsi
navigating to http://localhost:3000/instance/ when running deltacloud
locally now brings the user to a list of instances in pools which
they have the instance_view permission on
---
src/app/controllers/instance_controller.rb | 5 +++++
src/app/views/dashboard/summary.haml | 2 ++
src/app/views/instance/_list.html.erb | 24 ++++++++++++++++++++++++
src/app/views/instance/index.html.erb | 3 +--
4 files changed, 32 insertions(+), 2 deletions(-)
create mode 100644 src/app/views/instance/_list.html.erb
diff --git a/src/app/controllers/instance_controller.rb b/src/app/controllers/instance_controller.rb
index c898691..c1c56e9 100644
--- a/src/app/controllers/instance_controller.rb
+++ b/src/app/controllers/instance_controller.rb
@@ -25,6 +25,11 @@ class InstanceController < ApplicationController
before_filter :require_user
def index
+ @instances = current_user.permissions.all.find_all { |perm|
+ !perm.role.privileges.all.find { |priv|
+ priv.name == Privilege::INSTANCE_VIEW
+ }.nil? && perm.permission_object_type == "Pool"
+ }.collect { |perm| perm.permission_object.instances }.flatten
end
# Right now this is essentially a duplicate of PoolController#show,
diff --git a/src/app/views/dashboard/summary.haml b/src/app/views/dashboard/summary.haml
index 4eeb58b..b64ffb5 100644
--- a/src/app/views/dashboard/summary.haml
+++ b/src/app/views/dashboard/summary.haml
@@ -38,6 +38,8 @@
Create a Template
%a{:href => url_for(:controller => "users", :action => "new")}
Create a User
+ %a{:href => url_for(:controller => "instance", :action => "index")}
+ View Instances
- else
%a{:href => url_for(:controller => "", :action => "")}
Launch Instances
diff --git a/src/app/views/instance/_list.html.erb b/src/app/views/instance/_list.html.erb
new file mode 100644
index 0000000..66f6eeb
--- /dev/null
+++ b/src/app/views/instance/_list.html.erb
@@ -0,0 +1,24 @@
+<% if @instances.size == 0 %>
+<h1>There are no instances to display</h1>
+<% else %>
+ <table>
+ <thead>
+ <tr>
+ <th scope="col">Name</th>
+ <th scope="col">Pool</th>
+ <th scope="col">Hardware Profile</th>
+ <th scope="col">Image</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%(a)instances.each {|instance| %>
+ <tr>
+ <td><%= instance.name %></td>
+ <td><%= instance.pool.name if instance.pool %></td>
+ <td><%= instance.hardware_profile.name if instance.hardware_profile %></td>
+ <td><%= instance.image if instance.image %></td>
+ </tr>
+ <% } %>
+ </tbody>
+ </table>
+<% end %>
diff --git a/src/app/views/instance/index.html.erb b/src/app/views/instance/index.html.erb
index a632f6c..c19c3fa 100644
--- a/src/app/views/instance/index.html.erb
+++ b/src/app/views/instance/index.html.erb
@@ -1,2 +1 @@
-<h1>Instance#index</h1>
-<p>Find me in app/views/instance/index.html.erb</p>
+<%= render :partial => 'list' %>
--
1.6.2.5
13 years, 11 months
[PATCH] removed treeview from imagebuilder
by Jan Provazník
From: jenik <jenik(a)queeg.localdomain>
---
src/app/views/image_descriptor/_software.haml | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/src/app/views/image_descriptor/_software.haml b/src/app/views/image_descriptor/_software.haml
index 57245c1..21f4fb5 100644
--- a/src/app/views/image_descriptor/_software.haml
+++ b/src/app/views/image_descriptor/_software.haml
@@ -10,7 +10,6 @@
// when JS is enabled, hide the Dashboard content -- it'll be loaded
// by jquery UI tab using ajax
$("#dashboard-content").hide();
- $("#selected_packages").treeview({collapsed: true});
#{(a)image_descriptor.xml.packages.map {|group, pkgs| js_add_group_cmd(group, pkgs)}.join("\n")}
});
function remove_group(ev) {
@@ -33,12 +32,10 @@
if (!parent) parent = $("#selected_packages");
if (parent.find(".pkgname").filter(function() {return $(this).text() == pkgname}).length == 0) {
var node = $("<li><input type=checkbox name='xml[packages][]' value='" + group + '#' + pkgname + "' checked=true><span class='pkgname'>" + pkgname + "</span></li>").appendTo(parent);
- $("#selected_packages").treeview({add: node});
}
};
function add_group(name) {
var group = $("<li><span class='group'>" + name + "</span><span class='select' onclick='remove_group(event)'>Remove</span><ul></ul></li>").appendTo("#selected_packages");
- $("#selected_packages").treeview({add: group});
return group.find("ul");
};
function select_group(opts) {
--
1.6.6.1
13 years, 11 months
[PATCH aggregator] integrate graphs into 'provider service quality' portlet
by Mo Morsi
---
src/app/controllers/dashboard_controller.rb | 9 +++++++++
src/app/services/graph_service.rb | 6 +++---
src/app/views/dashboard/summary.haml | 2 +-
src/config/initializers/mime_types.rb | 1 +
4 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb
index 5061284..106552a 100644
--- a/src/app/controllers/dashboard_controller.rb
+++ b/src/app/controllers/dashboard_controller.rb
@@ -31,6 +31,15 @@ class DashboardController < ApplicationController
return params[:ajax] == "true"
end
+ def graph(opts = {})
+ entity = nil
+ entity = Provider.find(params[:id]) if params[:entity_type] == 'Provider'
+ graph = GraphService.dashboard_qos(p)[('Graph::'+params[:type]).constantize]
+ respond_to do |format|
+ format.svg { render :xml => graph.svg}
+ end
+ end
+
def index
@providers = Provider.find(:all)
diff --git a/src/app/services/graph_service.rb b/src/app/services/graph_service.rb
index 8fc5bad..9bb8177 100644
--- a/src/app/services/graph_service.rb
+++ b/src/app/services/graph_service.rb
@@ -1,13 +1,13 @@
class GraphService
require 'gnuplot'
- def gnuplot_open( persist=false )
+ def self.gnuplot_open( persist=false )
cmd = Gnuplot.gnuplot( persist ) or raise 'gnuplot not found'
output_stream = IO::popen( cmd, "r+")
end
- def qos_avg_time_to_submit_graph ( provider=nil, width=200, height=100 )
+ def self.qos_avg_time_to_submit_graph ( provider=nil, width=200, height=100 )
graph = Graph.new
gp = gnuplot_open
@@ -41,7 +41,7 @@ class GraphService
graph
end
- def dashboard_qos (provider = nil)
+ def self.dashboard_qos (provider = nil)
graphs = Hash.new
graphs[Graph::QOS_AVG_TIME_TO_SUBMIT] = qos_avg_time_to_submit_graph(provider)
graphs
diff --git a/src/app/views/dashboard/summary.haml b/src/app/views/dashboard/summary.haml
index f3d6ab6..6e7e267 100644
--- a/src/app/views/dashboard/summary.haml
+++ b/src/app/views/dashboard/summary.haml
@@ -53,7 +53,7 @@
<img src="images/dashboard_summary_prev.png" /><img src="images/dashboard_summary_next.png" />
- @providers.each do |provider|
.provider_service_quality_graph
- <!-- FIXME include graph -->
+ = "<object data='" + url_for(:action => :graph, :type => 'QOS_AVG_TIME_TO_SUBMIT', :entity_type => 'Provider', :id => provider.id) + "' type='image/svg+xml' />"
.provider_service_quality_graph_summary
= provider.name
<!-- FIXME 'good/poor/average service... -->
diff --git a/src/config/initializers/mime_types.rb b/src/config/initializers/mime_types.rb
index 72aca7e..c0feb58 100644
--- a/src/config/initializers/mime_types.rb
+++ b/src/config/initializers/mime_types.rb
@@ -3,3 +3,4 @@
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone
+Mime::Type.register "image/svg+xml", :svg
--
1.6.2.5
13 years, 11 months
key indicators portlet
by Jan Provazník
key indicators portlet: displays summary about instances, accounts/pools/providers counts
13 years, 11 months
[PATCH aggregator] instances index/list view and backend (revision 1)
by Mo Morsi
---
src/app/controllers/instance_controller.rb | 26 ++++++++++++++++++++++++++
src/app/models/instance.rb | 1 +
src/app/views/dashboard/summary.haml | 2 ++
src/app/views/instance/_list.html.erb | 25 +++++++++++++++++++++++++
src/app/views/instance/index.html.erb | 3 +--
5 files changed, 55 insertions(+), 2 deletions(-)
create mode 100644 src/app/views/instance/_list.html.erb
diff --git a/src/app/controllers/instance_controller.rb b/src/app/controllers/instance_controller.rb
index c898691..eaeab35 100644
--- a/src/app/controllers/instance_controller.rb
+++ b/src/app/controllers/instance_controller.rb
@@ -27,6 +27,32 @@ class InstanceController < ApplicationController
def index
end
+ def paginated
+ # 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')
+
+ # FIXME
+ #@instances = Instance.list_for_user(current_user, Privilege::INSTANCE_VIEW)
+ @instances = Instance.search_filter(params[:sSearch], Instance::SEARCHABLE_COLUMNS).paginate(
+ :page => page + 1,
+ :order => order
+ )
+
+ 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
+
# Right now this is essentially a duplicate of PoolController#show,
# but really it should be a single instance should we decide to have a page
# for that. Redirect on create was all that brought you here anyway, so
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 21a5cef..a3cf347 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -21,6 +21,7 @@
class Instance < ActiveRecord::Base
include SearchFilter
+ include PermissionedObject
cattr_reader :per_page
@@per_page = 15
diff --git a/src/app/views/dashboard/summary.haml b/src/app/views/dashboard/summary.haml
index f3d6ab6..d8b9e20 100644
--- a/src/app/views/dashboard/summary.haml
+++ b/src/app/views/dashboard/summary.haml
@@ -38,6 +38,8 @@
Create a Template
%a{:href => url_for(:controller => "users", :action => "new")}
Create a User
+ %a{:href => url_for(:controller => "instance", :action => "index")}
+ View Instances
- else
%a{:href => url_for(:controller => "", :action => "")}
Launch Instances
diff --git a/src/app/views/instance/_list.html.erb b/src/app/views/instance/_list.html.erb
new file mode 100644
index 0000000..9d12c76
--- /dev/null
+++ b/src/app/views/instance/_list.html.erb
@@ -0,0 +1,25 @@
+<%= 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 => 'instance', :action => 'paginated'),
+ :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>
diff --git a/src/app/views/instance/index.html.erb b/src/app/views/instance/index.html.erb
index a632f6c..c19c3fa 100644
--- a/src/app/views/instance/index.html.erb
+++ b/src/app/views/instance/index.html.erb
@@ -1,2 +1 @@
-<h1>Instance#index</h1>
-<p>Find me in app/views/instance/index.html.erb</p>
+<%= render :partial => 'list' %>
--
1.6.2.5
13 years, 11 months
[PATCH aggregator 2/2] don't ask user to select pool if it's already done via the URL/link
by Scott Seago
In addition, if a user only has permission on one pool, there's no need to ask the user to select it.
Signed-off-by: Scott Seago <sseago(a)redhat.com>
---
src/app/controllers/instance_controller.rb | 3 +++
src/app/views/instance/new.html.erb | 9 +++++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/src/app/controllers/instance_controller.rb b/src/app/controllers/instance_controller.rb
index c898691..159aab8 100644
--- a/src/app/controllers/instance_controller.rb
+++ b/src/app/controllers/instance_controller.rb
@@ -41,6 +41,9 @@ class InstanceController < ApplicationController
@instance = Instance.new(params[:instance])
require_privilege(Privilege::INSTANCE_MODIFY, @instance.pool) if @instance.pool
@pools = Pool.list_for_user(@current_user, Privilege::POOL_VIEW)
+ # FIXME: what error msg to show if no pool is selected and the user has
+ # permission on none?
+ @instance.pool = @pools[0] if (@instance.pool.nil? and (@pools.size == 1))
end
def create
diff --git a/src/app/views/instance/new.html.erb b/src/app/views/instance/new.html.erb
index 74096a2..0553a42 100644
--- a/src/app/views/instance/new.html.erb
+++ b/src/app/views/instance/new.html.erb
@@ -39,12 +39,21 @@
</li>
<input type=hidden name="instance[image_id]" value="<%= @instance.image ? @instance.image.id : '' %>">
+ <% if @instance.pool %>
+ <input type=hidden name="instance[pool_id]" value="<%= @instance.pool_id %>">
+ <% if (@pools.size > 1) %>
+ <li><label>Pool</label>
+ <%= @instance.pool.name %>
+ </li>
+ <% end %>
+ <% else %>
<li><label>Pool<span>Pick your pool</span></label>
<%= select("instance", "pool_id",
@pools.collect {|p| [ p.name, p.id ] },
{ :include_blank => true },
{:onchange => "poolSelected(this)"}) %>
</li>
+ <% end %>
<% if @instance.pool and @instance.pool.hardware_profiles.size > 0 %>
<li><label>Hardware Profile<span>Pick your hardware profile</span></label>
--
1.6.2.5
13 years, 11 months
[PATCH aggregator] Added provider account matchmaking to current task scheduler.
by Scott Seago
Note that this is not part of the condor infrastructure -- it's an interim solution to handle scheduling across providers until the full scheduling capabilities are put into use with Condor integration.
The full list of provider accounts is filtered by realm, hardware profile, and image -- so only those accounts that map validly to the "front-end/engine" realm/hwp/image choices of the user are considered. After this, we filter out those cloud accounts that do not have the available capacity to schedule the instance creation request.
As we do not yet have a UI to map images and HWPs from different providers to the same front-end image or HWP, multi-provider scheduling is only possible across accounts in the same provider, or across providers after manually mapping equivalent images and HWPs.
For a simple test case with exactly two providers in the AR database with the same set of available images and HWPs (this will only be true for two mock providers, or if you've set up two separate provider objects pointing to the same driver -- or two drivers pointing to the same cloud impl), the following should take your separately-mapped resources and map them together on the front end:
Provider.last.images.each do |image|
if image.aggregator_images[0].provider_images.size < 2
image.aggregator_images[0].delete
image.aggregator_images = [Provider.first.images.find_by_external_key(image.external_key).aggregator_images[0]]
image.save
end
agg_image = image.aggregator_images[0]
agg_image.name = image.name
agg_image.external_key = image.external_key
agg_image.save
end
Provider.last.hardware_profiles.each do |hardware_profile|
if hardware_profile.aggregator_hardware_profiles[0].provider_hardware_profiles.size < 2
hardware_profile.aggregator_hardware_profiles[0].delete
hardware_profile.aggregator_hardware_profiles = [Provider.first.hardware_profiles.find_by_external_key(hardware_profile.external_key).aggregator_hardware_profiles[0]]
hardware_profile.save
end
agg_hwp = hardware_profile.aggregator_hardware_profiles[0]
agg_hwp.name = hardware_profile.name
agg_hwp.external_key = hardware_profile.external_key
agg_hwp.save
end
Signed-off-by: Scott Seago <sseago(a)redhat.com>
---
src/app/models/instance.rb | 14 +++---
src/app/util/taskomatic.rb | 77 ++++++++++++++++++++++++----------
src/app/views/instance/new.html.erb | 2 +-
3 files changed, 62 insertions(+), 31 deletions(-)
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 21a5cef..56019ff 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -45,8 +45,6 @@ class Instance < ActiveRecord::Base
validates_uniqueness_of :name, :scope => :pool_id
validates_length_of :name, :maximum => 1024
- # FIXME: for now, hardware profile is required, realm is optional, although for RHEV-M,
- # hardware profile may be optional too
validates_presence_of :hardware_profile_id
validates_presence_of :image_id
@@ -114,11 +112,13 @@ class Instance < ActiveRecord::Base
end
def front_end_realm=(realm_name)
- provider_name, tmpstr = realm_name.split(Realm::AGGREGATOR_REALM_PROVIDER_DELIMITER,2)
- account_name, realm_name = tmpstr.split(Realm::AGGREGATOR_REALM_ACCOUNT_DELIMITER,2)
- provider = Provider.find_by_name(provider_name)
- self.cloud_account = provider.cloud_accounts.find_by_username(account_name)
- self.realm = provider.realms.find_by_name(realm_name) unless realm_name.nil?
+ unless realm_name.nil? or realm_name.empty?
+ provider_name, tmpstr = realm_name.split(Realm::AGGREGATOR_REALM_PROVIDER_DELIMITER,2)
+ account_name, realm_name = tmpstr.split(Realm::AGGREGATOR_REALM_ACCOUNT_DELIMITER,2)
+ provider = Provider.find_by_name(provider_name)
+ self.cloud_account = provider.cloud_accounts.find_by_username(account_name)
+ self.realm = provider.realms.find_by_name(realm_name) unless realm_name.nil?
+ end
end
# Returns the total time that this instance has been in the state
diff --git a/src/app/util/taskomatic.rb b/src/app/util/taskomatic.rb
index 3277c4d..08da3d2 100644
--- a/src/app/util/taskomatic.rb
+++ b/src/app/util/taskomatic.rb
@@ -50,40 +50,71 @@ class Taskomatic
# can go to state running.
# TODO Modify this to handle generic case for providers
pool = @task.instance.pool
- cloud_account = @task.instance.cloud_account
- [pool, cloud_account].each do |parent|
- quota = parent.quota
- if quota
- if !quota.can_create_instance?((a)task.instance) || !quota.can_start_instance?((a)task.instance)
- @task.state = Task::STATE_FAILED
- @task.instance.state = Instance::STATE_CREATE_FAILED
+ #find matching cloud account
+ if @task.instance.cloud_account
+ cloud_accounts = [@task.instance.cloud_account]
+ else
+ # FIXME: this provides a predictable order -- scheduler will eventually
+ # do something entirely different to determine preference
+ cloud_accounts = CloudAccount.find(:all, :order => 'created_at')
+ end
- if parent.class == Pool
- @task.failure_code = Task::FAILURE_OVER_POOL_QUOTA
- elsif parent.class == CloudAccount
- @task.failure_code = Task::FAILURE_OVER_CLOUD_ACCOUNT_QUOTA
- end
+ if @task.instance.image.provider_image?
+ image_providers = Set.new([(a)task.instance.image])
+ else
+ image_providers = Set.new((a)task.instance.image.provider_images.
+ collect { |image| image.provider})
+ end
- @task.save!
- @task.instance.save!
+ if @task.instance.hardware_profile.provider_hardware_profile?
+ hwp_providers = Set.new([(a)task.instance.hardware_profile])
+ else
+ hwp_providers = Set.new((a)task.instance.hardware_profile.provider_hardware_profiles.
+ collect { |hwp| hwp.provider })
+ end
- return @task
- end
- end
+ matching_providers = hwp_providers & image_providers
+ cloud_accounts.delete_if do |acct|
+ !matching_providers.include?(acct.provider) or
+ (acct.quota and
+ (!acct.quota.can_create_instance?((a)task.instance) or
+ !acct.quota.can_start_instance?((a)task.instance)))
+ end
+
+ if pool.quota and
+ (!pool.quota.can_create_instance?((a)task.instance) or
+ !pool.quota.can_start_instance?((a)task.instance))
+ @task.failure_code = Task::FAILURE_OVER_POOL_QUOTA
+ end
+ @task.failure_code = Task::FAILURE_PROVIDER_NOT_FOUND if cloud_accounts.empty?
+
+ unless @task.failure_code.nil?
+ @task.state = Task::STATE_FAILED
+ @task.instance.state = Instance::STATE_CREATE_FAILED
+ @task.save!
+ @task.instance.save!
+ return @task
end
begin
+ # take first matching cloud account
+ @task.instance.cloud_account = cloud_accounts[0]
client = @task.instance.cloud_account.connect
realm = @task.instance.realm.external_key rescue nil
# Map aggregator HWP/image to back-end provider HWP/image in instance
unless @task.instance.image.provider_image?
- @task.instance.image = @task.instance.image.provider_images[0]
+ @task.instance.image = @task.instance.image.provider_images.
+ find(:first, :conditions => {:provider_id =>
+ @task.instance.cloud_account.provider_id})
end
unless @task.instance.hardware_profile.provider_hardware_profile?
- @task.instance.hardware_profile = @task.instance.hardware_profile.provider_hardware_profiles[0]
+ @task.instance.hardware_profile = @task.instance.hardware_profile.
+ provider_hardware_profiles.
+ find(:first, :conditions => {:provider_id =>
+ @task.instance.cloud_account.provider_id})
end
@task.state = Task::STATE_PENDING
diff --git a/src/app/views/instance/new.html.erb b/src/app/views/instance/new.html.erb
index 894d1b6..74096a2 100644
--- a/src/app/views/instance/new.html.erb
+++ b/src/app/views/instance/new.html.erb
@@ -55,7 +55,7 @@
<% end %>
<% if @instance.pool and @instance.pool.realms.size > 0 %>
<li><label>Realm<span>Choose a realm</span></label>
- <%= select("instance", "front_end_realm", @instance.pool.realms, { :include_blank => false }) %>
+ <%= select("instance", "front_end_realm", @instance.pool.realms, { :include_blank => true }) %>
</li>
<% end %>
</ul>
--
1.6.2.5
13 years, 11 months
[PATCH aggregator] quota usage dashboard portlet frontend
by Mo Morsi
---
src/app/controllers/dashboard_controller.rb | 3 +
src/app/views/dashboard/summary.haml | 93 ++++++++++++++++++---------
src/public/stylesheets/components.css | 76 +++++++++++++++++++++-
3 files changed, 139 insertions(+), 33 deletions(-)
diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb
index 5061284..820a7e0 100644
--- a/src/app/controllers/dashboard_controller.rb
+++ b/src/app/controllers/dashboard_controller.rb
@@ -32,7 +32,10 @@ class DashboardController < ApplicationController
end
def index
+ # FIXME filter to just those that the user has access to
@providers = Provider.find(:all)
+ @cloud_accounts = CloudAccount.find(:all)
+ @pools = Pool.find(:all)
# FIXME remove general role based permission check, replace w/
# more granular / per-permission-object permission checks on the
diff --git a/src/app/views/dashboard/summary.haml b/src/app/views/dashboard/summary.haml
index f3d6ab6..f879045 100644
--- a/src/app/views/dashboard/summary.haml
+++ b/src/app/views/dashboard/summary.haml
@@ -26,41 +26,72 @@
%input{ :id => "hide_getting_started", :type => "checkbox" }
Thanks, don't show this again
-#actions_dashboard_section
- %h2
- Actions
- - if @is_admin
- %a{:href => url_for(:controller => "cloud_accounts", :action => "new")}
- Add a Provider Account
- %a{:href => url_for(:controller => "provider", :action => "new")}
- Add a Provider
- %a{:href => url_for(:controller => "", :action => "")}
- Create a Template
- %a{:href => url_for(:controller => "users", :action => "new")}
- Create a User
- - else
- %a{:href => url_for(:controller => "", :action => "")}
- Launch Instances
- %a{:href => url_for(:controller => "", :action => "")}
- Enter a help ticket
+.dashboard_column
+ #actions_dashboard_section
+ %h2
+ Actions
+ - if @is_admin
+ %a{:href => url_for(:controller => "cloud_accounts", :action => "new")}
+ Add a Provider Account
+ %a{:href => url_for(:controller => "provider", :action => "new")}
+ Add a Provider
+ %a{:href => url_for(:controller => "", :action => "")}
+ Create a Template
+ %a{:href => url_for(:controller => "users", :action => "new")}
+ Create a User
+ - else
+ %a{:href => url_for(:controller => "", :action => "")}
+ Launch Instances
+ %a{:href => url_for(:controller => "", :action => "")}
+ Enter a help ticket
+
+ #service_quality_dashboard_section
+ - if @is_admin
+ %h2
+ Provider Service Quality
+ .dashboard_section_summary
+ <img src="images/dashboard_summary_next.png" /><img src="images/dashboard_summary_prev.png" />
+ %p
+ Average time to submit tasks to provider, 24 hours
+ <div style="clear: both;" />
+ - @providers.each do |provider|
+ .provider_service_quality_graph
+ <!-- FIXME include graph -->
+ .provider_service_quality_graph_summary
+ = provider.name
+ <!-- FIXME 'good/poor/average service... -->
+ <div style="clear: both;" />
+ - else
+ %h2
+ Service Quality
-#service_quality_dashboard_section
- - if @is_admin
+.dashboard_column
+ #quota_usage_dashboard_section
%h2
- Provider Service Quality
+ Quota Usage
.dashboard_section_summary
- Average time to submit tasks to provider, 24 hours
- <img src="images/dashboard_summary_prev.png" /><img src="images/dashboard_summary_next.png" />
- - @providers.each do |provider|
- .provider_service_quality_graph
+ Instance utilization by account
+ - @cloud_accounts.each do |account|
+ .account_quota_usage_graph_summary
+ = "Account " + account.username
+ .account_quota_usage_history_graph
<!-- FIXME include graph -->
- .provider_service_quality_graph_summary
- = provider.name
- <!-- FIXME 'good/poor/average service... -->
- <div style="clear: both;" />
- - else
- %h2
- Service Quality
+ .account_quota_usage_current_graph
+ <!-- FIXME include graph -->
+ <div style="clear: both;" />
+ .dashboard_section_summary
+ <img src="images/dashboard_summary_next.png" /><img src="images/dashboard_summary_prev.png" />
+ %p
+ Quota usage by pool
+ <div style="clear: both;" />
+ - @pools.each do |pool|
+ .pool_quota_usage_summary
+ = pool.name
+ .pool_quota_usage_limit
+ <!-- FIXME 'quota limit met'... -->
+ .pool_quota_usage_instances
+ <!-- FIXME 'running instances'... -->
+ <div style="clear: both;" />
:javascript
$("#hide_getting_started").click(function(){
diff --git a/src/public/stylesheets/components.css b/src/public/stylesheets/components.css
index b61fbc9..ff4c428 100644
--- a/src/public/stylesheets/components.css
+++ b/src/public/stylesheets/components.css
@@ -72,20 +72,32 @@ ul.nav li.selected {
}
/* dashboard style */
+.dashboard_column{
+ float: left;
+ width: 47%;
+}
+
.dashboard_section_summary {
background: #F2F2F2;
font-size: 0.8em;
font-weight: bolder;
- margin: 0 15px 10px 0;
+ margin: 10px 15px 10px 0;
padding: 5px 0px 5px 5px;
}
+.dashboard_section_summary p {
+ display: inline;
+ float: left;
+ margin: 3px 0 3px 0;
+}
+
.dashboard_section_summary img:first-child {
- padding-left: 40px;
+ padding-right: 5px;
}
.dashboard_section_summary img {
vertical-align: middle;
+ float: right;
}
#getting_started_dashboard_section {
@@ -175,3 +187,63 @@ ul.nav li.selected {
height: 15px;
padding: 20px 0 24px 0;
}
+
+#quota_usage_dashboard_section {
+ width: 390px;
+ border: 1px solid black;
+ padding: 5px 0 5px 15px;
+ margin: 10px 0px 10px 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+
+.account_quota_usage_graph_summary {
+ font-size: 0.8em;
+ padding-left: 15px;
+ display: inline;
+ float: left;
+}
+
+.account_quota_usage_history_graph {
+ display: inline;
+ float: left;
+ margin-left: 10px;
+ border: 1px solid black;
+ width: 120px;
+ height: 20px;
+}
+
+.account_quota_usage_current_graph {
+ display: inline;
+ float: left;
+ margin-left: 10px;
+ border: 1px solid black;
+ width: 140px;
+ height: 20px;
+}
+
+.pool_quota_usage_summary {
+ display: inline;
+ float: left;
+ padding-left: 15px;
+ width: 15%;
+}
+
+.pool_quota_usage_limit {
+ display: inline;
+ float: left;
+ width: 33%;
+ height: 25px;
+ border: 1px solid black;
+ margin-left: 17px;
+}
+
+.pool_quota_usage_instances {
+ display: inline;
+ float: left;
+ width: 33%;
+ height: 25px;
+ border: 1px solid black;
+ margin-left: 17px;
+ margin-bottom: 15px;
+}
--
1.6.2.5
13 years, 11 months
[PATCH aggregator] Added Demo Data Rake Task
by Martyn Taylor
From: martyntaylor <mtaylor(a)redhat.com>
---
src/lib/tasks/demo_data.rake | 117 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 117 insertions(+), 0 deletions(-)
create mode 100644 src/lib/tasks/demo_data.rake
diff --git a/src/lib/tasks/demo_data.rake b/src/lib/tasks/demo_data.rake
new file mode 100644
index 0000000..6d60baf
--- /dev/null
+++ b/src/lib/tasks/demo_data.rake
@@ -0,0 +1,117 @@
+namespace :db do
+ desc "Populates a Cloud Account with historical tasks, takes a cloud account id, user id, the time period in hours, and the
+ number of tasks to create"
+
+ PROB_LONG_RESPONSE = 8
+ PROB_MEDIUM_RESPONSE = 70
+ PROB_SHORT_REPONSE = 20
+ PROB_FAILURE = 2
+
+ LONG_RESPONSE_MIN = 7
+ LONG_RESPONSE_MAX = 15
+
+ MEDIUM_RESPONSE_MIN = 2
+ MEDIUM_RESPONSE_MAX = 5
+
+ SHORT_RESPONSE_MIN = 1
+ SHORT_RESPONSE_MAX = 2
+
+ REQUESTS_PER_MINUTE = 1
+
+ END_TIME = Time.now
+
+ TASK_ACTIONS = [ "create", "start", "stop", "reboot", "destroy" ]
+
+ SHORT_ACC = PROB_SHORT_REPONSE + PROB_FAILURE
+ MEDIUM_ACC = PROB_MEDIUM_RESPONSE + PROB_SHORT_REPONSE + PROB_FAILURE
+
+ task :demo_data, :cloud_account_id, :user_id, :time_period, :number_of_tasks, :needs => :environment do |t, args|
+
+ @time_scale = args[:time_period].to_f * 60 * 60
+ @number_of_tasks = args[:number_of_tasks]
+
+ puts @number_of_tasks
+
+ [Task, Instance].each(&:delete_all)
+
+ cloud_account = CloudAccount.find(args[:cloud_account_id])
+ user = User.find(args[:user_id])
+
+ instance = create_instance()
+
+ started_at = Time.now
+ create_tasks(instance, user)
+ ended_at = Time.now
+
+ print_stats(started_at, ended_at)
+ end
+
+ def create_instance()
+ instance = Instance.new({:name => "instance",
+ :hardware_profile_id => HardwareProfile.find(:first),
+ :image_id => Image.find(:first),
+ :state => Instance::STATE_NEW,
+ :pool_id => 1
+ })
+ instance.save!
+ return instance
+ end
+
+ def print_stats(started_at, ended_at)
+ run_time = ended_at - started_at
+ tasks_create_time = run_time / @number_of_tasks.to_f
+ tasks_per_minute = 60 / tasks_create_time
+
+ puts "Total Run Time (s): " + run_time.to_s()
+ puts "Average Create Time (s): " + tasks_create_time.to_s()
+ puts "Task Created Per Minute: " + tasks_per_minute.to_s()
+ end
+
+ def create_task(instance, user)
+ task = Task.new({})
+ task.user = user
+ task.type = "InstanceTask"
+ task.action = TASK_ACTIONS[rand(TASK_ACTIONS.length)]
+ task.task_target_id = instance.id
+ task.created_at = END_TIME - (@time_scale.to_f)
+ return task
+ end
+
+ def create_tasks(instance, user)
+ for i in 1..(a)number_of_tasks.to_f do
+ task = create_task(instance, user)
+
+ random = 1 + rand(100)
+ if random <= PROB_FAILURE
+ task.state = Task::STATE_FAILED
+ task.failure_code = Task::FAILURE_CODES[rand(Task::FAILURE_CODES.length)]
+ else
+ task.state = Task::STATE_FINISHED
+
+ time_submitted = END_TIME - rand(1 + (@time_scale.to_f))
+ task.time_submitted = time_submitted
+
+ task.time_started = calculate_time_started(time_submitted, random)
+
+ time_ended = task.time_started + rand(20) + 1
+ task.time_ended = time_ended
+ end
+ task.save!
+ end
+ end
+
+ def calculate_time_started(time_submitted, random)
+ time_started = nil
+
+ if random <= SHORT_ACC
+ time_started = time_submitted + (SHORT_RESPONSE_MIN + rand(SHORT_RESPONSE_MAX - SHORT_RESPONSE_MIN + 1))
+ elsif random <= MEDIUM_ACC
+ time_started = time_submitted + (MEDIUM_RESPONSE_MIN + rand(MEDIUM_RESPONSE_MAX - MEDIUM_RESPONSE_MIN + 1))
+ else
+ time_started = time_submitted + (LONG_RESPONSE_MIN + rand(LONG_RESPONSE_MAX - LONG_RESPONSE_MIN + 1))
+ end
+
+ return time_started
+ end
+
+end
\ No newline at end of file
--
1.6.6.1
13 years, 11 months