On Tue, Jul 20, 2010 at 12:49:04PM -0400, [email protected] wrote:
> From: martyntaylor <[email protected]>
> 
> ---
>  src/app/controllers/dashboard_controller.rb |   18 +-
>  src/app/models/graph.rb                     |   28 +++
>  src/app/services/graph_service.rb           |  320 
> +++++++++++++++++----------
>  src/app/views/dashboard/summary.haml        |    8 +-
>  4 files changed, 255 insertions(+), 119 deletions(-)
> 
> diff --git a/src/app/controllers/dashboard_controller.rb 
> b/src/app/controllers/dashboard_controller.rb
> index bcd2073..757598d 100644
> --- a/src/app/controllers/dashboard_controller.rb
> +++ b/src/app/controllers/dashboard_controller.rb
> @@ -31,17 +31,25 @@ class DashboardController < ApplicationController
>      return params[:ajax] == "true"
>    end
>  
> -  def provider_qos_graph
> +  def provider_qos_avg_time_to_submit_graph
>      params[:provider] = Provider.find(params[:id])
> -    graph = GraphService.dashboard_qos(current_user, 
> params)[params[:provider]][Graph::QOS_AVG_TIME_TO_SUBMIT]
> +    graph = 
> GraphService.dashboard_qos_avg_time_to_submit_graph(current_user, 
> params)[params[:provider]][Graph::QOS_AVG_TIME_TO_SUBMIT]
>      respond_to do |format|
>        format.svg  { render :xml => graph.svg}
>      end
>    end
>  
> -  def account_quota_graph
> -    params[:account] = CloudAccount.find(params[:id])
> -    graph = GraphService.dashboard_quota(current_user, 
> params)[params[:account]][Graph::QUOTA_INSTANCES_IN_USE]
> +  def quota_usage_graph
> +    if params[:cloud_account_id]
> +      params[:parent] = CloudAccount.find(params[:cloud_account_id])
> +    elsif params[:pool_id]
> +      params[:parent] = Pool.find(params[:pool_id])
> +    else
> +      return nil
> +    end
> +
> +    graphs = GraphService.dashboard_quota_usage(current_user, params)
> +    graph = 
> graphs[params[:parent]][Graph.get_quota_usage_graph_name(params[:resource_name])]
>      respond_to do |format|
>        format.svg  { render :xml => graph.svg}
>      end
> diff --git a/src/app/models/graph.rb b/src/app/models/graph.rb
> index 1c20dc3..cf1b498 100644
> --- a/src/app/models/graph.rb
> +++ b/src/app/models/graph.rb
> @@ -4,7 +4,35 @@ class Graph
>    QOS_AVG_TIME_TO_SUBMIT = "qos_avg_time_to_submit"
>    QUOTA_INSTANCES_IN_USE = "quota_instances_in_use"
>    INSTANCES_BY_PROVIDER_PIE = "instances_by_provider_pie"
> +
> +  # Quota Usage Graphs
> +  QUOTA_USAGE_RUNNING_INSTANCES = "quota_utilization_running_instances"
> +  QUOTA_USAGE_RUNNING_MEMORY = "quota_utilization_running_memory"
> +  QUOTA_USAGE_RUNNING_CPUS = "quota_utilization_running_cpus"
> +  QUOTA_USAGE_TOTAL_INSTANCES = "quota_utilization_total_instances"
> +  QUOTA_USAGE_TOTAL_STORAGE = "quota_utilization_total_storage"
> +  QUOTA_USAGE_OVERALL = "quota_utilization_overall"
> +
>    def initialize
>      @svg = ""
>    end
> +
> +  def self.get_quota_usage_graph_name(resource_name)
> +    case resource_name
> +      when Quota::RESOURCE_RUNNING_INSTANCES
> +        return QUOTA_USAGE_RUNNING_INSTANCES
> +      when Quota::RESOURCE_RUNNING_MEMORY
> +        return QUOTA_USAGE_RUNNING_MEMORY
> +      when  Quota::RESOURCE_RUNNING_CPUS
> +        return QUOTA_USAGE_RUNNING_CPUS
> +      when Quota::RESOURCE_TOTAL_INSTANCES
> +        return QUOTA_USAGE_TOTAL_INSTANCES
> +      when Quota::RESOURCE_TOTAL_STORAGE
> +        return QUOTA_USAGE_TOTAL_STORAGE
> +      when Quota::RESOURCE_OVERALL
> +        return QUOTA_USAGE_OVERALL
> +      else
> +        return nil
> +    end
> +  end
>  end
> diff --git a/src/app/services/graph_service.rb 
> b/src/app/services/graph_service.rb
> index 11da01c..6c17743 100644
> --- a/src/app/services/graph_service.rb
> +++ b/src/app/services/graph_service.rb
> @@ -3,6 +3,8 @@ class GraphService
>    require 'nokogiri'
>    require 'scruffy'
>  
> +  DATA_SERVICE = DataServiceActiveRecord
> +
>    def self.dashboard_quota (user,opts = {})
>      #FIXME add permission checks to filter what graphs user can get
>      graphs = Hash.new
> @@ -12,7 +14,7 @@ class GraphService
>      if opts[:cloud_account]
>        cloud_account = opts[:cloud_account]
>        cloud_account_graphs = Hash.new
> -      cloud_account_graphs[Graph::QUOTA_INSTANCES_IN_USE] = 
> quota_instances_in_use_graph(cloud_account,opts)
> +      cloud_account_graphs[Graph::QUOTA_INSTANCES_IN_USE] = 
> qos_failure_rate_graph(parent, opts = {})
>        graphs[cloud_account] = cloud_account_graphs
>      else
>        CloudAccount.all.each do |cloud_account|
> @@ -24,7 +26,16 @@ class GraphService
>      graphs
>    end
>  
> -  def self.dashboard_qos (user,opts = {})
> +  def self.dashboard_quota_usage(user, opts = {})
> +    parent = opts[:parent]
> +
> +    graphs = Hash.new
> +    graphs[parent] = quota_usage_graph(parent, opts)
> +
> +    return graphs
> +  end
> +
> +  def self.dashboard_qos_avg_time_to_submit_graph(user, opts = {})
>      #FIXME add permission checks to filter what graphs user can get
>      graphs = Hash.new
>  
> @@ -58,7 +69,198 @@ class GraphService
>      output_stream = IO::popen( cmd, "r+")
>    end
>  
> -  def self.quota_instances_in_use_graph (cloud_account, opts = {})
> +  def self.quota_usage_graph (parent, opts = {})
> +    x = [1,2]
> +
> +    #we'll just have zero values for the unexpected case where cloud_account 
> has no quota
> +    y = x.collect { |v| 0 }
> +    if parent.quota
> +      quota = parent.quota
> +      data_point = DataServiceActiveRecord.quota_usage(parent, 
> opts[:resource_name])
> +      #Handle No Limit case
> +      if data_point.max == Quota::NO_LIMIT
> +        y = [data_point.used, nil]
> +      else
> +        y = [data_point.used, data_point.max]
> +      end
> +    end
> +
> +    chart_opts = {:x => x, :y => y}
> +
> +    graphs = Hash.new
> +    graphs[Graph.get_quota_usage_graph_name(opts[:resource_name])] = 
> draw_bar_chart(opts, chart_opts)
> +    return graphs
> +  end
> +
> +  def self.qos_avg_time_to_submit_graph(parent, opts = {})
> +    start_time = Time.parse(opts[:start_time])
> +    end_time = Time.parse(opts[:end_time])
> +    interval_length = opts[:interval_length].to_f
> +    action = opts[:task_action]
> +
> +    stats = DATA_SERVICE.qos_task_submission_stats(parent, start_time, 
> end_time, interval_length, action)
> +    data = get_data_from_stats(stats, "average")
> +    draw_line_graph(opts, data)
> +  end
> +
> +  def self.qos_failure_rate_graph(parent, opts = {})
> +    start_time = Time.parse(opts[:start_time])
> +    end_time = Time.parse(opts[:end_time])
> +    interval_length = opts[:interval_length].to_f
> +    failure_code = opts[:failure_code]
> +
> +    stats = DATA_SERVICE.qos_failure_rate_stats(parent, start_time, 
> end_time, interval_length, failure_code)
> +    data = get_data_from_stats(stats, "failure_rate")
> +    data[:y_range] = "[0:100]"
> +    draw_line_graph(opts, data)
> +  end
> +
> +  def self.qos_avg_time_to_complete_life_cycle_event(parent, opts = {})
> +    start_time = Time.parse(opts[:start_time])
> +    end_time = Time.parse(opts[:end_time])
> +    interval_length = opts[:interval_length].to_f
> +    action = opts[:task_action]
> +
> +    stats = DATA_SERVICE.qos_task_completion_stats(parent, start_time, 
> end_time, interval_length, action)
> +    data = get_data_from_stats(stats, "average")
> +    draw_line_graph(opts, data)
> +  end
> +
> +  def self.instances_by_provider_pie (opts = {})
> +    pie_opts = {}
> +    providers = Provider.all
> +    providers.each do |provider|
> +      running_instances = 0
> +      provider.cloud_accounts.each do |account|
> +        running_instances = running_instances + 
> account.quota.running_instances if account.quota
> +      end
> +      if running_instances > 0
> +        pie_opts[:"#{provider.name}"] = running_instances
> +      end
> +    end
> +
> +    return draw_pie_chart(opts, pie_opts)
> +  end
> +
> +  def self.get_data_from_stats(stats, type)
> +    x = []
> +    y = []
> +    y_max = 0
> +    for i in 0...stats.length do
> +      x << i
> +      y_value = stats[i][type]
> +      if y_value
> +        y << y_value
> +        if y_value > y_max
> +          y_max = y_value
> +        end
> +      else
> +        y << 0
> +      end
> +    end
> +
> +    if y_max == 0
> +      y_max = 1
> +    else
> +      y_max = y_max * 1.1
> +    end
> +
> +    y_range = "[0:" + y_max.to_s + "]"
> +    return { :x => x, :y => y, :y_range => y_range }
> +  end
> +
> +  def self.draw_pie_chart(opts, pie_opts)
> +    #things we're checking for in opts: :height, :width
> +    height = 200 unless opts[:height].nil? ? nil : height = 
> opts[:height].to_i
> +    width =  300 unless  opts[:width].nil? ? nil : width  = opts[:width].to_i
> +
> +    graph = Graph.new
> +
> +    mytheme = Scruffy::Themes::Keynote.new
> +    mytheme.background = :white
> +    mytheme.marker = :black #sets the label text color
> +    mytheme.colors = %w(#00689a #00b0e0)
> +
> +    scruffy_graph = Scruffy::Graph.new({:theme => mytheme})
> +    scruffy_graph.renderer = Scruffy::Renderers::Pie.new
> +    scruffy_graph.add :pie, '', pie_opts
> +
> +    raw_svg = scruffy_graph.render :width => width, :height => height
> +
> +    xml = Nokogiri::XML(raw_svg)
> +    svg = xml.css 'svg'
> +    svg.each do |node|
> +      node.set_attribute 'viewBox',"0 0 #{width} #{height}"
> +    end
> +
> +    xml.root.traverse do |node|
> +      if node.name == 'text'
> +        if node.has_attribute? 'font-family'
> +          node.set_attribute 'font-family','sans-serif'
> +        end
> +        if (node.has_attribute? 'font-size') && 
> node.get_attribute('font-size').length > 0
> +          size = node.get_attribute('font-size').to_f
> +          size = size * 1.5
> +          node.set_attribute 'font-size',size.to_s
> +        end
> +      end
> +    end
> +
> +    graph.svg = xml.to_s
> +    graph
> +  end
> +
> +  def self.draw_line_graph(opts, data)
> +    #things we're checking for in opts: :height, :width
> +
> +    height = 60 unless opts[:height].nil? ? nil : height = opts[:height].to_i
> +    width = 100 unless  opts[:width].nil? ? nil : width  = opts[:width].to_i
> +
> +    graph = Graph.new
> +    gp = gnuplot_open
> +
> +    Gnuplot::Plot.new( gp ) do |plot|
> +      plot.terminal "svg size #{width},#{height}"
> +      plot.arbitrary_lines << "unset xtics"
> +      plot.arbitrary_lines << "unset x2tics"
> +      plot.arbitrary_lines << "unset ytics"
> +      plot.arbitrary_lines << "unset y2tics"
> +      plot.set "bmargin","0"
> +      plot.set "lmargin","1"
> +      plot.set "rmargin","0"
> +      plot.set "tmargin","0"
> +
> +      #FIXME: get data from DataService for the provider.
> +      #For demo, plot a random walk for demo of graph display until we hook 
> into DataService
> +      #First build two equal-length arrays
> +      #x = (0..500).collect { |v| v.to_f }
> +
> +      #walk = 0
> +      #y = x.collect { |v| rand > 0.5 ? walk = walk + 1 : walk = walk - 1 }
> +
> +      x = data[:x]
> +      y = data[:y]
> +      y_range = data[:y_range]
> +
> +      #plot.set "yrange [-50:50]"
> +      plot.set "yrange " + y_range
> +
> +      #This type of plot takes two equal length arrays of numbers as input.
> +      plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
> +        ds.using = "1:2"
> +        ds.with = "lines"
> +        ds.notitle
> +      end
> +    end
> +    gp.flush
> +    gp.close_write
> +    gp.read(nil,graph.svg)
> +    gp.close_read
> +    graph
> +  end
> +
> +  def self.draw_bar_chart(opts, chart_opts)
> +
>      #things we're checking for in opts: :max_value, :height, :width
>  
>      unless max_value = opts[:max_value]
> @@ -67,7 +269,6 @@ class GraphService
>      height = 80 unless opts[:height].nil? ? nil : height = opts[:height].to_i
>      width = 150 unless  opts[:width].nil? ? nil : width  = opts[:width].to_i
>  
> -
>      raw_svg = ""
>      gp = gnuplot_open
>      Gnuplot::Plot.new( gp ) do |plot|
> @@ -87,14 +288,8 @@ class GraphService
>        plot.set "xrange [.25:2.75]"
>        plot.set "yrange [0:#{max_value * 1.5}]" #we want to scale maxvalue 
> 50% larger to leave room for label
>  
> -      x = [1,2]
> -      #we'll just have zero values for the unexpected case where 
> cloud_account has no quota
> -      y = x.collect { |v| 0 }
> -      if cloud_account.quota
> -        quota = cloud_account.quota
> -        y = [quota.running_instances,quota.maximum_running_instances]
> -      end
> -
> +      x = chart_opts[:x]
> +      y = chart_opts[:y]
>  
>        #The two arrays above are three columns of data for gnuplot.
>        plot.data << Gnuplot::DataSet.new( [[x[0]], [y[0]]] ) do |ds|
> @@ -155,105 +350,6 @@ class GraphService
>      graph = Graph.new
>      graph.svg = modified_svg
>      graph
> -
> -  end
> -
> -  def self.qos_avg_time_to_submit_graph (provider, opts = {})
> -    #things we're checking for in opts: :height, :width
> -
> -    height = 60 unless opts[:height].nil? ? nil : height = opts[:height].to_i
> -    width = 100 unless  opts[:width].nil? ? nil : width  = opts[:width].to_i
> -
> -    graph = Graph.new
> -    gp = gnuplot_open
> -
> -    Gnuplot::Plot.new( gp ) do |plot|
> -      plot.terminal "svg size #{width},#{height}"
> -      plot.arbitrary_lines << "unset xtics"
> -      plot.arbitrary_lines << "unset x2tics"
> -      plot.arbitrary_lines << "unset ytics"
> -      plot.arbitrary_lines << "unset y2tics"
> -      plot.set "bmargin","0"
> -      plot.set "lmargin","1"
> -      plot.set "rmargin","0"
> -      plot.set "tmargin","0"
> -
> -      #FIXME: get data from DataService for the provider.
> -      #For demo, plot a random walk for demo of graph display until we hook 
> into DataService
> -      #First build two equal-length arrays
> -      x = (0..500).collect { |v| v.to_f }
> -
> -      walk = 0
> -      y = x.collect { |v| rand > 0.5 ? walk = walk + 1 : walk = walk - 1 }
> -      plot.set "yrange [-50:50]"
> -
> -      #This type of plot takes two equal length arrays of numbers as input.
> -      plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
> -        ds.using = "1:2"
> -        ds.with = "lines"
> -        ds.notitle
> -      end
> -    end
> -    gp.flush
> -    gp.close_write
> -    gp.read(nil,graph.svg)
> -    gp.close_read
> -    graph
> -  end
> -
> -  def self.instances_by_provider_pie (opts = {})
> -    #things we're checking for in opts: :height, :width
> -
> -    height = 200 unless opts[:height].nil? ? nil : height = 
> opts[:height].to_i
> -    width =  300 unless  opts[:width].nil? ? nil : width  = opts[:width].to_i
> -
> -    graph = Graph.new
> -
> -    mytheme = Scruffy::Themes::Keynote.new
> -    mytheme.background = :white
> -    mytheme.marker = :black #sets the label text color
> -    mytheme.colors = %w(#00689a #00b0e0)
> -
> -    scruffy_graph = Scruffy::Graph.new({:theme => mytheme})
> -    scruffy_graph.renderer = Scruffy::Renderers::Pie.new
> -
> -    pie_opts = {}
> -    providers = Provider.all
> -    providers.each do |provider|
> -      running_instances = 0
> -      provider.cloud_accounts.each do |account|
> -        running_instances = running_instances + 
> account.quota.running_instances if account.quota
> -      end
> -      if running_instances > 0
> -        pie_opts[:"#{provider.name}"] = running_instances
> -      end
> -    end
> -
> -    scruffy_graph.add :pie, '', pie_opts
> -
> -    raw_svg = scruffy_graph.render :width => width, :height => height
> -
> -    xml = Nokogiri::XML(raw_svg)
> -    svg = xml.css 'svg'
> -    svg.each do |node|
> -      node.set_attribute 'viewBox',"0 0 #{width} #{height}"
> -    end
> -
> -    xml.root.traverse do |node|
> -      if node.name == 'text'
> -        if node.has_attribute? 'font-family'
> -          node.set_attribute 'font-family','sans-serif'
> -        end
> -        if (node.has_attribute? 'font-size') && 
> node.get_attribute('font-size').length > 0
> -          size = node.get_attribute('font-size').to_f
> -          size = size * 1.5
> -          node.set_attribute 'font-size',size.to_s
> -        end
> -      end
> -    end
> -
> -    graph.svg = xml.to_s
> -    graph
>    end
>  
> -end
> +end
> \ No newline at end of file
> diff --git a/src/app/views/dashboard/summary.haml 
> b/src/app/views/dashboard/summary.haml
> index 66aedde..f3a21d3 100644
> --- a/src/app/views/dashboard/summary.haml
> +++ b/src/app/views/dashboard/summary.haml
> @@ -60,7 +60,11 @@
>          %div{ :style => "clear:both"}
>        - @providers.each do |provider|
>          .provider_service_quality_graph
> -          = "<object data='" + url_for(:action => :provider_qos_graph, :id 
> => provider.id, :width => 100, :height => 50) + "' type='image/svg+xml' />"
> +          -end_time = Time.now
> +          -start_time = end_time - (24 * 60 * 60)
> +          -interval_length = 3600
> +          -task_action = "create"
> +          = "<object data='" + url_for(:action => 
> :provider_qos_avg_time_to_submit_graph, :id => provider.id, :start_time => 
> start_time, :end_time => end_time, :interval_length => interval_length, 
> :task_action => task_action, :width => 100, :height => 50) + "' 
> type='image/svg+xml' />"
>          .provider_service_quality_graph_summary
>            = provider.name
>            <!-- FIXME 'good/poor/average service... -->
> @@ -109,7 +113,7 @@
>        .account_quota_usage_graph_summary
>          = account.provider.name + ": " + account.name
>        .account_quota_usage_current_graph
> -        %object{ :data => url_for(:action => :account_quota_graph, :id => 
> account.id, :width => 100, :height => 50), :type => 'image/svg+xml'}
> +        %object{ :data => url_for(:action => :quota_usage_graph, 
> :cloud_account_id => account.id, :resource_name => 
> Quota::RESOURCE_RUNNING_INSTANCES, :width => 100, :height => 50), :type => 
> 'image/svg+xml'}
>        <div style="clear: both;" />
>  
>  :javascript
> -- 
> 1.7.1.1
> 
> _______________________________________________
> deltacloud-devel mailing list
> [email protected]
> https://fedorahosted.org/mailman/listinfo/deltacloud-devel

ACK, sir!
_______________________________________________
deltacloud-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/deltacloud-devel

Reply via email to