tengine_job 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +23 -0
  4. data/Gemfile.lock +109 -0
  5. data/README.rdoc +20 -0
  6. data/Rakefile +42 -0
  7. data/VERSION +1 -0
  8. data/examples/0004_retry_one_layer.rb +24 -0
  9. data/examples/0004_retry_one_layer.sh +38 -0
  10. data/examples/0005_retry_two_layer.rb +54 -0
  11. data/examples/0005_retry_two_layer.sh +80 -0
  12. data/examples/0006_retry_three_layer.rb +58 -0
  13. data/examples/0006_retry_three_layer.sh +74 -0
  14. data/examples/0007_simple_jobnet.rb +7 -0
  15. data/examples/0021_dynamic_env.rb +20 -0
  16. data/examples/VERSION +1 -0
  17. data/examples/tengine_job_test.sh +10 -0
  18. data/lib/tengine/job.rb +94 -0
  19. data/lib/tengine/job/category.rb +54 -0
  20. data/lib/tengine/job/connectable.rb +43 -0
  21. data/lib/tengine/job/drivers/job_control_driver.rb +82 -0
  22. data/lib/tengine/job/drivers/job_execution_driver.rb +30 -0
  23. data/lib/tengine/job/drivers/jobnet_control_driver.rb +117 -0
  24. data/lib/tengine/job/drivers/schedule_driver.rb +30 -0
  25. data/lib/tengine/job/dsl_binder.rb +12 -0
  26. data/lib/tengine/job/dsl_evaluator.rb +18 -0
  27. data/lib/tengine/job/dsl_loader.rb +180 -0
  28. data/lib/tengine/job/edge.rb +150 -0
  29. data/lib/tengine/job/element_selector_notation.rb +169 -0
  30. data/lib/tengine/job/end.rb +32 -0
  31. data/lib/tengine/job/executable.rb +74 -0
  32. data/lib/tengine/job/execution.rb +141 -0
  33. data/lib/tengine/job/expansion.rb +37 -0
  34. data/lib/tengine/job/fork.rb +6 -0
  35. data/lib/tengine/job/job.rb +23 -0
  36. data/lib/tengine/job/jobnet.rb +173 -0
  37. data/lib/tengine/job/jobnet/builder.rb +150 -0
  38. data/lib/tengine/job/jobnet/job_state_transition.rb +167 -0
  39. data/lib/tengine/job/jobnet/jobnet_state_transition.rb +110 -0
  40. data/lib/tengine/job/jobnet/state_transition.rb +37 -0
  41. data/lib/tengine/job/jobnet_actual.rb +55 -0
  42. data/lib/tengine/job/jobnet_template.rb +10 -0
  43. data/lib/tengine/job/join.rb +6 -0
  44. data/lib/tengine/job/junction.rb +29 -0
  45. data/lib/tengine/job/killing.rb +30 -0
  46. data/lib/tengine/job/mm_compatibility.rb +6 -0
  47. data/lib/tengine/job/mm_compatibility/connectable.rb +13 -0
  48. data/lib/tengine/job/name_path.rb +31 -0
  49. data/lib/tengine/job/root.rb +16 -0
  50. data/lib/tengine/job/root_jobnet_actual.rb +39 -0
  51. data/lib/tengine/job/root_jobnet_template.rb +49 -0
  52. data/lib/tengine/job/script_executable.rb +235 -0
  53. data/lib/tengine/job/signal.rb +121 -0
  54. data/lib/tengine/job/start.rb +20 -0
  55. data/lib/tengine/job/stoppable.rb +15 -0
  56. data/lib/tengine/job/vertex.rb +172 -0
  57. data/lib/tengine_job.rb +3 -0
  58. data/spec/fixtures/rjn_0001_simple_jobnet_builder.rb +42 -0
  59. data/spec/fixtures/rjn_0002_simple_parallel_jobnet_builder.rb +42 -0
  60. data/spec/fixtures/rjn_0003_fork_join_jobnet_builder.rb +61 -0
  61. data/spec/fixtures/rjn_0004_parallel_jobnet_with_finally_fixture.rb +62 -0
  62. data/spec/fixtures/rjn_0005_retry_two_layer_fixture.rb +153 -0
  63. data/spec/fixtures/rjn_0008_expansion_fixture.rb +32 -0
  64. data/spec/fixtures/rjn_0009_tree_sequential_jobnet_builder.rb +174 -0
  65. data/spec/fixtures/rjn_0010_2jobs_and_1job_parallel_jobnet_builder.rb +39 -0
  66. data/spec/fixtures/rjn_0011_nested_fork_jobnet_builder.rb +96 -0
  67. data/spec/fixtures/rjn_0012_nested_and_finally_builder.rb +157 -0
  68. data/spec/fixtures/rjn_1004_hadoop_job_in_jobnet_fixture.rb +105 -0
  69. data/spec/fixtures/rjn_means_root_jobnet +0 -0
  70. data/spec/fixtures/test_credential_fixture.rb +12 -0
  71. data/spec/fixtures/test_server_fixture.rb +28 -0
  72. data/spec/mongoid.yml +35 -0
  73. data/spec/spec_helper.rb +56 -0
  74. data/spec/sshd/.gitignore +1 -0
  75. data/spec/sshd/id_rsa +51 -0
  76. data/spec/sshd/id_rsa.pub +1 -0
  77. data/spec/sshd/ssh_host_rsa_key +51 -0
  78. data/spec/sshd/ssh_host_rsa_key.pub +1 -0
  79. data/spec/sshd/sshd_config +10 -0
  80. data/spec/sshd/sshd_config.erb +11 -0
  81. data/spec/sshd/tengine_job_test.sh +6 -0
  82. data/spec/support/jobnet_fixture_builder.rb +145 -0
  83. data/spec/support/mongo_index_key_log.rb +91 -0
  84. data/spec/tengine/job/category_spec.rb +193 -0
  85. data/spec/tengine/job/connectable_spec.rb +94 -0
  86. data/spec/tengine/job/drivers/job_controll_driver/connection_error_spec.rb +236 -0
  87. data/spec/tengine/job/drivers/job_controll_driver/duplicated_job_start_spec.rb +302 -0
  88. data/spec/tengine/job/drivers/job_controll_driver/expansion_spec.rb +120 -0
  89. data/spec/tengine/job/drivers/job_controll_driver/stop_spec.rb +159 -0
  90. data/spec/tengine/job/drivers/job_controll_driver_spec.rb +623 -0
  91. data/spec/tengine/job/drivers/job_execution_driver_spec.rb +88 -0
  92. data/spec/tengine/job/drivers/jobnet_control_driver/nested_and_finally_spec.rb +472 -0
  93. data/spec/tengine/job/drivers/jobnet_control_driver/nested_jobnet_spec.rb +231 -0
  94. data/spec/tengine/job/drivers/jobnet_control_driver/stop_jobnet_spec.rb +202 -0
  95. data/spec/tengine/job/drivers/jobnet_control_driver_spec.rb +446 -0
  96. data/spec/tengine/job/drivers/schedule_driver_spec.rb +202 -0
  97. data/spec/tengine/job/dsl_binder_spec.rb +36 -0
  98. data/spec/tengine/job/dsl_loader_spec.rb +403 -0
  99. data/spec/tengine/job/dsls/0013_hadoop_job_run.rb +29 -0
  100. data/spec/tengine/job/dsls/0014_join_and_join.rb +19 -0
  101. data/spec/tengine/job/dsls/0015_fork_and_fork.rb +18 -0
  102. data/spec/tengine/job/dsls/0016_complex_fork_and_join.rb +20 -0
  103. data/spec/tengine/job/dsls/0017_finally.rb +15 -0
  104. data/spec/tengine/job/dsls/0018_expansion.rb +23 -0
  105. data/spec/tengine/job/dsls/0019_execute_job_on_event.rb +16 -0
  106. data/spec/tengine/job/dsls/0020_duplicated_jobnet_name.rb +16 -0
  107. data/spec/tengine/job/dsls/1060_test_dir1/1060_test_dir2/0013_hadoop_job_run.rb +29 -0
  108. data/spec/tengine/job/dsls/2003_expansion/expansion_5.rb +11 -0
  109. data/spec/tengine/job/dsls/VERSION +1 -0
  110. data/spec/tengine/job/dynamic_env_spec.rb +95 -0
  111. data/spec/tengine/job/edge_spec.rb +241 -0
  112. data/spec/tengine/job/element_selector_notation_spec.rb +354 -0
  113. data/spec/tengine/job/examples_spec.rb +62 -0
  114. data/spec/tengine/job/execution_spec.rb +100 -0
  115. data/spec/tengine/job/expansion_spec.rb +116 -0
  116. data/spec/tengine/job/hadoop_job_run_spec.rb +65 -0
  117. data/spec/tengine/job/job_spec.rb +4 -0
  118. data/spec/tengine/job/jobnet/1015_complecated_jobnet_spec.rb +72 -0
  119. data/spec/tengine/job/jobnet_actual_spec.rb +175 -0
  120. data/spec/tengine/job/jobnet_spec.rb +399 -0
  121. data/spec/tengine/job/jobnet_template_spec.rb +240 -0
  122. data/spec/tengine/job/killing_spec.rb +91 -0
  123. data/spec/tengine/job/reset_spec.rb +958 -0
  124. data/spec/tengine/job/reset_spec/4056_1_dump.txt +1 -0
  125. data/spec/tengine/job/root_jobnet_actual_spec.rb +89 -0
  126. data/spec/tengine/job/root_jobnet_template_spec.rb +248 -0
  127. data/spec/tengine/job/script_executable_spec.rb +132 -0
  128. data/spec/tengine/job/stoppable_spec.rb +176 -0
  129. data/spec/tengine/job/vertex_spec.rb +25 -0
  130. data/spec/tengine_job_spec.rb +4 -0
  131. data/tengine_job.gemspec +197 -0
  132. data/tmp/log/.gitignore +1 -0
  133. metadata +296 -0
@@ -0,0 +1,120 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'tengine/rspec'
4
+
5
+ describe 'job_control_driver' do
6
+ include Tengine::RSpec::Extension
7
+
8
+ target_dsl File.expand_path("../../../../../lib/tengine/job/drivers/job_control_driver.rb", File.dirname(__FILE__))
9
+ driver :job_control_driver
10
+
11
+ shared_examples_for "/rjn0008/rjn0001/j11を実行する際の環境変数" do |dsl_version|
12
+ it "expansionだったジョブネットよりも上位のジョブの情報は出力されない" do
13
+ @rjn0001 = @root.vertex_by_name_path("/rjn0008/rjn0001")
14
+ @j11 = @root.vertex_by_name_path("/rjn0008/rjn0001/j11")
15
+ @root.phase_key = :running
16
+ @rjn0001.phase_key = :running
17
+ @j11.phase_key = :ready
18
+ @j11.prev_edges.each{|edge| edge.phase_key = :transmitting}
19
+ @root.save!
20
+ @root.reload
21
+ tengine.should_not_fire
22
+ mock_ssh = mock(:ssh)
23
+ mock_channel = mock(:channel)
24
+ Net::SSH.should_receive(:start).
25
+ with("localhost", an_instance_of(Tengine::Resource::Credential), an_instance_of(Hash)).and_yield(mock_ssh)
26
+ mock_ssh.should_receive(:open_channel).and_yield(mock_channel)
27
+ mock_channel.should_receive(:exec) do |*args|
28
+ args.length.should == 1
29
+ # args.first.should =~ %r<source \/etc\/profile && export MM_ACTUAL_JOB_ID=[0-9a-f]{24} MM_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_FULL_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_ACTUAL_JOB_NAME_PATH=\\"/rjn0001/j11\\" MM_ACTUAL_JOB_SECURITY_TOKEN= MM_SCHEDULE_ID=[0-9a-f]{24} MM_SCHEDULE_ESTIMATED_TIME= MM_TEMPLATE_JOB_ID=[0-9a-f]{24} MM_TEMPLATE_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" && tengine_job_agent_run -- \$HOME/j11\.sh>
30
+ args.first.should =~ %r<source \/etc\/profile>
31
+ t_rjn1001 = Tengine::Job::RootJobnetTemplate.find_by_name("rjn0001")
32
+ t_rjn1001.dsl_version.should == dsl_version
33
+ t_j11 = t_rjn1001.vertex_by_name_path("/rjn0001/j11")
34
+ args.first.should =~ %r<MM_TEMPLATE_JOB_ID=#{t_j11.id.to_s}>
35
+ args.first.should_not =~ %r<MM_TEMPLATE_JOB_ANCESTOR_IDS=\"#{@template.id.to_s};#{t_rjn1001.id.to_s}\">
36
+ args.first.should =~ %r<MM_TEMPLATE_JOB_ANCESTOR_IDS=\"#{t_rjn1001.id.to_s}\">
37
+ args.first.should =~ %r<job_test j11>
38
+ end
39
+ tengine.receive("start.job.job.tengine", :properties => {
40
+ :execution_id => @execution.id.to_s,
41
+ :root_jobnet_id => @root.id.to_s,
42
+ :target_jobnet_id => @rjn0001.id.to_s,
43
+ :target_job_id => @j11.id.to_s,
44
+ })
45
+ @root.reload
46
+ @rjn0001 = @root.vertex_by_name_path("/rjn0008/rjn0001")
47
+ @j11 = @root.vertex_by_name_path("/rjn0008/rjn0001/j11")
48
+ @root.phase_key = :running
49
+ @rjn0001.phase_key = :running
50
+ end
51
+ end
52
+
53
+ # in [rjn0008]
54
+ # (S1) --e1-->(rjn0001)--e2-->(rjn0002)--e3-->(E1)
55
+ #
56
+ # in [rjn0001]
57
+ # (S1) --e1-->(j11)--e2-->(j12)--e3-->(E1)
58
+ #
59
+ # in [rjn0002]
60
+ # |--e2-->(j11)--e4-->|
61
+ # (S1)--e1-->[F1] [J1]--e6-->(E1)
62
+ # |--e3-->(j12)--e5-->|
63
+ context "rjn0008" do
64
+ before do
65
+ Tengine::Core::Setting.delete_all
66
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => "1")
67
+ Tengine::Job::Vertex.delete_all
68
+ Rjn0001SimpleJobnetBuilder.new.create_template
69
+ Rjn0002SimpleParallelJobnetBuilder.new.create_template
70
+ builder = Rjn0008ExpansionFixture.new
71
+ @template = builder.create_template
72
+ @root = @template.generate
73
+ @ctx = builder.context
74
+ @execution = Tengine::Job::Execution.create!({
75
+ :root_jobnet_id => @root.id,
76
+ })
77
+ @base_props = {
78
+ :execution_id => @execution.id.to_s,
79
+ :root_jobnet_id => @root.id.to_s,
80
+ :target_jobnet_id => @root.id.to_s,
81
+ }
82
+ end
83
+
84
+ it_should_behave_like "/rjn0008/rjn0001/j11を実行する際の環境変数", "1"
85
+ end
86
+
87
+ context "複数のバージョンのデータがある場合" do
88
+ before do
89
+ Tengine::Core::Setting.delete_all
90
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => "2")
91
+ Tengine::Job::Vertex.delete_all
92
+ Rjn0001SimpleJobnetBuilder.new.tap do |f|
93
+ f.create_template(:dsl_version => "1")
94
+ f.create_template(:dsl_version => "2")
95
+ end
96
+ Rjn0002SimpleParallelJobnetBuilder.new.tap do |f|
97
+ f.create_template(:dsl_version => "1")
98
+ f.create_template(:dsl_version => "2")
99
+ end
100
+ builder = Rjn0008ExpansionFixture.new
101
+ builder.create_template(:dsl_version => "1")
102
+ @template = builder.create_template(:dsl_version => "2")
103
+ @root = @template.generate
104
+ @ctx = builder.context
105
+ @execution = Tengine::Job::Execution.create!({
106
+ :root_jobnet_id => @root.id,
107
+ })
108
+ @base_props = {
109
+ :execution_id => @execution.id.to_s,
110
+ :root_jobnet_id => @root.id.to_s,
111
+ :target_jobnet_id => @root.id.to_s,
112
+ }
113
+ end
114
+
115
+ it_should_behave_like "/rjn0008/rjn0001/j11を実行する際の環境変数", '2'
116
+ end
117
+
118
+ end
119
+
120
+
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'tengine/rspec'
4
+
5
+ require 'net/ssh'
6
+
7
+ describe "<BUG>(tengined複数起動)強制停止すると、ステータスが「強制停止済」ではなく「エラー終了」になる" do
8
+ include Tengine::RSpec::Extension
9
+
10
+ driver_path = File.expand_path("../../../../../lib/tengine/job/drivers/job_control_driver.rb", File.dirname(__FILE__))
11
+
12
+ #
13
+ # in [jn0004]
14
+ # |--e3-->(j2)--e5-->|
15
+ # (S1)--e1-->(j1)--e2-->[F1] [J1]--e7-->(j4)--e8-->(E1)
16
+ # |--e4-->(j3)--e6-->|
17
+ #
18
+ # in [jn0004/finally]
19
+ # (S2) --e9-->(jn0004_f)-e10-->(E2)
20
+ #
21
+ # 現象:
22
+ # j1を強制停止した際に、プロセスが2つ動いている場合、その片方のプロセスAが
23
+ # stop.job.job.tengineイベントを受け取りSSHでtengine_job_agent_killを実行します。
24
+ # その実行の戻り値を得るまでの間に、もう片方のプロセスBが、プロセスが終了して発火される
25
+ # finished.process.job.tengineイベントを処理すると、stop_reasonがuser_stopでなくなってしまっていました。
26
+ #
27
+ context "jn0004" do
28
+ before do
29
+ Tengine::Resource::Server.delete_all
30
+ Tengine::Job::Execution.delete_all
31
+ Tengine::Job::Vertex.delete_all
32
+ TestCredentialFixture.test_credential1
33
+ TestServerFixture.test_server1
34
+ TestServerFixture.test_server2
35
+ builder = Rjn0004ParallelJobnetWithFinally.new
36
+ @root = builder.create_actual
37
+ @ctx = builder.context
38
+ @execution = Tengine::Job::Execution.create!({
39
+ :root_jobnet_id => @root.id,
40
+ })
41
+ @base_props = {
42
+ :execution_id => @execution.id.to_s,
43
+ :root_jobnet_id => @root.id.to_s,
44
+ :root_jobnet_name_path => @root.name_path,
45
+ :target_jobnet_id => @root.id.to_s,
46
+ :target_jobnet_name_path => @root.name_path,
47
+ }
48
+
49
+ # 2つのプロセスの代わりに、2つのカーネルを別のFiberで動かす
50
+ @bootstrap1 = Tengine::Core::Bootstrap.new(:tengined => { :load_path => driver_path })
51
+ @bootstrap1.kernel.tap{|k| k.bind; k.evaluate}
52
+ @tengine1 = Tengine::RSpec::ContextWrapper.new(@bootstrap1.kernel)
53
+ #
54
+ @bootstrap2 = Tengine::Core::Bootstrap.new(:tengined => { :load_path => driver_path })
55
+ @bootstrap2.kernel.tap{|k| k.bind; k.evaluate}
56
+ @tengine2 = Tengine::RSpec::ContextWrapper.new(@bootstrap2.kernel)
57
+ end
58
+
59
+ before do
60
+ @pid = "123"
61
+ @ctx[:e1].phase_key = :transmitted
62
+ @ctx[:j1].tap do |j|
63
+ j.phase_key = :running
64
+ j.executing_pid = @pid
65
+ end
66
+ @root.phase_key = :running
67
+ @root.version = 4
68
+ @root.save!
69
+
70
+ @f1 = Fiber.new do
71
+ @tengine1.should_not_fire
72
+ ssh1 = mock(:ssh1)
73
+ Net::SSH.should_receive(:start).with("localhost",
74
+ an_instance_of(Tengine::Resource::Credential),
75
+ an_instance_of(Hash)).once.and_yield(ssh1)
76
+ channel1 = mock(:channel1)
77
+ ssh1.stub(:open_channel).and_yield(channel1)
78
+ channel1.stub(:exec).with(any_args).and_yield(channel1, true)
79
+ channel1.should_receive(:on_close) do
80
+ Tengine.logger.debug( ("!" * 100) << "\non_close: Fiber.yield #{Process.pid} #{__FILE__}##{__LINE__}")
81
+ Fiber.yield
82
+ end # on_dataが呼び出される前に止める
83
+ channel1.stub(:on_data)
84
+ channel1.stub(:on_extended_data)
85
+ @tengine1.receive("stop.job.job.tengine", :properties => {
86
+ :stop_reason => "user_stop",
87
+ :target_job_id => @ctx.vertex(:j1).id.to_s,
88
+ :target_job_name_path => @ctx.vertex(:j1).name_path,
89
+ }.update(@base_props))
90
+ :end
91
+ end
92
+
93
+ @f2 = Fiber.new do
94
+ @tengine2.should_fire(:"error.job.job.tengine", {
95
+ :source_name => @ctx[:j1].name_as_resource,
96
+ :properties=>{
97
+ :target_job_id => @ctx.vertex(:j1).id.to_s,
98
+ :target_job_name_path => @ctx.vertex(:j1).name_path,
99
+ :exit_status=>nil,
100
+ }.update(@base_props)
101
+ })
102
+ @tengine2.receive("finished.process.job.tengine", :properties => {
103
+ :pid=>17485,
104
+ :exit_status=>nil,
105
+ :target_job_id => @ctx.vertex(:j1).id.to_s,
106
+ :target_job_name_path => @ctx.vertex(:j1).name_path,
107
+ }.update(@base_props))
108
+ :end
109
+ end
110
+
111
+ @j1 = @root.element("j1")
112
+
113
+ @root.reload
114
+ @root.version.should == 4
115
+ Tengine::Job.test_harness_clear
116
+ end
117
+
118
+ it "tengine_job_agent_killの戻り値の前にfinished.process.job.tengineが来ても強制終了となるべき" do
119
+ # f1-1.
120
+ Tengine.logger.info("1" * 100)
121
+ # Tengine::Job.should_receive(:test_harness).with(1, "before yield in update_with_lock").once
122
+ # Tengine::Job.should_receive(:test_harness).with(2, "after yield in update_with_lock").once{ Fiber.yield}
123
+ @f1.resume.should_not == :end
124
+ @root.reload
125
+ @root.version.should == 5
126
+ @root.element("j1").tap do |j|
127
+ j.phase_key.should == :dying
128
+ j.executing_pid.should == @pid
129
+ j.stop_reason.should == "user_stop"
130
+ end
131
+
132
+ # f2
133
+ Tengine.logger.info("2" * 100)
134
+ # Tengine::Job.should_receive(:test_harness).with(3, "before yield in update_with_lock").once
135
+ # Tengine::Job.should_receive(:test_harness).with(4, "after yield in update_with_lock").once{ Fiber.yield}
136
+ @f2.resume.should == :end
137
+ @root.reload
138
+ @root.version.should == 6
139
+ @root.element("j1").tap do |j|
140
+ j.phase_key.should == :error
141
+ j.executing_pid.should == @pid
142
+ j.stop_reason.should == "user_stop"
143
+ end
144
+
145
+ # f1-2.
146
+ Tengine.logger.info("3" * 100)
147
+ # Tengine::Job.should_receive(:test_harness).with(5, "after update_with_lock").once{ Fiber.yield}
148
+ @f1.resume.should == :end
149
+ @root.reload
150
+ @root.version.should == 6
151
+ @root.element("j1").tap do |j|
152
+ j.phase_key.should == :error
153
+ j.executing_pid.should == @pid
154
+ j.stop_reason.should == "user_stop"
155
+ end
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,623 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'tengine/rspec'
4
+
5
+ require 'net/ssh'
6
+
7
+ describe 'job_control_driver' do
8
+ include Tengine::RSpec::Extension
9
+
10
+ target_dsl File.expand_path("../../../../lib/tengine/job/drivers/job_control_driver.rb", File.dirname(__FILE__))
11
+ driver :job_control_driver
12
+
13
+ context "rjn0001" do
14
+ before do
15
+ Tengine::Job::Vertex.delete_all
16
+ builder = Rjn0001SimpleJobnetBuilder.new
17
+ @jobnet = builder.create_actual
18
+ @ctx = builder.context
19
+ @execution = Tengine::Job::Execution.create!({
20
+ :root_jobnet_id => @jobnet.id,
21
+ })
22
+ end
23
+
24
+ context "ジョブの起動イベントを受け取ったら" do
25
+ it "通常の場合" do
26
+ @jobnet.phase_key = :starting
27
+ @ctx.edge(:e1).phase_key = :transmitting
28
+ @ctx.vertex(:j11).phase_key = :ready
29
+ @jobnet.save!
30
+ @jobnet.reload
31
+ tengine.should_not_fire
32
+ mock_ssh = mock(:ssh)
33
+ mock_channel = mock(:channel)
34
+ Net::SSH.should_receive(:start).
35
+ with("localhost", an_instance_of(Tengine::Resource::Credential), an_instance_of(Hash)).and_yield(mock_ssh)
36
+ mock_ssh.should_receive(:open_channel).and_yield(mock_channel)
37
+ mock_channel.should_receive(:exec) do |*args|
38
+ args.length.should == 1
39
+ # args.first.should =~ %r<source \/etc\/profile && export MM_ACTUAL_JOB_ID=[0-9a-f]{24} MM_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_FULL_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_ACTUAL_JOB_NAME_PATH=\\"/rjn0001/j11\\" MM_ACTUAL_JOB_SECURITY_TOKEN= MM_SCHEDULE_ID=[0-9a-f]{24} MM_SCHEDULE_ESTIMATED_TIME= MM_TEMPLATE_JOB_ID=[0-9a-f]{24} MM_TEMPLATE_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" && tengine_job_agent_run -- \$HOME/j11\.sh>
40
+ args.first.should =~ %r<source \/etc\/profile>
41
+ args.first.should =~ %r<MM_ACTUAL_JOB_ID=[0-9a-f]{24} MM_ACTUAL_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\" MM_FULL_ACTUAL_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\" MM_ACTUAL_JOB_NAME_PATH=\"/rjn0001/j11\" MM_ACTUAL_JOB_SECURITY_TOKEN= MM_SCHEDULE_ID=[0-9a-f]{24} MM_SCHEDULE_ESTIMATED_TIME= MM_TEMPLATE_JOB_ID=[0-9a-f]{24} MM_TEMPLATE_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\">
42
+ args.first.should =~ %r<job_test j11>
43
+ end
44
+ tengine.receive("start.job.job.tengine", :properties => {
45
+ :execution_id => @execution.id.to_s,
46
+ :root_jobnet_id => @jobnet.id.to_s,
47
+ :root_jobnet_name_path => @jobnet.name_path,
48
+ :target_jobnet_id => @jobnet.id.to_s,
49
+ :target_jobnet_name_path => @jobnet.name_path,
50
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
51
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
52
+ })
53
+ @jobnet.reload
54
+ @ctx.edge(:e1).phase_key.should == :transmitted
55
+ @ctx.edge(:e2).phase_key.should == :active
56
+ @ctx.vertex(:j11).phase_key.should == :starting
57
+ end
58
+
59
+ context "starting直前stopによってinitializedになっている場合" do
60
+ [:starting, :running].each do |root_phase_key|
61
+
62
+ it "ルートが#{root_phase_key}" do
63
+ @jobnet.phase_key = root_phase_key
64
+ @ctx[:e1].phase_key = :closing
65
+ @ctx[:e2].phase_key = :closing
66
+ @ctx[:e3].phase_key = :closing
67
+ @ctx[:j11].phase_key = :initialized
68
+ @jobnet.save!
69
+ @jobnet.reload
70
+ tengine.should_fire(:"error.jobnet.job.tengine", {
71
+ :source_name => @ctx[:root].name_as_resource,
72
+ :properties=>{
73
+ :execution_id => @execution.id.to_s,
74
+ :root_jobnet_id => @jobnet.id.to_s,
75
+ :root_jobnet_name_path => @jobnet.name_path,
76
+ :target_jobnet_id => @jobnet.id.to_s,
77
+ :target_jobnet_name_path => @jobnet.name_path,
78
+ }
79
+ })
80
+ tengine.receive("start.job.job.tengine", :properties => {
81
+ :execution_id => @execution.id.to_s,
82
+ :root_jobnet_id => @jobnet.id.to_s,
83
+ :root_jobnet_name_path => @jobnet.name_path,
84
+ :target_jobnet_id => @jobnet.id.to_s,
85
+ :target_jobnet_name_path => @jobnet.name_path,
86
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
87
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
88
+ })
89
+ @jobnet.reload
90
+ @ctx.edge(:e1).phase_key.should == :closing
91
+ @ctx.edge(:e2).phase_key.should == :closed
92
+ @ctx.edge(:e3).phase_key.should == :closed
93
+ @ctx.vertex(:j11).phase_key.should == :initialized
94
+ @jobnet.phase_key.should == :error
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ it "存在しないスクリプトを実行しようとした場合、標準エラー出力にエラーメッセージが返されるので、それを保持する" do
101
+ @jobnet.phase_key = :starting
102
+ @ctx.edge(:e1).phase_key = :transmitting
103
+ @ctx.vertex(:j11).phase_key = :ready
104
+ @jobnet.save!
105
+ @jobnet.reload
106
+ mock_ssh = mock(:ssh)
107
+ Net::SSH.stub(:start).with(any_args).and_yield(mock_ssh)
108
+ mock_channel = mock(:channel)
109
+ mock_ssh.stub(:open_channel).and_yield(mock_channel)
110
+ mock_channel.stub(:exec).with(any_args).and_yield(mock_channel, true)
111
+ mock_channel.stub(:on_data)
112
+ mock_channel.should_receive(:on_extended_data).and_yield(mock_channel,
113
+ "session", "[Errno::ENOENT] No such file or directory - /home/goku/unexist_script.sh")
114
+ mock_channel.stub(:on_close)
115
+ tengine.should_fire(:"error.job.job.tengine", {
116
+ :source_name => @ctx[:j11].name_as_resource,
117
+ :properties=>{
118
+ :execution_id => @execution.id.to_s,
119
+ :root_jobnet_id => @jobnet.id.to_s,
120
+ :root_jobnet_name_path => @jobnet.name_path,
121
+ :target_jobnet_id => @jobnet.id.to_s,
122
+ :target_jobnet_name_path => @jobnet.name_path,
123
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
124
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
125
+ :exit_status=>nil,
126
+ :message=>"Failure to execute /rjn0001/j11 via SSH: [Errno::ENOENT] No such file or directory - /home/goku/unexist_script.sh"
127
+ }
128
+ })
129
+ tengine.receive("start.job.job.tengine", :properties => {
130
+ :execution_id => @execution.id.to_s,
131
+ :root_jobnet_id => @jobnet.id.to_s,
132
+ :root_jobnet_name_path => @jobnet.name_path,
133
+ :target_jobnet_id => @jobnet.id.to_s,
134
+ :target_jobnet_name_path => @jobnet.name_path,
135
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
136
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
137
+ })
138
+ @jobnet.reload
139
+ @ctx.edge(:e1).phase_key.should == :transmitted
140
+ @ctx.edge(:e2).phase_key.should == :active
141
+ @ctx.vertex(:j11).tap do |job|
142
+ job.phase_key.should == :error
143
+ job.error_messages.should == [
144
+ "[Errno::ENOENT] No such file or directory - /home/goku/unexist_script.sh",
145
+ "Failure to execute /rjn0001/j11 via SSH: [Errno::ENOENT] No such file or directory - /home/goku/unexist_script.sh"
146
+ ]
147
+ end
148
+ @jobnet.phase_key.should == :running
149
+ end
150
+
151
+ end
152
+
153
+
154
+ it "PIDを取得できたら" do
155
+ @ctx.edge(:e1).phase_key = :transmitted
156
+ @ctx.edge(:e2).phase_key = :active
157
+ @ctx.vertex(:j11).phase_key = :starting
158
+ @jobnet.save!
159
+ @jobnet.reload
160
+ tengine.should_not_fire
161
+ mock_event = mock(:event)
162
+ @pid = "123"
163
+ signal = Tengine::Job::Signal.new(mock_event)
164
+ signal.data = {:executing_pid => @pid}
165
+ @ctx.vertex(:j11).ack(signal) # このメソッド内ではsaveされないので、ここでreloadもしません。
166
+ @ctx.vertex(:j11).executing_pid.should == @pid
167
+ @ctx.edge(:e1).phase_key.should == :transmitted
168
+ @ctx.edge(:e2).phase_key.should == :active
169
+ @ctx.vertex(:j11).phase_key.should == :running
170
+ end
171
+
172
+ test_error_message1 = "Job process failed. STDOUT and STDERR were redirected to files. You can see them at /home/goku/stdout-1234.log and /home/goku/stderr-1234.log on the server test_server1"
173
+ {
174
+ :success => ["0", {}],
175
+ :error => ["1", {
176
+ :stdout_log => "/home/goku/stdout-1234.log",
177
+ :stderr_log => "/home/goku/stderr-1234.log",
178
+ :message => test_error_message1
179
+ }]
180
+ }.each do |phase_key, (exit_status, extra_props)|
181
+ it "ジョブ実行#{phase_key}の通知" do
182
+ test_key = "test_key.finished.process.job.tengine"
183
+ Tengine::Core::Event.delete_all(:conditions => {:key => test_key})
184
+ Tengine::Core::Event.create!(:event_type_name => "job.heartbeat.tengine", :key => test_key)
185
+ @jobnet.reload
186
+ j11 = @jobnet.find_descendant_by_name_path("/rjn0001/j11")
187
+ j11.executing_pid = "123"
188
+ j11.phase_key = :running
189
+ j11.previous_edges.length.should == 1
190
+ j11.previous_edges.first.phase_key = :transmitted
191
+ @ctx[:root].save!
192
+ tengine.should_fire(:"#{phase_key}.job.job.tengine",
193
+ :source_name => @ctx[:j11].name_as_resource,
194
+ :properties => {
195
+ :execution_id => @execution.id.to_s,
196
+ :root_jobnet_id => @jobnet.id.to_s,
197
+ :root_jobnet_name_path => @jobnet.name_path,
198
+ :target_jobnet_id => @jobnet.id.to_s,
199
+ :target_jobnet_name_path => @jobnet.name_path,
200
+ :target_job_id => @ctx[:j11].id.to_s,
201
+ :target_job_name_path => @ctx[:j11].name_path,
202
+ :exit_status => exit_status
203
+ })
204
+ tengine.receive(:"finished.process.job.tengine",
205
+ :key => test_key,
206
+ :source_name => @ctx[:j11].name_as_resource,
207
+ :properties => {
208
+ :execution_id => @execution.id.to_s,
209
+ :root_jobnet_id => @jobnet.id.to_s,
210
+ :root_jobnet_name_path => @jobnet.name_path,
211
+ :target_jobnet_id => @jobnet.id.to_s,
212
+ :target_jobnet_name_path => @jobnet.name_path,
213
+ :target_job_id => @ctx[:j11].id.to_s,
214
+ :target_job_name_path => @ctx[:j11].name_path,
215
+ :exit_status => exit_status
216
+ }.merge(extra_props))
217
+ @jobnet.reload
218
+ @ctx.edge(:e1).phase_key.should == :transmitted
219
+ @ctx.edge(:e2).phase_key.should == :active
220
+ @ctx.vertex(:j11).tap do |j|
221
+ j.phase_key.should == phase_key
222
+ j.exit_status.should == exit_status
223
+ if phase_key == :error
224
+ j.error_messages.should == [test_error_message1]
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ it "強制停止" do
231
+ @pid = "123"
232
+ @jobnet.reload
233
+ j11 = @jobnet.find_descendant_by_name_path("/rjn0001/j11")
234
+ j11.executing_pid = @pid
235
+ j11.phase_key = :running
236
+ j11.previous_edges.length.should == 1
237
+ j11.previous_edges.first.phase_key = :transmitted
238
+ @ctx[:root].save!
239
+
240
+ tengine.should_not_fire
241
+ mock_ssh = mock(:ssh)
242
+ mock_channel = mock(:channel)
243
+ Net::SSH.should_receive(:start).
244
+ with("localhost", an_instance_of(Tengine::Resource::Credential), an_instance_of(Hash)).and_yield(mock_ssh)
245
+ mock_ssh.should_receive(:open_channel).and_yield(mock_channel)
246
+ mock_channel.should_receive(:exec) do |*args|
247
+ interval = Tengine::Job::Killing::DEFAULT_KILLING_SIGNAL_INTERVAL
248
+ args.length.should == 1
249
+ args.first.should =~ %r<source \/etc\/profile>
250
+ args.first.should =~ %r<tengine_job_agent_kill #{@pid} #{interval} KILL$>
251
+ end
252
+ tengine.receive(:"stop.job.job.tengine",
253
+ :source_name => @ctx[:j11].name_as_resource,
254
+ :properties => {
255
+ :execution_id => @execution.id.to_s,
256
+ :root_jobnet_id => @jobnet.id.to_s,
257
+ :target_jobnet_id => @jobnet.id.to_s,
258
+ :target_job_id => @ctx[:j11].id.to_s,
259
+ })
260
+ @jobnet.reload
261
+ @ctx.edge(:e1).phase_key.should == :transmitted
262
+ @ctx.edge(:e2).phase_key.should == :active
263
+ @ctx.vertex(:j11).tap do |j|
264
+ j.phase_key.should == :dying
265
+ j.exit_status.should == nil
266
+ end
267
+ end
268
+
269
+ it "強制停止(ジョブネット)" do
270
+ @pid11 = "11"
271
+ @pid12 = "12"
272
+ @jobnet.reload
273
+ j11 = @jobnet.find_descendant_by_name_path("/rjn0001/j11")
274
+ j11.executing_pid = @pid11
275
+ j11.phase_key = :success
276
+ j11.previous_edges.length.should == 1
277
+ j11.previous_edges.first.phase_key = :transmitted
278
+ j12 = @jobnet.find_descendant_by_name_path("/rjn0001/j12")
279
+ j12.executing_pid = @pid12
280
+ j12.phase_key = :running
281
+ j12.previous_edges.length.should == 1
282
+ j12.previous_edges.first.phase_key = :transmitted
283
+ @ctx[:root].save!
284
+
285
+ # phase_key が success の j11 は fireされない
286
+ tengine.should_not_fire(:"stop.job.job.tengine")
287
+ # phase_key が running の j12 は fireされる
288
+ tengine.should_fire(:"stop.job.job.tengine",
289
+ :source_name => @ctx[:j12].name_as_resource,
290
+ :properties => {
291
+ :stop_reason => "user_stop",
292
+ :target_jobnet_id => @jobnet.id.to_s,
293
+ :target_jobnet_name_path => "/rjn0001",
294
+ :target_job_id => @ctx[:j12].id.to_s,
295
+ :target_job_name_path => "/rjn0001/j12",
296
+ :execution_id => @execution.id.to_s,
297
+ :root_jobnet_id => @jobnet.id.to_s,
298
+ :root_jobnet_name_path => "/rjn0001",
299
+ })
300
+ # jobnet に対して強制停止された
301
+ tengine.receive(:"stop.jobnet.job.tengine",
302
+ :source_name => @jobnet.name_as_resource,
303
+ :properties => {
304
+ :stop_reason => "user_stop",
305
+ :target_jobnet_id => @jobnet.id.to_s,
306
+ :target_jobnet_name_path => "/rjn0001",
307
+ :execution_id => @execution.id.to_s,
308
+ :root_jobnet_id => @jobnet.id.to_s,
309
+ :root_jobnet_name_path => "/rjn0001",
310
+ })
311
+ end
312
+
313
+ it "強制停止(後続のジョブ)" do
314
+ @pid11 = "11"
315
+ @pid12 = "12"
316
+ @jobnet.reload
317
+ j11 = @jobnet.find_descendant_by_name_path("/rjn0001/j11")
318
+ j11.executing_pid = @pid11
319
+ j11.phase_key = :success
320
+ j11.previous_edges.length.should == 1
321
+ j11.previous_edges.first.phase_key = :transmitted
322
+ j12 = @jobnet.find_descendant_by_name_path("/rjn0001/j12")
323
+ j12.executing_pid = @pid12
324
+ j12.phase_key = :running
325
+ j12.previous_edges.length.should == 1
326
+ j12.previous_edges.first.phase_key = :transmitted
327
+ @ctx[:root].save!
328
+
329
+ mock_ssh = mock(:ssh)
330
+ mock_channel = mock(:channel)
331
+ Net::SSH.should_receive(:start).
332
+ with("localhost", an_instance_of(Tengine::Resource::Credential), an_instance_of(Hash)).and_yield(mock_ssh)
333
+ mock_ssh.should_receive(:open_channel).and_yield(mock_channel)
334
+ mock_channel.should_receive(:exec) do |*args|
335
+ interval = Tengine::Job::Killing::DEFAULT_KILLING_SIGNAL_INTERVAL
336
+ args.length.should == 1
337
+ args.first.should =~ %r<source \/etc\/profile>
338
+ args.first.should =~ %r<tengine_job_agent_kill #{@pid12} #{interval} KILL$>
339
+ end
340
+
341
+ # job12 に対して強制停止
342
+ tengine.receive(:"stop.job.job.tengine",
343
+ :source_name => @ctx[:j12].name_as_resource,
344
+ :properties => {
345
+ :stop_reason => "user_stop",
346
+ :target_jobnet_id => @jobnet.id.to_s,
347
+ :target_jobnet_name_path => "/rjn0001",
348
+ :target_job_id => @ctx[:j12].id.to_s,
349
+ :target_job_name_path => "/rjn0001/j12",
350
+ :execution_id => @execution.id.to_s,
351
+ :root_jobnet_id => @jobnet.id.to_s,
352
+ :root_jobnet_name_path => "/rjn0001",
353
+ })
354
+ @jobnet.reload
355
+ @ctx.edge(:e1).phase_key.should == :transmitted
356
+ @ctx.edge(:e2).phase_key.should == :transmitted
357
+ @ctx.edge(:e3).phase_key.should == :active
358
+ @ctx.vertex(:j11).tap do |j|
359
+ j.phase_key.should == :success
360
+ j.stop_reason.should == nil
361
+ end
362
+ @ctx.vertex(:j12).tap do |j|
363
+ j.phase_key.should == :dying
364
+ j.stop_reason.should == "user_stop"
365
+ end
366
+ end
367
+
368
+
369
+ if ENV['PASSWORD']
370
+ context "実際にSSHで接続", :ssh_actual => true do
371
+ before do
372
+ resource_fixture = GokuAtEc2ApNortheast.new
373
+ credential = resource_fixture.goku_ssh_pw
374
+ credential.auth_values = {:username => ENV['USER'], :password => ENV['PASSWORD']}
375
+ credential.save!
376
+ server = resource_fixture.hadoop_master_node
377
+ server.local_ipv4 = "127.0.0.1"
378
+ server.save!
379
+ end
380
+
381
+ it do
382
+ tengine.should_not_fire
383
+ tengine.receive("start.job.job.tengine", :properties => {
384
+ :execution_id => @execution.id.to_s,
385
+ :root_jobnet_id => @jobnet.id.to_s,
386
+ :target_jobnet_id => @jobnet.id.to_s,
387
+ })
388
+ @jobnet.reload
389
+ j11 = @jobnet.find_descendant_by_name_path("/rjn0001/j11")
390
+ j11.executing_pid.should_not be_nil
391
+ j11.exit_status.should == nil
392
+ j11.phase_key.should == :running
393
+ j11.previous_edges.length.should == 1
394
+ j11.previous_edges.first.phase_key.should == :transmitted
395
+ end
396
+
397
+ end
398
+ end
399
+ end
400
+
401
+ context "再実行" do
402
+ context "ジョブを再実行" do
403
+ {
404
+ false => "後続も実行",
405
+ true => "スポット再実行"
406
+ }.each do |spot, caption|
407
+ context(caption) do
408
+
409
+ before do
410
+ Tengine::Job::Vertex.delete_all
411
+ builder = Rjn0001SimpleJobnetBuilder.new
412
+ @root = builder.create_actual
413
+ @ctx = builder.context
414
+ @execution = Tengine::Job::Execution.create!({
415
+ :root_jobnet_id => @root.id,
416
+ :spot => spot, :retry => true,
417
+ :target_actual_ids => [@ctx[:j11].id.to_s]
418
+ })
419
+ @root.phase_key = :running
420
+ @ctx[:j11].phase_key = :success
421
+ @ctx[:j12].phase_key = :error
422
+ @ctx[:e1].phase_key = :transmitted
423
+ @ctx[:e2].phase_key = :transmitted
424
+ @ctx[:e3].phase_key = :active
425
+ end
426
+
427
+ [:initialized, :success, :error, :stuck].each do |phase_key|
428
+ it "phase_keyが#{phase_key}ならば再実行できるので、startのイベントを発火する" do
429
+ @ctx[:j11].phase_key = phase_key
430
+ @root.save!
431
+ tengine.should_fire(:"start.job.job.tengine", {
432
+ :source_name => @ctx[:j11].name_as_resource,
433
+ :properties=>{
434
+ :execution_id => @execution.id.to_s,
435
+ :root_jobnet_name_path => @root.name_path,
436
+ :root_jobnet_id => @root.id.to_s,
437
+ :target_jobnet_name_path => @root.name_path,
438
+ :target_jobnet_id => @root.id.to_s,
439
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
440
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
441
+ }
442
+ })
443
+ tengine.receive("restart.job.job.tengine", :properties => {
444
+ :execution_id => @execution.id.to_s,
445
+ :root_jobnet_id => @root.id.to_s,
446
+ :root_jobnet_name_path => @root.name_path,
447
+ :target_jobnet_id => @root.id.to_s,
448
+ :target_jobnet_name_path => @root.name_path,
449
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
450
+ :target_job_name_path => @ctx.vertex(:j11).name_path,
451
+ })
452
+ @root.reload
453
+ @root.phase_key.should == :running
454
+ @ctx.edge(:e1).phase_key.should == :transmitted
455
+ @ctx.vertex(:j11).phase_key.should == :ready
456
+ if spot
457
+ @ctx.vertex(:j12).phase_key.should == :error
458
+ @ctx.edge(:e2).phase_key.should == :transmitted
459
+ @ctx.edge(:e3).phase_key.should == :active
460
+ else
461
+ @ctx.vertex(:j12).phase_key.should == :initialized
462
+ @ctx.edge(:e2).phase_key.should == :active
463
+ @ctx.edge(:e3).phase_key.should == :active
464
+ end
465
+ end
466
+ end
467
+
468
+ [:ready, :starting, :running, :dying].each do |phase_key|
469
+ it "phase_keyが#{phase_key}ならば再実行できず、エラーのイベントを発火する" do
470
+ @ctx[:j11].phase_key = phase_key
471
+ @root.save!
472
+ tengine.should_fire("restart.job.job.tengine.error.tengined").with(any_args)
473
+ Tengine::Core::Kernel.temp_exception_reporter(:except_test) do
474
+ tengine.receive("restart.job.job.tengine", :properties => {
475
+ :execution_id => @execution.id.to_s,
476
+ :root_jobnet_id => @root.id.to_s,
477
+ :target_jobnet_id => @root.id.to_s,
478
+ :target_job_id => @ctx.vertex(:j11).id.to_s,
479
+ })
480
+ end
481
+ # 再実行に失敗したのでルートジョブネット以下何も状態は変更されません
482
+ @root.reload
483
+ @root.phase_key.should == :running
484
+ @ctx.edge(:e1).phase_key.should == :transmitted
485
+ @ctx.vertex(:j11).phase_key.should == phase_key
486
+ end
487
+
488
+ end
489
+ end
490
+ end
491
+
492
+ end
493
+
494
+ end
495
+
496
+
497
+ context "<BUG>同じジョブネットが複数バージョン存在する際、ジョブ実行時にスクリプトに渡される環境変数の「MM_TEMPLATE_JOB_ID」「MM_TEMPLATE_JOB_ANCESTOR_IDS」が実行しているバージョン以外のものがセットされている" do
498
+ shared_examples_for "最新のバージョンのルートジョブネットを参照する" do |dsl_version|
499
+
500
+ it do
501
+ @root.phase_key = :starting
502
+ @root.element("prev!j11").phase_key = :transmitting
503
+ @root.element('j11').phase_key = :ready
504
+ @root.save!
505
+ @root.reload
506
+ tengine.should_not_fire
507
+ mock_ssh = mock(:ssh)
508
+ mock_channel = mock(:channel)
509
+ Net::SSH.should_receive(:start).
510
+ with("localhost", an_instance_of(Tengine::Resource::Credential), an_instance_of(Hash)).and_yield(mock_ssh)
511
+ mock_ssh.should_receive(:open_channel).and_yield(mock_channel)
512
+ mock_channel.should_receive(:exec) do |*args|
513
+ args.length.should == 1
514
+ # args.first.should =~ %r<source \/etc\/profile && export MM_ACTUAL_JOB_ID=[0-9a-f]{24} MM_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_FULL_ACTUAL_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" MM_ACTUAL_JOB_NAME_PATH=\\"/rjn0001/j11\\" MM_ACTUAL_JOB_SECURITY_TOKEN= MM_SCHEDULE_ID=[0-9a-f]{24} MM_SCHEDULE_ESTIMATED_TIME= MM_TEMPLATE_JOB_ID=[0-9a-f]{24} MM_TEMPLATE_JOB_ANCESTOR_IDS=\\"[0-9a-f]{24}\\" && tengine_job_agent_run -- \$HOME/j11\.sh>
515
+ args.first.should =~ %r<source \/etc\/profile>
516
+ args.first.should =~ %r<MM_ACTUAL_JOB_ID=[0-9a-f]{24} MM_ACTUAL_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\" MM_FULL_ACTUAL_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\" MM_ACTUAL_JOB_NAME_PATH=\"/rjn0001/j11\" MM_ACTUAL_JOB_SECURITY_TOKEN= MM_SCHEDULE_ID=[0-9a-f]{24} MM_SCHEDULE_ESTIMATED_TIME= MM_TEMPLATE_JOB_ID=[0-9a-f]{24} MM_TEMPLATE_JOB_ANCESTOR_IDS=\"[0-9a-f]{24}\">
517
+ @template.dsl_version.should == dsl_version
518
+ template_job = @template.element("/rjn0001/j11")
519
+ args.first.should =~ %r<MM_TEMPLATE_JOB_ID=#{template_job.id.to_s}>
520
+ args.first.should =~ %r<MM_TEMPLATE_JOB_ANCESTOR_IDS=\"#{@template.id.to_s}\">
521
+ args.first.should =~ %r<job_test j11>
522
+ end
523
+ tengine.receive("start.job.job.tengine", :properties => {
524
+ :execution_id => @execution.id.to_s,
525
+ :root_jobnet_id => @root.id.to_s,
526
+ :root_jobnet_name_path => @root.name_path,
527
+ :target_jobnet_id => @root.id.to_s,
528
+ :target_jobnet_name_path => @root.name_path,
529
+ :target_job_id => @root.element('j11').id.to_s,
530
+ :target_job_name_path => @root.element('j11').name_path,
531
+ })
532
+ @root.reload
533
+ @root.element('prev!j11').phase_key.should == :transmitted
534
+ @root.element('next!j11').phase_key.should == :active
535
+ @root.element('j11').phase_key.should == :starting
536
+ end
537
+ end
538
+
539
+ context "バージョン1つだけ" do
540
+ before do
541
+ Tengine::Core::Setting.delete_all
542
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => "1")
543
+ Tengine::Job::Vertex.delete_all
544
+ Rjn0001SimpleJobnetBuilder.new.tap do |builder|
545
+ @template = builder.create_template(:dsl_version => "1")
546
+ @root = @template.generate
547
+ @ctx = builder.context
548
+ end
549
+ @execution = Tengine::Job::Execution.create!({
550
+ :root_jobnet_id => @root.id,
551
+ })
552
+ end
553
+ it{ @root.template.dsl_version.should == "1" }
554
+ it_should_behave_like "最新のバージョンのルートジョブネットを参照する", "1"
555
+ end
556
+
557
+ context "バージョン2つ" do
558
+ before do
559
+ Tengine::Core::Setting.delete_all
560
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => "2")
561
+ Tengine::Job::Vertex.delete_all
562
+ Rjn0001SimpleJobnetBuilder.new.tap do |builder|
563
+ builder.create_template(:dsl_version => "1")
564
+ @template = builder.create_template(:dsl_version => "2")
565
+ @root = @template.generate
566
+ @ctx = builder.context
567
+ end
568
+ @execution = Tengine::Job::Execution.create!({
569
+ :root_jobnet_id => @root.id,
570
+ })
571
+ end
572
+ it{ @root.template.dsl_version.should == "2" }
573
+ it_should_behave_like "最新のバージョンのルートジョブネットを参照する", "2"
574
+ end
575
+
576
+ context "バージョン10個" do
577
+ before do
578
+ Tengine::Core::Setting.delete_all
579
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => "10")
580
+ Tengine::Job::Vertex.delete_all
581
+ Rjn0001SimpleJobnetBuilder.new.tap do |builder|
582
+ (1..9).each do |idx|
583
+ builder.create_template(:dsl_version => idx.to_s)
584
+ end
585
+ @template = builder.create_template(:dsl_version => "10")
586
+ @root = @template.generate
587
+ @ctx = builder.context
588
+ end
589
+ @execution = Tengine::Job::Execution.create!({
590
+ :root_jobnet_id => @root.id,
591
+ })
592
+ end
593
+ it{ @root.template.dsl_version.should == "10" }
594
+ it_should_behave_like "最新のバージョンのルートジョブネットを参照する", "10"
595
+ end
596
+ end
597
+
598
+ context "https://www.pivotaltracker.com/story/show/22624209" do
599
+ it "stuckにする" do
600
+ Tengine::Core::Schedule.delete_all
601
+ Tengine::Job::Vertex.delete_all
602
+ builder = Rjn0001SimpleJobnetBuilder.new
603
+ @root = builder.create_actual
604
+ @ctx = builder.context
605
+ @execution = Tengine::Job::Execution.create!({
606
+ :root_jobnet_id => @root.id,
607
+ })
608
+ @root.phase_key = :initialized
609
+ @root.save!
610
+ EM.run_block do
611
+ tengine.receive("expired.job.heartbeat.tengine", :properties => {
612
+ :execution_id => @execution.id.to_s,
613
+ :root_jobnet_id => @root.id.to_s,
614
+ :target_job_id => @root.children[1].id.to_s,
615
+ })
616
+ end
617
+ @root.reload
618
+ @root.children[1].phase_key.should == :stuck
619
+ @root.phase_key.should_not == :stuck # initialized
620
+ end
621
+ end
622
+
623
+ end