naf 2.1.6 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. data/Gemfile +0 -1
  2. data/README.rdoc +3 -3
  3. data/RELEASE_NOTES.rdoc +19 -0
  4. data/app/controllers/naf/api_simple_cluster_authenticator_application_controller.rb +9 -0
  5. data/app/controllers/naf/application_controller.rb +18 -1
  6. data/app/controllers/naf/log_parsers_controller.rb +11 -7
  7. data/app/models/logical/naf/construction_zone/boss.rb +21 -13
  8. data/app/models/logical/naf/construction_zone/foreman.rb +1 -1
  9. data/app/models/logical/naf/construction_zone/proletariat.rb +9 -1
  10. data/app/models/logical/naf/user_session.rb +53 -0
  11. data/app/models/naf/application_schedule.rb +14 -3
  12. data/app/models/naf/application_type.rb +7 -1
  13. data/app/models/naf/machine.rb +4 -4
  14. data/app/models/process/naf/log_archiver.rb +2 -1
  15. data/app/models/process/naf/log_archiver_queuer.rb +25 -0
  16. data/app/models/process/naf/logger/base.rb +0 -2
  17. data/app/views/naf/log_viewer/_log_display.html.erb +6 -1
  18. data/lib/naf.rb +16 -4
  19. data/lib/naf/configuration.rb +9 -3
  20. data/lib/naf/version.rb +1 -1
  21. data/naf.gemspec +2 -2
  22. data/spec/controllers/naf/application_controller_spec.rb +1 -1
  23. data/spec/factories/naf.rb +39 -0
  24. data/spec/models/logical/naf/construction_zone/boss_rspec.rb +119 -0
  25. data/spec/models/logical/naf/construction_zone/foreman_spec.rb +105 -0
  26. data/spec/models/logical/naf/construction_zone/proletariat_spec.rb +67 -0
  27. data/spec/models/logical/naf/construction_zone/work_order_spec.rb +2 -1
  28. data/spec/models/logical/naf/user_session_spec.rb +92 -0
  29. data/spec/models/naf/application_schedule_spec.rb +61 -0
  30. data/spec/models/naf/machine_spec.rb +5 -3
  31. metadata +13 -4
data/Gemfile CHANGED
@@ -13,7 +13,6 @@ gem 'will_paginate'
13
13
  gem 'facter'
14
14
  gem 'shoulda-matchers', '2.0.0'
15
15
  gem 'timecop', '0.4.5'
16
- gem 'open4'
17
16
  gem 'yajl-ruby'
18
17
  gem 'aws-sdk'
19
18
  gem 'fiksu-af'
data/README.rdoc CHANGED
@@ -40,8 +40,8 @@ Machines have an allocate-able number of slots of a specific affinity. Applicati
40
40
  === Tags
41
41
  Scripts have tags to describe the stage/progress of the process. They can be system or custom tags. All tags are visible by the user, so set tags at different stages of your script. This is a way of knowing what is happening in the script without having to take a look at the logs.
42
42
 
43
-
44
43
  === Please find up-to-date information on Naf here: {Naf Wiki}[http://www.github.com/fiksu/naf/wiki]
45
- === Instructions on upgrading to Naf v1.1.4: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-to-Naf-v1.1.4]
44
+ === Instructions on upgrading to Naf v2.1.8: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-from-Naf-v2.1.6-to-Naf-v2.1.8]
45
+ === Instructions on upgrading to Naf v2.1.6: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-to-Naf-v2.1.6]
46
46
  === Instructions on upgrading to Naf v2.0: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-to-Naf-v2.0]
47
- === Instructions on upgrading to Naf v2.1: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-to-Naf-v2.1]
47
+ === Instructions on upgrading to Naf v1.1.4: {Instructions}[https://github.com/fiksu/naf/wiki/Upgrading-to-Naf-v1.1.4]
data/RELEASE_NOTES.rdoc CHANGED
@@ -1,5 +1,24 @@
1
1
  = Release Notes
2
2
 
3
+ === Version 2.1.8
4
+ Bug fixes:
5
+ * Removed check for signed message. Encrypted data generated by ActiveSupport::MessageVerifier is different depending on the ruby version.
6
+
7
+ === Version 2.1.7
8
+ Bug fixes:
9
+ * Boss#enqueue_command had the first two parameters switched
10
+ * Boss#enqueue_n_commands referenced a machine object, but that object did not exist in the scope
11
+ * Boss#enqueue_n_commands called job_affinity_tabs on a job when it should be calling historical_job_affinity_tabs
12
+ * Foreman#limited_by_run_group? checked the affinity_classification_name of an affinity, but did not check if the affinity was null
13
+ * Job exit status always set to 0, even after the job errors
14
+ * Unnecessary 'open4' require statements
15
+ * Deleted application still runs if it has an enabled schedule
16
+ * LogArchiver did not delete empty folders
17
+
18
+ Changes:
19
+ * Created a log archival queuer script
20
+ * Created Api Authenticator for logs
21
+
3
22
  === Version 2.1.6
4
23
  Bug fixes:
5
24
  * Historical jobs application_schedule_id was not getting set, causing the runner to constantly queue applications.
@@ -0,0 +1,9 @@
1
+ module Naf
2
+ class ApiSimpleClusterAuthenticatorApplicationController < ActionController::Base
3
+
4
+ def naf_cookie_valid?
5
+ ::Logical::Naf::UserSession.new(session[::Naf.configuration.api_domain_cookie_name]).valid?
6
+ end
7
+
8
+ end
9
+ end
@@ -1,11 +1,13 @@
1
1
  module Naf
2
- class ApplicationController < Naf.controller_class
2
+ class ApplicationController < Naf.ui_controller_class
3
3
  layout Naf.layout
4
4
 
5
5
  require 'will_paginate/array'
6
6
 
7
7
  protect_from_forgery
8
8
 
9
+ before_filter :check_naf_cookie_presence
10
+
9
11
  protected
10
12
 
11
13
  # Sets current rows_per_page direction from cookies or params.
@@ -39,5 +41,20 @@ module Naf
39
41
  end
40
42
  cookies[:search_status] = @search_status
41
43
  end
44
+
45
+ private
46
+
47
+ def check_naf_cookie_presence
48
+ user_session = ::Logical::Naf::UserSession.new(session[domain_cookie_name])
49
+ if !user_session.valid?
50
+ session.delete(domain_cookie_name)
51
+ session[domain_cookie_name] = user_session.token_cookie
52
+ end
53
+ end
54
+
55
+ def domain_cookie_name
56
+ @domain_cookie_name ||= ::Naf.configuration.api_domain_cookie_name
57
+ end
58
+
42
59
  end
43
60
  end
@@ -1,15 +1,19 @@
1
1
  module Naf
2
- class LogParsersController < Naf::ApplicationController
2
+ class LogParsersController < Naf::ApiSimpleClusterAuthenticatorApplicationController
3
3
 
4
4
  def logs
5
- response = params['logical_type'].constantize.new(params).logs
6
- if response.present?
7
- success = true
5
+ if naf_cookie_valid?
6
+ response = params['logical_type'].constantize.new(params).logs
7
+ if response.present?
8
+ success = true
9
+ else
10
+ success = false
11
+ end
12
+
13
+ render json: "convertToJsonCallback(" + { success: success }.merge(response).to_json + ")"
8
14
  else
9
- success = false
15
+ render json: "convertToJsonCallback(" + { success: false }.to_json + ")"
10
16
  end
11
-
12
- render json: "convertToJsonCallback(" + { success: success }.merge(response).to_json + ")"
13
17
  end
14
18
 
15
19
  end
@@ -60,8 +60,8 @@ module Logical::Naf::ConstructionZone
60
60
  affinities = [],
61
61
  prerequisites = [],
62
62
  enqueue_backlogs = false)
63
- work_order = WorkOrder.new(application_type,
64
- command,
63
+ work_order = WorkOrder.new(command,
64
+ application_type,
65
65
  application_run_group_restriction,
66
66
  application_run_group_name,
67
67
  application_run_group_limit,
@@ -79,22 +79,18 @@ module Logical::Naf::ConstructionZone
79
79
 
80
80
  def enqueue_n_commands_on_machines(parameters, number_of_jobs = :from_limit, machines = [])
81
81
  logger.detail "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machines.length} machine(s)"
82
+ # enqueue the command on each machine
82
83
  machines.each do |machine|
83
84
  number_of_jobs = (parameters[:application_run_group_quantum] || 1) if number_of_jobs == :from_limit
84
85
  logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
86
+ # enqueue the command number_of_jobs times
85
87
  (1..number_of_jobs).each do
86
88
  machine_parameters = {
87
89
  application_run_group_restriction: ::Naf::ApplicationRunGroupRestriction.limited_per_machine
88
90
  }.merge(parameters)
89
- machine_parameters[:affinities] =
90
- [machine.affinity] + if machine_parameters[:affinities].nil?
91
- []
92
- elsif machine_parameters[:affinities].is_a? Array
93
- machine_parameters[:affinities]
94
- else
95
- [machine_parameters[:affinities]]
96
- end
97
- work_order = AdHocWorkOrder.new(machine_parameters)
91
+ machine_parameters[:affinities] = [machine.affinity] + affinities(machine_parameters)
92
+ work_order = AdHocWorkOrder.new(machine_parameters)
93
+
98
94
  @foreman.enqueue(work_order)
99
95
  end
100
96
  end
@@ -102,7 +98,7 @@ module Logical::Naf::ConstructionZone
102
98
 
103
99
  def enqueue_n_commands(parameters, number_of_jobs = :from_limit)
104
100
  number_of_jobs = (parameters[:application_run_group_quantum] || 1) if number_of_jobs == :from_limit
105
- logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s) on #{machine}"
101
+ logger.info "enqueuing #{parameters[:command]} #{number_of_jobs} time(s)"
106
102
  (1..number_of_jobs).each do
107
103
  work_order = AdHocWorkOrder.new(parameters)
108
104
  @foreman.enqueue(work_order)
@@ -115,7 +111,19 @@ module Logical::Naf::ConstructionZone
115
111
  job.application_run_group_name,
116
112
  job.application_run_group_limit,
117
113
  job.priority,
118
- job.job_affinity_tabs.map{|jat| jat.affinity})
114
+ job.historical_job_affinity_tabs.map{|jat| jat.affinity})
115
+ end
116
+
117
+ private
118
+
119
+ def affinities(params)
120
+ if params[:affinities].nil?
121
+ []
122
+ elsif params[:affinities].is_a? Array
123
+ params[:affinities]
124
+ else
125
+ [params[:affinities]]
126
+ end
119
127
  end
120
128
 
121
129
  end
@@ -32,7 +32,7 @@ module Logical::Naf::ConstructionZone
32
32
  machine_affinity = nil
33
33
  affinities.each do |affinity|
34
34
  machine_affinity = ::Naf::Affinity.find_by_id(affinity[:affinity_id])
35
- if machine_affinity.affinity_classification_name == 'machine'
35
+ if machine_affinity.present? && machine_affinity.affinity_classification_name == 'machine'
36
36
  break
37
37
  end
38
38
  end
@@ -3,7 +3,8 @@ module Logical::Naf::ConstructionZone
3
3
  def create_job(parameters, affinities, prerequisites)
4
4
  ::Naf::HistoricalJob.transaction do
5
5
  historical_job = create_historical_job(parameters, affinities, prerequisites)
6
- queued_job = create_queued_job(historical_job)
6
+ create_queued_job(historical_job)
7
+
7
8
  return historical_job
8
9
  end
9
10
  end
@@ -11,16 +12,20 @@ module Logical::Naf::ConstructionZone
11
12
  def create_historical_job(parameters, affinities, prerequisites)
12
13
  ::Naf::HistoricalJob.transaction do
13
14
  historical_job = ::Naf::HistoricalJob.create!(parameters)
15
+ # Create affinity tabs, if affinities are provided
14
16
  affinities.each do |affinity|
15
17
  ::Naf::HistoricalJobAffinityTab.create(affinity.merge(historical_job_id: historical_job.id))
16
18
  end
19
+ # Verify there is no loop found in prerequisites
17
20
  historical_job.verify_prerequisites(prerequisites)
21
+ # Create historical job prerequesites, if prerequisites are provided
18
22
  prerequisites.each do |prerequisite|
19
23
  ::Naf::HistoricalJobPrerequisite.create({
20
24
  historical_job_id: historical_job.id,
21
25
  prerequisite_historical_job_id: prerequisite.id
22
26
  })
23
27
  end
28
+
24
29
  return historical_job
25
30
  end
26
31
  end
@@ -36,6 +41,9 @@ module Logical::Naf::ConstructionZone
36
41
  priority: historical_job.priority)
37
42
  queued_job.id = historical_job.id
38
43
  queued_job.save!
44
+
45
+ return queued_job
39
46
  end
47
+
40
48
  end
41
49
  end
@@ -0,0 +1,53 @@
1
+ module Logical
2
+ module Naf
3
+ class UserSession
4
+
5
+ attr_reader :message
6
+
7
+ def initialize(signed_message)
8
+ @message = self.class.unsign_message(signed_message)
9
+ end
10
+
11
+ def valid?
12
+ message.present? && message[:value].present? &&
13
+ (Time.zone.now - message[:value]) < ::Naf.configuration.
14
+ simple_cluster_authenticator_cookie_expiration_time
15
+ end
16
+
17
+ def token_cookie
18
+ self.class.sign_message(self.class.build_token_cookie)
19
+ end
20
+
21
+ def self.build_token_cookie
22
+ {
23
+ value: Time.zone.now
24
+ }
25
+ end
26
+
27
+ # Sign the provided string using a MessageVerifier.
28
+ def self.sign_message(message)
29
+ self.message_verifier.generate(message) if !message.nil?
30
+ end
31
+
32
+ # Unsign the provided string using a MessageVerifier.
33
+ def self.unsign_message(message)
34
+ if message.nil?
35
+ return nil
36
+ end
37
+
38
+ begin
39
+ self.message_verifier.verify(message)
40
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
41
+ nil
42
+ end
43
+ end
44
+
45
+ # Returns an ActiveSuport MessageVerifier for signing/unsigning strings seeded with the
46
+ # applications secret token.
47
+ def self.message_verifier
48
+ @@message_verifier ||= ActiveSupport::MessageVerifier.new(Rails.application.class.config.secret_token)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -106,7 +106,7 @@ module Naf
106
106
  schedules = ::Naf::ApplicationSchedule.
107
107
  joins(:run_interval_style).
108
108
  where("#{Naf.schema_name}.run_interval_styles.name IN (?)", ['at beginning of day', 'at beginning of hour']).
109
- enabled.select do |schedule|
109
+ enabled.application_not_deleted.select do |schedule|
110
110
 
111
111
  interval_time = time.to_date
112
112
  if schedule.run_interval_style.name == 'at beginning of day'
@@ -133,7 +133,7 @@ module Naf
133
133
  schedules = ::Naf::ApplicationSchedule.
134
134
  joins(:run_interval_style).
135
135
  where("#{Naf.schema_name}.run_interval_styles.name = ?", 'after previous run').
136
- enabled.select do |schedule|
136
+ enabled.application_not_deleted.select do |schedule|
137
137
 
138
138
  (not_finished_applications[schedule.id].nil? &&
139
139
  (application_last_runs[schedule.id].nil? ||
@@ -149,13 +149,24 @@ module Naf
149
149
  ::Naf::ApplicationSchedule.
150
150
  joins(:run_interval_style).
151
151
  where("#{Naf.schema_name}.run_interval_styles.name = ?", 'keep running').
152
- enabled
152
+ enabled.application_not_deleted
153
153
  end
154
154
 
155
155
  def self.enabled
156
156
  where(enabled: true)
157
157
  end
158
158
 
159
+ def self.application_not_deleted
160
+ where("
161
+ NOT EXISTS (
162
+ SELECT 1
163
+ FROM #{Naf.schema_name}.applications AS app
164
+ WHERE app.id = #{Naf.schema_name}.application_schedules.application_id AND
165
+ app.deleted = true
166
+ )
167
+ ")
168
+ end
169
+
159
170
  def self.should_be_queued
160
171
  current_time = Time.zone.now
161
172
  # Applications that are still running
@@ -33,8 +33,14 @@ module Naf
33
33
  self.send(invocation_method.to_sym, job)
34
34
  end
35
35
 
36
+ # This method calls Process.spawn to excute a built command. The first part
37
+ # of the command is the execution of the job command, redirecting stderr to
38
+ # stdout. Stdout and stderr are then sent through a pipe to be used as input
39
+ # for the job logger. The job logger will also redirect stderr to stdout, and
40
+ # save any crash logs. At the end of the built command, there is a exit $PIPESTATUS
41
+ # command that will return the exit status of the whole command.
36
42
  def invoke(job, job_command)
37
- command = job_command + " 2>&1 | #{JOB_LOGGER} >> #{LOGGING_ROOT_DIRECTORY}/naf/crash.log 2>&1"
43
+ command = job_command + " 2>&1 | #{JOB_LOGGER} >> #{LOGGING_ROOT_DIRECTORY}/naf/crash.log 2>&1; exit $PIPESTATUS"
38
44
  Process.spawn({ 'NAF_JOB_ID' => job.id.to_s }, command)
39
45
  end
40
46
 
@@ -202,9 +202,9 @@ module Naf
202
202
  started_on(self).each do |job|
203
203
 
204
204
  marking_at = Time.zone.now
205
- machine_logger.alarm "#{by_machine.id} marking #{job} as dead at #{marking_at}"
205
+ machine_logger.alarm "#{by_machine.try(:id)} marking #{job} as dead at #{marking_at}"
206
206
  job.request_to_terminate = job.historical_job.request_to_terminate = true
207
- job.marked_dead_by_machine_id = job.historical_job.marked_dead_by_machine_id = by_machine.id
207
+ job.marked_dead_by_machine_id = job.historical_job.marked_dead_by_machine_id = by_machine.try(:id)
208
208
  job.marked_dead_at = job.historical_job.marked_dead_at = marking_at
209
209
  job.historical_job.finished_at = marking_at
210
210
  job.save!
@@ -216,7 +216,7 @@ module Naf
216
216
  marking_at = Time.zone.now
217
217
  machine_logger.alarm "#{by_machine.try(:id)} marking #{self} as down at #{marking_at}"
218
218
  self.marked_down = true
219
- self.marked_down_by_machine_id = by_machine.id
219
+ self.marked_down_by_machine_id = by_machine.try(:id)
220
220
  self.marked_down_at = marking_at
221
221
  save!
222
222
  mark_processes_as_dead(by_machine)
@@ -224,7 +224,7 @@ module Naf
224
224
 
225
225
  def affinity
226
226
  return ::Naf::Affinity.
227
- where(affinity_classification_id: ::Naf::AffinityClassification.location.id,
227
+ where(affinity_classification_id: ::Naf::AffinityClassification.machine.id,
228
228
  affinity_name: self.id.to_s).first
229
229
  end
230
230
 
@@ -66,7 +66,8 @@ module Process::Naf
66
66
  today = Time.zone.now.to_date
67
67
  files.each do |file|
68
68
  logger.info "Archived file: #{file}"
69
- `rm #{file}`
69
+ directory = `dirname #{file}`
70
+ `rm -r #{directory}`
70
71
  end
71
72
  end
72
73
 
@@ -0,0 +1,25 @@
1
+ module Process::Naf
2
+ class LogArchiverQueuer < ::Process::Naf::Application
3
+
4
+ def work
5
+ # Archive logs
6
+ params = { command: log_archiver.command }
7
+ boss.enqueue_n_commands_on_machines(params, :from_limit, machines)
8
+ end
9
+
10
+ private
11
+
12
+ def boss
13
+ ::Logical::Naf::ConstructionZone::Boss.new
14
+ end
15
+
16
+ def machines
17
+ ::Naf::Machine.enabled.up.all
18
+ end
19
+
20
+ def log_archiver
21
+ ::Naf::Application.where(command: '::Process::Naf::LogArchiver.run').first
22
+ end
23
+
24
+ end
25
+ end
@@ -1,5 +1,3 @@
1
- require 'open4'
2
-
3
1
  module Process::Naf::Logger
4
2
  class Base < ::Af::Application
5
3
 
@@ -165,7 +165,12 @@
165
165
  }
166
166
  },
167
167
  error: function(response) {
168
- jQuery('#stdout').prepend('Something went wrong, retry your search.');
168
+ message = '&nbsp;&nbsp;<span>Failed to retrieve ' + '<%= record_type %>' + '(' +
169
+ '<%= record_id %>' + ') logs from ' + '<%= logs_url %>'.match(/^https?\:\/\/([^\/?#]+)/).pop() + '. Please refer to ' +
170
+ 'Naf FAQs on the' + ' wiki'.link('https://github.com/fiksu/naf/wiki/Frequently-Asked-Questions') +
171
+ ' for further information.<br></span>';
172
+
173
+ jQuery('#stdout').prepend(message);
169
174
  }
170
175
  });
171
176
  }
data/lib/naf.rb CHANGED
@@ -21,10 +21,6 @@ module Naf
21
21
  configuration.model_class.constantize
22
22
  end
23
23
 
24
- def controller_class
25
- configuration.controller_class.constantize
26
- end
27
-
28
24
  def title
29
25
  configuration.title
30
26
  end
@@ -33,6 +29,22 @@ module Naf
33
29
  configuration.layout
34
30
  end
35
31
 
32
+ def ui_controller_class
33
+ configuration.ui_controller_class.constantize
34
+ end
35
+
36
+ def api_controller_class
37
+ configuration.api_controller_class.constantize
38
+ end
39
+
40
+ def api_domain_cookie_name
41
+ configuration.api_domain_cookie_name
42
+ end
43
+
44
+ def simple_cluster_authenticator_cookie_expiration_time
45
+ configuration.simple_cluster_authenticator_cookie_expiration_time
46
+ end
47
+
36
48
  def using_another_database?
37
49
  model_class != ActiveRecord::Base
38
50
  end
@@ -2,17 +2,23 @@ module Naf
2
2
  class Configuration
3
3
  attr_accessor :schema_name,
4
4
  :model_class,
5
- :controller_class,
5
+ :ui_controller_class,
6
+ :api_controller_class,
6
7
  :title,
7
8
  :layout,
8
- :default_page_options
9
+ :default_page_options,
10
+ :api_domain_cookie_name,
11
+ :simple_cluster_authenticator_cookie_expiration_time
9
12
 
10
13
  def initialize
11
14
  @model_class = "::ActiveRecord::Base"
12
- @controller_class = "::ApplicationController"
15
+ @ui_controller_class = "::ApplicationController"
13
16
  @title = "Naf - a Rails Job Scheduling Engine"
14
17
  @layout = "naf_layout"
15
18
  @default_page_options = [10, 20, 50, 100, 250, 500, 750, 1000, 1500, 2000]
19
+ @api_controller_class = "Naf::ApiSimpleClusterAuthenticatorApplicationController"
20
+ @simple_cluster_authenticator_cookie_expiration_time = 1.week
21
+ @api_domain_cookie_name = "naf_#{Rails.application.class.parent.name.underscore}"
16
22
  end
17
23
 
18
24
  end
data/lib/naf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Naf
2
- VERSION = '2.1.6'
2
+ VERSION = '2.1.8'
3
3
  end
data/naf.gemspec CHANGED
@@ -8,11 +8,11 @@ Gem::Specification.new do |s|
8
8
  s.name = "naf"
9
9
  s.version = Naf::VERSION
10
10
  s.license = 'New BSD License'
11
- s.date = '2014-03-05'
11
+ s.date = '2014-03-24'
12
12
  s.summary = "Creates infrastructure for a customizable and robust Postgres-backed script scheduling/running"
13
13
  s.description = "A cloud based distributed cron, application framework and operations console. Naf works as a distributed script running " +
14
14
  "system that provides scheduling, logging, alarming, machine redundancy, and the ability to set constraint during script execution"
15
- s.authors = ["Keith Gabryelski", "Leonardo Meira", "Nathaniel Lim", "Aleksandr Dembskiy"]
15
+ s.authors = ["Keith Gabryelski", "Leonardo Meira"]
16
16
  s.email = ['keith@fiksu.com', 'lmeira@fiksu.com']
17
17
  s.files = `git ls-files`.split("\n")
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module Naf
4
4
  describe ApplicationController do
5
5
  it "should inherit from specified controller" do
6
- ApplicationController.superclass.should == Naf.controller_class
6
+ ApplicationController.superclass.should == Naf.ui_controller_class
7
7
  end
8
8
  end
9
9
 
@@ -224,6 +224,11 @@ FactoryGirl.define do
224
224
  end
225
225
  end
226
226
 
227
+ factory :run_group_restriction, class: ::Naf::ApplicationRunGroupRestriction do
228
+ id 4
229
+ application_run_group_restriction_name "restriction"
230
+ end
231
+
227
232
  #############################################################
228
233
  ####### Application Types #################################
229
234
  #############################################################
@@ -307,6 +312,16 @@ FactoryGirl.define do
307
312
  end
308
313
  end
309
314
 
315
+ factory :machine_affinity, class: ::Naf::Affinity do
316
+ id 4
317
+ association :affinity_classification, factory: :machine_affinity_classification
318
+ affinity_name "machine"
319
+ # Ensure single creation
320
+ initialize_with do
321
+ ::Naf::Affinity.find_or_initialize_by_id(id)
322
+ end
323
+ end
324
+
310
325
  factory :affinity, class: ::Naf::Affinity do
311
326
  association :affinity_classification, factory: :purpose_affinity_classification
312
327
  sequence(:affinity_name) do |n|
@@ -342,6 +357,22 @@ FactoryGirl.define do
342
357
  end
343
358
  end
344
359
 
360
+ factory :weight_affinity_classification, class: ::Naf::AffinityClassification do
361
+ id 4
362
+ affinity_classification_name "weight"
363
+ initialize_with do
364
+ ::Naf::AffinityClassification.find_or_initialize_by_id(id)
365
+ end
366
+ end
367
+
368
+ factory :machine_affinity_classification, class: ::Naf::AffinityClassification do
369
+ id 5
370
+ affinity_classification_name "machine"
371
+ initialize_with do
372
+ ::Naf::AffinityClassification.find_or_initialize_by_id(id)
373
+ end
374
+ end
375
+
345
376
  factory :affinity_classification, class: ::Naf::AffinityClassification do
346
377
  sequence(:affinity_classification_name) { |n| "affinity_classification_#{n}" }
347
378
  end
@@ -368,6 +399,14 @@ FactoryGirl.define do
368
399
  association :affinity, factory: :canary_affinity
369
400
  end
370
401
 
402
+ factory :weight_job_affinity_tab, parent: :job_affinity_tab_base do
403
+ association :affinity, factory: :weight_affinity
404
+ end
405
+
406
+ factory :machine_job_affinity_tab, parent: :job_affinity_tab_base do
407
+ association :affinity, factory: :machine_affinity
408
+ end
409
+
371
410
  # Application Schedule Affinity Tabs
372
411
 
373
412
  factory :app_schedule_affinity_tab_base, class: ::Naf::ApplicationScheduleAffinityTab do
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ module Logical::Naf::ConstructionZone
4
+
5
+ describe Boss do
6
+ let!(:boss) { Logical::Naf::ConstructionZone::Boss.new }
7
+ let!(:work_order) {
8
+ Logical::Naf::ConstructionZone::WorkOrder.new('::Process::Naf::Janitor.run')
9
+ }
10
+ let(:params) { {
11
+ command: '::Process::Naf::Janitor.run',
12
+ application_type: ::Naf::ApplicationType.rails,
13
+ application_run_group_restriction: ::Naf::ApplicationRunGroupRestriction.
14
+ limited_per_all_machines,
15
+ application_run_group_name: '::Process::Naf::Janitor.run',
16
+ application_run_group_limit: 1,
17
+ priority: 0,
18
+ affinities: [],
19
+ prerequisites: [],
20
+ enqueue_backlogs: false,
21
+ application: nil,
22
+ application_schedule: nil
23
+ } }
24
+
25
+ shared_examples 'create one historical job' do |num_records|
26
+ it 'return the correct object' do
27
+ job.should be_a(::Naf::HistoricalJob)
28
+ end
29
+
30
+ it 'return correct number of historical jobs' do
31
+ ::Naf::HistoricalJob.should have(num_records).records
32
+ end
33
+ end
34
+
35
+ describe '#enqueue_application' do
36
+ let(:application) { FactoryGirl.create(:application) }
37
+ let!(:job) {
38
+ boss.enqueue_application(application,
39
+ ::Naf::ApplicationRunGroupRestriction.no_limit,
40
+ application.command)
41
+ }
42
+
43
+ it_should_behave_like 'create one historical job', 1
44
+ end
45
+
46
+ describe '#enqueue_application_schedule' do
47
+ let!(:job) { boss.enqueue_application_schedule(FactoryGirl.create(:schedule)) }
48
+
49
+ it_should_behave_like 'create one historical job', 1
50
+ end
51
+
52
+ describe '#enqueue_rails_command' do
53
+ let!(:job) { boss.enqueue_rails_command('::Process::Naf::Janitor.run') }
54
+
55
+ it_should_behave_like 'create one historical job', 1
56
+ end
57
+
58
+ describe '#enqueue_command' do
59
+ let!(:job) { boss.enqueue_command('::Process::Naf::Janitor.run') }
60
+
61
+ it_should_behave_like 'create one historical job', 1
62
+ end
63
+
64
+ describe '#enqueue_ad_hoc_command' do
65
+ let!(:job) { boss.enqueue_ad_hoc_command(params) }
66
+
67
+ it_should_behave_like 'create one historical job', 1
68
+ end
69
+
70
+ describe '#enqueue_n_commands_on_machines' do
71
+ let!(:affinity) { FactoryGirl.create(:normal_affinity) }
72
+
73
+ before do
74
+ params[:application_run_group_quantum] = 2
75
+ params[:application_run_group_limit] = 5
76
+ end
77
+
78
+ it 'not create a historical job when array of machines is empty' do
79
+ boss.enqueue_n_commands_on_machines({})
80
+ ::Naf::HistoricalJob.should have(0).records
81
+ end
82
+
83
+ it 'create two historical jobs when a machine is present' do
84
+ machine = FactoryGirl.create(:machine)
85
+ classification = FactoryGirl.create(:location_affinity_classification)
86
+ FactoryGirl.create(:affinity, id: 5,
87
+ affinity_name: machine.id.to_s,
88
+ affinity_classification: classification)
89
+
90
+ boss.enqueue_n_commands_on_machines(params, :from_limit, [machine])
91
+ ::Naf::HistoricalJob.should have(2).records
92
+ end
93
+ end
94
+
95
+ describe '#enqueue_n_commands' do
96
+ subject { boss.enqueue_n_commands(params) }
97
+
98
+ it 'create one historical jobs when application_run_group_quantum is not specified' do
99
+ params[:application_run_group_quantum] = 1
100
+ subject
101
+ ::Naf::HistoricalJob.should have(1).records
102
+ end
103
+
104
+ it 'create five historical jobs' do
105
+ params[:application_run_group_quantum] = 5
106
+ params[:application_run_group_limit] = 5
107
+ subject
108
+ ::Naf::HistoricalJob.should have(5).records
109
+ end
110
+ end
111
+
112
+ describe '#reenqueue' do
113
+ let!(:job) { boss.reenqueue(FactoryGirl.create(:job)) }
114
+
115
+ it_should_behave_like 'create one historical job', 2
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ module Logical::Naf::ConstructionZone
4
+ describe Foreman do
5
+
6
+ let!(:foreman) { Logical::Naf::ConstructionZone::Foreman.new }
7
+ let!(:work_order) {
8
+ Logical::Naf::ConstructionZone::WorkOrder.new('::Process::Naf::Janitor.run')
9
+ }
10
+
11
+ describe '#enqueue' do
12
+ it 'return historical job when enqueue_backlogs is set to true' do
13
+ work_order.enqueue_backlogs
14
+ foreman.enqueue(work_order).should be_a(::Naf::HistoricalJob)
15
+ end
16
+
17
+ it 'return historical job when enqueue_backlogs is set to false and there is not run group limit' do
18
+ foreman.enqueue(work_order).should be_a(::Naf::HistoricalJob)
19
+ end
20
+
21
+ it 'return nil when work order is limited by run group' do
22
+ foreman.should_receive(:limited_by_run_group?).and_return(true)
23
+ foreman.enqueue(work_order).should be_nil
24
+ end
25
+ end
26
+
27
+ describe '#limited_by_run_group?' do
28
+ let!(:no_limit) { FactoryGirl.create(:no_limit) }
29
+ let!(:limited_per_machine) { FactoryGirl.create(:limited_per_machine) }
30
+ let!(:limited_per_all_machines) { FactoryGirl.create(:limited_per_all_machines) }
31
+
32
+ it 'return false when run group restriction is set to no limit' do
33
+ foreman.limited_by_run_group?(no_limit, nil, nil, []).should be_false
34
+ end
35
+
36
+ it 'return false when run group limit is nil' do
37
+ foreman.limited_by_run_group?(limited_per_machine, 'test', nil, []).should be_false
38
+ end
39
+
40
+ it 'return false when run group name is nil' do
41
+ foreman.limited_by_run_group?(limited_per_machine, nil, 1, []).should be_false
42
+ end
43
+
44
+ describe 'run group restriction is set to limited per machine' do
45
+ let!(:machine) { FactoryGirl.create(:machine) }
46
+ let(:historical_job) { FactoryGirl.create(:job, application_run_group_name: 'test') }
47
+ let(:tab) { FactoryGirl.create(:machine_job_affinity_tab, historical_job_id: historical_job.id) }
48
+
49
+ before do
50
+ FactoryGirl.create(:queued_job, application_run_group_name: 'test', id: historical_job.id)
51
+ FactoryGirl.create(:running_job_base, application_run_group_name: 'test',
52
+ started_on_machine_id: machine.id,
53
+ application_run_group_name: 'test')
54
+ end
55
+
56
+ it 'return false when application does not have affinity associated with machine' do
57
+ foreman.limited_by_run_group?(limited_per_machine, 'test', 1, []).should be_false
58
+ end
59
+
60
+ it 'return false when limit is greater than number of running/queued jobs' do
61
+ foreman.limited_by_run_group?(
62
+ limited_per_machine, 'test', 5, [{ affinity_id: tab.affinity.id }]
63
+ ).should be_false
64
+ end
65
+
66
+ it 'return true when limit is equal to number of running/queued jobs' do
67
+ foreman.limited_by_run_group?(
68
+ limited_per_machine, 'test', 1, [{ affinity_id: tab.affinity.id }]
69
+ ).should be_true
70
+ end
71
+
72
+ it 'return true when limit is less than number of running/queued jobs' do
73
+ FactoryGirl.create(:running_job_base, application_run_group_name: 'test',
74
+ started_on_machine_id: machine.id,
75
+ application_run_group_name: 'test')
76
+ foreman.limited_by_run_group?(
77
+ limited_per_machine, 'test', 1, [{ affinity_id: tab.affinity.id }]
78
+ ).should be_true
79
+ end
80
+ end
81
+
82
+ describe 'run group restriction is set to limited per all machines' do
83
+ it 'return false when limit is greater than number of running/queued jobs' do
84
+ foreman.limited_by_run_group?(limited_per_all_machines, 'test', 1, []).should be_false
85
+ end
86
+
87
+ it 'return true when limit is equal to number of running/queued jobs' do
88
+ FactoryGirl.create(:queued_job, application_run_group_name: 'test')
89
+ foreman.limited_by_run_group?(limited_per_all_machines, 'test', 1, []).should be_true
90
+ end
91
+
92
+ it 'return true when limit is less than number of running/queued jobs' do
93
+ FactoryGirl.create(:queued_job, application_run_group_name: 'test')
94
+ FactoryGirl.create(:running_job_base, application_run_group_name: 'test')
95
+ foreman.limited_by_run_group?(limited_per_all_machines, 'test', 1, []).should be_true
96
+ end
97
+ end
98
+
99
+ it 'return true when a different run group restriction is found' do
100
+ restriction = FactoryGirl.create(:run_group_restriction)
101
+ foreman.limited_by_run_group?(restriction, 'test', 1, []).should be_true
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module Logical::Naf::ConstructionZone
4
+
5
+ describe Proletariat do
6
+
7
+ let!(:proletariat) { ::Logical::Naf::ConstructionZone::Proletariat.new }
8
+ let(:application) { FactoryGirl.create(:scheduled_application) }
9
+ let(:application_type) { FactoryGirl.create(:rails_app_type) }
10
+ let(:restriction) { FactoryGirl.create(:no_limit) }
11
+ let!(:params) {
12
+ {
13
+ command: '::Process::Naf::Janitor.run',
14
+ application_type_id: application_type.id,
15
+ application_run_group_restriction_id: restriction.id,
16
+ application_run_group_name: '::Process::Naf::Janitor.run',
17
+ application_run_group_limit: 1,
18
+ priority: 0,
19
+ application_id: application.id,
20
+ application_schedule_id: application.application_schedules.first.id
21
+ }
22
+ }
23
+ let!(:affinity) { { affinity_id: FactoryGirl.create(:normal_affinity).id } }
24
+ let!(:prerequisite) { FactoryGirl.create(:job) }
25
+
26
+ describe '#create_job' do
27
+ it 'return a historical job' do
28
+ proletariat.create_job(params, [], []).should be_a(::Naf::HistoricalJob)
29
+ end
30
+ end
31
+
32
+ describe '#create_historical_job' do
33
+ let!(:historical_job) { proletariat.create_historical_job(params, [affinity], [prerequisite]) }
34
+
35
+ it 'return historical job when exception is not raised' do
36
+ historical_job.should be_a(::Naf::HistoricalJob)
37
+ end
38
+
39
+ it 'create a historical job affinity tab' do
40
+ ::Naf::HistoricalJobAffinityTab.should have(1).records
41
+ end
42
+
43
+ it 'create a historical job affinity tab' do
44
+ ::Naf::HistoricalJobPrerequisite.should have(1).records
45
+ end
46
+
47
+ it 'raise an exception when there is a loop found in prerequisites' do
48
+ prerequisite.should_receive(:prerequisites).and_raise(::Naf::HistoricalJob::JobPrerequisiteLoop.new(prerequisite))
49
+ begin
50
+ job = proletariat.create_historical_job(params, [affinity], [prerequisite])
51
+ rescue
52
+ end
53
+ job.should be_nil
54
+ end
55
+ end
56
+
57
+ describe '#create_queued_job' do
58
+ let!(:historical_job) { FactoryGirl.create(:scheduled_job) }
59
+
60
+ it 'return a queued job' do
61
+ historical_job.application_schedule_id = historical_job.application.application_schedules.first.id
62
+ proletariat.create_queued_job(historical_job).should be_a(::Naf::QueuedJob)
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -21,6 +21,7 @@ module Logical::Naf::ConstructionZone
21
21
  application_schedule_id: nil
22
22
  }
23
23
  }
24
+
24
25
  it 'return correct values' do
25
26
  work_order.historical_job_parameters.should == params
26
27
  end
@@ -49,7 +50,7 @@ module Logical::Naf::ConstructionZone
49
50
 
50
51
  it 'return hash with the affinity_id when a Machine object is provided' do
51
52
  machine = FactoryGirl.create(:machine)
52
- classification = FactoryGirl.create(:location_affinity_classification)
53
+ classification = FactoryGirl.create(:machine_affinity_classification)
53
54
  affinity = FactoryGirl.create(:affinity, id: 4,
54
55
  affinity_name: machine.id.to_s,
55
56
  affinity_classification: classification)
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ module Logical
4
+ module Naf
5
+
6
+ describe UserSession do
7
+ let!(:user_session) { ::Logical::Naf::UserSession.new(nil) }
8
+
9
+ describe '#valid?' do
10
+ it 'return false when message is not present' do
11
+ user_session.valid?.should be_false
12
+ end
13
+
14
+ it 'return false when value is not present' do
15
+ user_session.instance_variable_set(:@message, {})
16
+ user_session.valid?.should be_false
17
+ end
18
+
19
+ it 'return false when session is expired' do
20
+ user_session.instance_variable_set(:@message, { value: Time.zone.now - 1.month })
21
+ user_session.valid?.should be_false
22
+ end
23
+
24
+ it 'return true for invalid signed message' do
25
+ user_session.instance_variable_set(:@message, { value: Time.zone.now - 1.hour })
26
+ user_session.valid?.should be_true
27
+ end
28
+ end
29
+
30
+ describe '#token_cookie' do
31
+ let!(:signed_message) { user_session.token_cookie }
32
+
33
+ it 'not be nil' do
34
+ signed_message.should_not be_nil
35
+ end
36
+ end
37
+
38
+ describe '#build_token_cookie' do
39
+ before do
40
+ Timecop.freeze(Time.zone.now)
41
+ end
42
+
43
+ after do
44
+ Timecop.return
45
+ end
46
+
47
+ it 'return hash with current time' do
48
+ ::Logical::Naf::UserSession.build_token_cookie.should == { value: Time.zone.now }
49
+ end
50
+ end
51
+
52
+ describe '#sign_message' do
53
+ it 'return nil when message is nil' do
54
+ ::Logical::Naf::UserSession.sign_message(nil).should be_nil
55
+ end
56
+
57
+ it 'sign the message when message is present' do
58
+ ::Logical::Naf::UserSession.sign_message(::Logical::Naf::UserSession.build_token_cookie).
59
+ should =~ /^.{123}={1}-{2}[a-zA-Z0-9]{40}$/
60
+ end
61
+ end
62
+
63
+ describe '#unsign_message' do
64
+ it 'return nil when message is not signed' do
65
+ ::Logical::Naf::UserSession.unsign_message(nil).should be_nil
66
+ end
67
+
68
+ it 'return nil when InvalidSignature exception is raised' do
69
+ ::Logical::Naf::UserSession.stub(:message_verifier).
70
+ and_raise(ActiveSupport::MessageVerifier::InvalidSignature)
71
+ ::Logical::Naf::UserSession.unsign_message(nil).should be_nil
72
+ end
73
+
74
+ it 'return message when signed message is valid' do
75
+ message_verifier = ActiveSupport::MessageVerifier.
76
+ new(Rails.application.class.config.secret_token)
77
+ message = { value: Time.zone.now }
78
+
79
+ ::Logical::Naf::UserSession.
80
+ unsign_message(message_verifier.generate(message)).should == message
81
+ end
82
+ end
83
+
84
+ describe '#message_verifier' do
85
+ it 'return instance of ActiveSupport::MessageVerifier' do
86
+ ::Logical::Naf::UserSession.message_verifier.should be_a(ActiveSupport::MessageVerifier)
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -95,6 +95,12 @@ module Naf
95
95
  time = Time.zone.now
96
96
  ::Naf::ApplicationSchedule.exact_schedules(time, {}, {}).should == []
97
97
  end
98
+
99
+ it "return no schedules when application is deleted" do
100
+ schedule.application.deleted = true
101
+ schedule.application.save!
102
+ ::Naf::ApplicationSchedule.exact_schedules(time, {}, {}).should == []
103
+ end
98
104
  end
99
105
 
100
106
  describe "#relative_schedules" do
@@ -116,6 +122,61 @@ module Naf
116
122
  schedule.run_interval = 20
117
123
  ::Naf::ApplicationSchedule.relative_schedules(time, {}, apps).should == []
118
124
  end
125
+
126
+ it "return no schedules when application is deleted" do
127
+ schedule.application.deleted = true
128
+ schedule.application.save!
129
+ ::Naf::ApplicationSchedule.exact_schedules(time, {}, {}).should == []
130
+ end
131
+ end
132
+
133
+ describe "#constant_schedules" do
134
+ it "return schedule when it is ready" do
135
+ schedule.run_interval_style.name = 'keep running'
136
+ schedule.run_interval_style.save!
137
+
138
+ ::Naf::ApplicationSchedule.constant_schedules.should == [schedule]
139
+ end
140
+
141
+ it "return no schedules when application is deleted" do
142
+ schedule.application.deleted = true
143
+ schedule.application.save!
144
+ ::Naf::ApplicationSchedule.constant_schedules.should == []
145
+ end
146
+
147
+ it "return no schedules when schedule is disabled" do
148
+ schedule.enabled = false
149
+ schedule.save!
150
+ ::Naf::ApplicationSchedule.constant_schedules.should == []
151
+ end
152
+
153
+ it "return no schdules when run interval style is not keep running" do
154
+ ::Naf::ApplicationSchedule.constant_schedules.should == []
155
+ end
156
+ end
157
+
158
+ describe "#enabled" do
159
+ it "return empty array when schedule is disabled" do
160
+ schedule.enabled = false
161
+ schedule.save!
162
+ ::Naf::ApplicationSchedule.enabled.should == []
163
+ end
164
+
165
+ it "return array with schedule when schedule is enabled" do
166
+ ::Naf::ApplicationSchedule.enabled.should == [schedule]
167
+ end
168
+ end
169
+
170
+ describe "#application_not_deleted" do
171
+ it "return empty array when application is deleted" do
172
+ schedule.application.deleted = true
173
+ schedule.application.save!
174
+ ::Naf::ApplicationSchedule.application_not_deleted.should == []
175
+ end
176
+
177
+ it "return array with schedule when application is not deleted" do
178
+ ::Naf::ApplicationSchedule.application_not_deleted.should == [schedule]
179
+ end
119
180
  end
120
181
 
121
182
  #-------------------------
@@ -396,10 +396,12 @@ module Naf
396
396
  end
397
397
 
398
398
  describe "#affinity" do
399
+ let!(:classification) { FactoryGirl.create(:machine_affinity_classification) }
399
400
  it "return affinity associated with machine's id" do
400
- affinity = FactoryGirl.create(:affinity, id: 4,
401
- affinity_classification_id: 1,
402
- affinity_name: machine.id.to_s)
401
+ affinity = FactoryGirl.create(:affinity,
402
+ id: 4,
403
+ affinity_classification_id: FactoryGirl.create(:machine_affinity_classification).id,
404
+ affinity_name: machine.id.to_s)
403
405
  machine.affinity.should == affinity
404
406
  end
405
407
 
metadata CHANGED
@@ -1,18 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: naf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.1.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Keith Gabryelski
9
9
  - Leonardo Meira
10
- - Nathaniel Lim
11
- - Aleksandr Dembskiy
12
10
  autorequire:
13
11
  bindir: bin
14
12
  cert_chain: []
15
- date: 2014-03-05 00:00:00.000000000 Z
13
+ date: 2014-03-24 00:00:00.000000000 Z
16
14
  dependencies:
17
15
  - !ruby/object:Gem::Dependency
18
16
  name: rails
@@ -239,6 +237,7 @@ files:
239
237
  - app/assets/stylesheets/naf.css
240
238
  - app/assets/stylesheets/naf/layout.css.scss
241
239
  - app/controllers/naf/affinities_controller.rb
240
+ - app/controllers/naf/api_simple_cluster_authenticator_application_controller.rb
242
241
  - app/controllers/naf/application_controller.rb
243
242
  - app/controllers/naf/application_schedule_affinity_tabs_controller.rb
244
243
  - app/controllers/naf/application_schedules_controller.rb
@@ -287,6 +286,7 @@ files:
287
286
  - app/models/logical/naf/machine_runner_invocation.rb
288
287
  - app/models/logical/naf/pickler.rb
289
288
  - app/models/logical/naf/unpickler.rb
289
+ - app/models/logical/naf/user_session.rb
290
290
  - app/models/naf/affinity.rb
291
291
  - app/models/naf/affinity_classification.rb
292
292
  - app/models/naf/application.rb
@@ -319,6 +319,7 @@ files:
319
319
  - app/models/process/naf/data_migration/backfill_application_schedule_run_interval.rb
320
320
  - app/models/process/naf/janitor.rb
321
321
  - app/models/process/naf/log_archiver.rb
322
+ - app/models/process/naf/log_archiver_queuer.rb
322
323
  - app/models/process/naf/log_reader.rb
323
324
  - app/models/process/naf/logger/base.rb
324
325
  - app/models/process/naf/logger/job_log.rb
@@ -485,6 +486,9 @@ files:
485
486
  - spec/factories/naf.rb
486
487
  - spec/helpers/naf/application_helper_spec.rb
487
488
  - spec/models/logical/naf/application_spec.rb
489
+ - spec/models/logical/naf/construction_zone/boss_rspec.rb
490
+ - spec/models/logical/naf/construction_zone/foreman_spec.rb
491
+ - spec/models/logical/naf/construction_zone/proletariat_spec.rb
488
492
  - spec/models/logical/naf/construction_zone/work_order_spec.rb
489
493
  - spec/models/logical/naf/job_fetcher_spec.rb
490
494
  - spec/models/logical/naf/job_spec.rb
@@ -492,6 +496,7 @@ files:
492
496
  - spec/models/logical/naf/machine_runner_invocation_spec.rb
493
497
  - spec/models/logical/naf/machine_runner_spec.rb
494
498
  - spec/models/logical/naf/machine_spec.rb
499
+ - spec/models/logical/naf/user_session_spec.rb
495
500
  - spec/models/naf/affinity_classification_spec.rb
496
501
  - spec/models/naf/affinity_spec.rb
497
502
  - spec/models/naf/application_run_group_restriction_spec.rb
@@ -600,6 +605,9 @@ test_files:
600
605
  - spec/factories/naf.rb
601
606
  - spec/helpers/naf/application_helper_spec.rb
602
607
  - spec/models/logical/naf/application_spec.rb
608
+ - spec/models/logical/naf/construction_zone/boss_rspec.rb
609
+ - spec/models/logical/naf/construction_zone/foreman_spec.rb
610
+ - spec/models/logical/naf/construction_zone/proletariat_spec.rb
603
611
  - spec/models/logical/naf/construction_zone/work_order_spec.rb
604
612
  - spec/models/logical/naf/job_fetcher_spec.rb
605
613
  - spec/models/logical/naf/job_spec.rb
@@ -607,6 +615,7 @@ test_files:
607
615
  - spec/models/logical/naf/machine_runner_invocation_spec.rb
608
616
  - spec/models/logical/naf/machine_runner_spec.rb
609
617
  - spec/models/logical/naf/machine_spec.rb
618
+ - spec/models/logical/naf/user_session_spec.rb
610
619
  - spec/models/naf/affinity_classification_spec.rb
611
620
  - spec/models/naf/affinity_spec.rb
612
621
  - spec/models/naf/application_run_group_restriction_spec.rb