On Fri, Jun 04, 2010 at 07:12:52PM +0000, [email protected] wrote: > From: martyntaylor <[email protected]> > > --- > src/app/services/data_service.rb | 112 +++++++++++++++++++++++ > src/spec/services/data_service_spec.rb | 157 > ++++++++++++++++++++++++++++++++ > 2 files changed, 269 insertions(+), 0 deletions(-) > create mode 100644 src/app/services/data_service.rb > create mode 100644 src/spec/services/data_service_spec.rb > > diff --git a/src/app/services/data_service.rb > b/src/app/services/data_service.rb > new file mode 100644 > index 0000000..6465f2e > --- /dev/null > +++ b/src/app/services/data_service.rb > @@ -0,0 +1,112 @@ > +class DataService > + > + QoSDataPoint = Struct.new(:time, :average, :max, :min) > + QuotaUsagePoint = Struct.new(:used, :max) > + TotalQuotaUsagePoint = Struct.new(:name, :no_instances) > + > + # This will return array of data points between start and end, if there is > a data point where the interval start + interval end > + # is greater than the end time, it will be ignored > + # Example: > + # start = 12.30, end = 12.32, interval = 45secs > + # Intervals: 12.30.00 - 12.30.45, 12.30.45 - 12.31.30 will be returned. > Interval 12.31.30 - 12.32.15 will not > + def self.qos_task_submission_stats(start_time, end_time, interval_length, > parent, action) > + > + instances = [] > + > + if parent.class == Provider > + cloud_accounts = CloudAccount.find(:all, :conditions => {:provider_id > => parent.id}) > + cloud_accounts.each do |cloud_account| > + instances.concat(instances) > + end > + elsif parent.class == Pool || parent.class == CloudAccount > + instances = parent.instances > + else > + return nil > + end > + > + return calculate_qos_task_submission_stats(start_time, end_time, > interval_length, instances, action) > + end > + > + def self.tasks_submissions_mean_max_min(time, tasks) > + > + first_pass = true > + > + total_time = nil > + maximum_time = nil > + minimum_time = nil > + > + tasks.each do |task| > + > + if(first_pass == true) > + total_time = task.submission_time > + maximum_time = task.submission_time > + minimum_time = task.submission_time > + first_pass = false > + else > + total_time += task.submission_time > + > + if task.submission_time > maximum_time > + maximum_time = task.submission_time > + end > + > + if task.submission_time< minimum_time > + minimum_time = task.submission_time > + end > + end > + > + end > + average_time = total_time / tasks.length > + > + return QoSDataPoint.new(time, average_time, maximum_time, minimum_time) > + end > + > + # Returns the Used and Maximum Number of Instances in Quota > + def self.quota_utilisation(parent) > + quota = parent.quota > + if quota > + return QuotaUsagePoint.new(quota.total_instances, > quota.maximum_total_instances) > + end > + end > + > + def self.total_quota_utilisation(provider) > + data_points = [] > + free_instances = 0 > + > + cloud_accounts = CloudAccount.find(:all, :conditions => {:provider_id => > provider.id}) > + cloud_accounts.each do |cloud_account| > + quota = cloud_account.quota > + if quota > + data_points << TotalQuotaUsagePoint.new(cloud_account.username, > quota.total_instances) > + free_instances += (quota.maximum_total_instances - > quota.total_instances) > + end > + end > + data_points << TotalQuotaUsagePoint.new("free", free_instances) > + return data_points > + end > + > + private > + def self.calculate_qos_task_submission_stats(start_time, end_time, > interval_length, instances, action) > + > + data = [] > + until start_time > (end_time - interval_length) do > + interval_time = start_time + interval_length > + > + tasks = Task.find(:all, :conditions => { :time_submitted => > start_time..interval_time, > + :time_started => > start_time..Time.now, > + :failure_code => nil, > + :action => action, > + :task_target_id => instances > + }) > + if tasks.length > 0 > + data << tasks_submissions_mean_max_min(start_time, tasks) > + else > + data << QoSDataPoint.new(start_time, 0, 0, 0) > + end > + > + start_time = interval_time > + end > + > + return data > + end > + > +end > diff --git a/src/spec/services/data_service_spec.rb > b/src/spec/services/data_service_spec.rb > new file mode 100644 > index 0000000..f69f8e8 > --- /dev/null > +++ b/src/spec/services/data_service_spec.rb > @@ -0,0 +1,157 @@ > +require 'spec_helper' > + > +describe DataService do > + > + it "should calculate the quota usage for a provider with a numbner of > cloud accounts" do > + client = mock('DeltaCloud', :null_object => true) > + provider = Factory.build(:mock_provider) > + provider.stub!(:connect).and_return(client) > + provider.save! > + > + data = [[25, 10], [40, 20], [20, 20]] > + free = 0 > + for i in 0..2 > + cloud_account = Factory.build(:cloud_account, :provider => provider, > :username => "username" + i.to_s) > + cloud_account.stub!(:valid_credentials?).and_return(true) > + cloud_account.save! > + > + quota = Factory(:quota, :maximum_total_instances => data[i][0], > :total_instances => data[i][1]) > + cloud_account.quota_id = quota.id > + cloud_account.save! > + > + free += (data[i][0] - data[i][1]) > + end > + > + data_points = DataService.total_quota_utilisation(provider) > + data_points[0].should == > DataService::TotalQuotaUsagePoint.new("username0", data[0][1]) > + data_points[1].should == > DataService::TotalQuotaUsagePoint.new("username1", data[1][1]) > + data_points[2].should == > DataService::TotalQuotaUsagePoint.new("username2", data[2][1]) > + data_points[3].should == DataService::TotalQuotaUsagePoint.new("free", > free) > + > + end > + > + it "should calculate the total number of instances and maximum numbder of > instances of a cloud account" do > + client = mock('DeltaCloud', :null_object => true) > + provider = Factory.build(:mock_provider) > + provider.stub!(:connect).and_return(client) > + provider.save! > + > + cloud_account = Factory.build(:cloud_account, :provider => provider) > + cloud_account.stub!(:valid_credentials?).and_return(true) > + cloud_account.save! > + > + quota = Factory(:quota, :maximum_total_instances => 50, :total_instances > => 20) > + cloud_account.quota_id = quota.id > + > + data_point = DataService.quota_utilisation(cloud_account) > + data_point.should == DataService::QuotaUsagePoint.new(20, 50) > + end > + > + it "should calculate the average, max and min task submission times" do > + tasks = [] > + instance = Factory :instance > + > + for i in 1..10 do > + time = Time.utc(2010,"jan",1,20,15,1) > + task = Task.new(:instance => instance, :type => "InstanceTask", :state > => Task::STATE_PENDING, :failure_code => nil) > + task.time_submitted = time > + time += i > + task.time_started = time > + task.save > + tasks << task > + end > + > + data_point = DataService.tasks_submissions_mean_max_min(Time.now, tasks) > + > + data_point.average.should == 5.5 > + data_point.min.should == 1 > + data_point.max.should == 10 > + end > + > + it "should create data points for the average, max and min task submission > times between two times at given intervals" do > + pool = Factory :pool > + instance = Factory(:instance, :pool_id => pool.id) > + > + expected_averages = [ 20, 40, 60, 80, 100] > + no_intervals = expected_averages.length > + interval_length = 30 > + > + end_time = Time.utc(2010,"jan",1,20,15,1) > + start_time = end_time - (interval_length * no_intervals) > + > + generate_tasks(start_time, interval_length, instance, expected_averages) > + > + data_points = DataService.qos_task_submission_stats(start_time, > end_time, interval_length, pool, InstanceTask::ACTION_CREATE) > + > + for i in 0...data_points.length > + average_time = expected_averages[i] > + dp = data_points[i] > + > + dp.average.should == average_time > + # The multiplications could be set as static numbers but are left as > calculations for easier understanding of code > + dp.max.should == (average_time / 10) * 2 * 9 > + dp.min.should == (average_time / 10) * 2 > + end > + end > + > + it "should create data points for mean, max and min task submission times > at given intervals for a provider with multiple accounts" do > + pool = Factory :pool > + > + expected_averages = [] > + expected_averages[0] = [ 20, 40, 60, 80, 100] > + expected_averages[1] = [ 40, 60, 80, 100, 120] > + expected_averages[2] = [ 60, 80, 100, 120, 140] > + > + no_intervals = expected_averages.length > + interval_length = 30 > + end_time = Time.utc(2010,"jan",1,20,15,1) > + start_time = end_time - (interval_length * no_intervals) > + > + client = mock('DeltaCloud', :null_object => true) > + provider = Factory.build(:mock_provider) > + provider.stub!(:connect).and_return(client) > + provider.save! > + > + cloud_accounts = [] > + expected_averages.each do |expected_average| > + cloud_account = Factory.build(:cloud_account, :provider => provider, > :username => "username" + expected_average[0].to_s) > + cloud_account.stub!(:valid_credentials?).and_return(true) > + cloud_account.save! > + > + instance = Factory(:instance, :cloud_account_id => cloud_account.id, > :pool_id => pool.id) > + generate_tasks(start_time, interval_length, instance, expected_average) > + end > + > + data_points = DataService.qos_task_submission_stats(start_time, > end_time, interval_length, pool, InstanceTask::ACTION_CREATE) > + > + for i in 0...data_points.length > + dp = data_points[i] > + dp.average.should == expected_averages[1][i] > + dp.max.should == (expected_averages[2][i] / 10) * 2 * 9 > + dp.min.should == (expected_averages[0][i] / 10) * 2 > + end > + end > + > + def generate_tasks(start_time, interval_length, instance, > expected_averages) > + interval_time = start_time > + expected_averages.each do |avg| > + submission_time = interval_time + (interval_length / 2) > + for i in 1..9 do > + started_time = submission_time + ((avg / 10) * 2) * i > + > + task = InstanceTask.new(:instance => instance, > + :type => "InstanceTask", > + :state => Task::STATE_QUEUED, > + :failure_code => nil, > + :action => InstanceTask::ACTION_CREATE, > + :task_target_id => instance.id) > + task.created_at = submission_time > + task.time_submitted = submission_time > + task.time_started = started_time > + task.save! > + end > + interval_time += interval_length > + end > + end > + > +end > -- > 1.6.6.1 > > _______________________________________________ > deltacloud-devel mailing list > [email protected] > https://fedorahosted.org/mailman/listinfo/deltacloud-devel
ACK! Thanks, Steve. _______________________________________________ deltacloud-devel mailing list [email protected] https://fedorahosted.org/mailman/listinfo/deltacloud-devel
