mortar 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
data/lib/mortar/command/jobs.rb
CHANGED
@@ -23,6 +23,10 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
23
23
|
|
24
24
|
include Mortar::Git
|
25
25
|
|
26
|
+
CLUSTER_TYPE__SINGLE_JOB = 'single_job'
|
27
|
+
CLUSTER_TYPE__PERSISTENT = 'persistent'
|
28
|
+
CLUSTER_TYPE__PERMANENT = 'permanent'
|
29
|
+
|
26
30
|
# jobs
|
27
31
|
#
|
28
32
|
# Show recent and running jobs.
|
@@ -57,6 +61,7 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
57
61
|
# -c, --clusterid CLUSTERID # Run job on an existing cluster with ID of CLUSTERID (optional)
|
58
62
|
# -s, --clustersize NUMNODES # Run job on a new cluster, with NUMNODES nodes (optional; must be >= 2 if provided)
|
59
63
|
# -1, --singlejobcluster # Stop the cluster after job completes. (Default: false—-cluster can be used for other jobs, and will shut down after 1 hour of inactivity)
|
64
|
+
# -2, --permanentcluster # Don't automatically stop the cluster after it has been idle for an hour (Default: false--cluster will be shut down after 1 hour of inactivity)
|
60
65
|
# -p, --parameter NAME=VALUE # Set a pig parameter value in your script.
|
61
66
|
# -f, --param-file PARAMFILE # Load pig parameter values from a file.
|
62
67
|
# -d, --donotnotify # Don't send an email on job completion. (Default: false--an email will be sent to you once the job completes)
|
@@ -102,7 +107,7 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
102
107
|
end
|
103
108
|
|
104
109
|
if options[:clusterid]
|
105
|
-
[:clustersize, :singlejobcluster].each do |opt|
|
110
|
+
[:clustersize, :singlejobcluster, :permanentcluster].each do |opt|
|
106
111
|
unless options[opt].nil?
|
107
112
|
error("Option #{opt.to_s} cannot be set when running a job on an existing cluster (with --clusterid option)")
|
108
113
|
end
|
@@ -116,11 +121,19 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
116
121
|
# post job to API
|
117
122
|
response = action("Requesting job execution") do
|
118
123
|
if options[:clustersize]
|
124
|
+
if options[:singlejobcluster] && options[:permanentcluster]
|
125
|
+
error("Cannot declare cluster as both --singlejobcluster and --permanentcluster")
|
126
|
+
end
|
119
127
|
cluster_size = options[:clustersize].to_i
|
120
|
-
|
128
|
+
cluster_type = CLUSTER_TYPE__PERSISTENT
|
129
|
+
if options[:singlejobcluster]
|
130
|
+
cluster_type = CLUSTER_TYPE__SINGLE_JOB
|
131
|
+
elsif options[:permanentcluster]
|
132
|
+
cluster_type = CLUSTER_TYPE__PERMANENT
|
133
|
+
end
|
121
134
|
api.post_job_new_cluster(project.name, script.name, git_ref, cluster_size,
|
122
135
|
:parameters => pig_parameters,
|
123
|
-
:
|
136
|
+
:cluster_type => cluster_type,
|
124
137
|
:notify_on_job_finish => notify_on_job_finish,
|
125
138
|
:is_control_script => is_control_script).body
|
126
139
|
else
|
@@ -22,7 +22,7 @@ require "mortar/local/jython"
|
|
22
22
|
|
23
23
|
|
24
24
|
class Mortar::Local::Controller
|
25
|
-
include Mortar::
|
25
|
+
include Mortar::Local::InstallUtil
|
26
26
|
|
27
27
|
NO_JAVA_ERROR_MESSAGE = <<EOF
|
28
28
|
A suitable java installation could not be found. If you already have java installed
|
@@ -42,8 +42,8 @@ https://pypi.python.org/pypi/virtualenv
|
|
42
42
|
EOF
|
43
43
|
|
44
44
|
NO_AWS_KEYS_ERROR_MESSAGE = <<EOF
|
45
|
-
Please specify your aws access key via
|
46
|
-
and your aws secret key via
|
45
|
+
Please specify your aws access key via environment variable AWS_ACCESS_KEY
|
46
|
+
and your aws secret key via environment variable AWS_SECRET_KEY"
|
47
47
|
EOF
|
48
48
|
|
49
49
|
|
@@ -91,6 +91,19 @@ EOF
|
|
91
91
|
|
92
92
|
jy = Mortar::Local::Jython.new()
|
93
93
|
jy.install_or_update()
|
94
|
+
|
95
|
+
ensure_local_install_dir_in_gitignore
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_local_install_dir_in_gitignore()
|
99
|
+
if File.exists? local_project_gitignore
|
100
|
+
open(local_project_gitignore, 'r+') do |gitignore|
|
101
|
+
unless gitignore.read().include? local_install_directory_name
|
102
|
+
gitignore.seek(0, IO::SEEK_END)
|
103
|
+
gitignore.puts local_install_directory_name
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
94
107
|
end
|
95
108
|
|
96
109
|
# Main entry point for user running a pig script
|
@@ -28,10 +28,26 @@ module Mortar
|
|
28
28
|
|
29
29
|
include Mortar::Helpers
|
30
30
|
|
31
|
-
def
|
31
|
+
def local_install_directory_name
|
32
|
+
".mortar-local"
|
33
|
+
end
|
34
|
+
|
35
|
+
def project_root
|
32
36
|
# note: assumes that CWD is the project root, is
|
33
37
|
# this a safe assumption?
|
34
|
-
|
38
|
+
Dir.getwd
|
39
|
+
end
|
40
|
+
|
41
|
+
def local_install_directory
|
42
|
+
File.join(project_root, local_install_directory_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def local_pig_logfile
|
46
|
+
project_root + "/local-pig.log"
|
47
|
+
end
|
48
|
+
|
49
|
+
def local_project_gitignore
|
50
|
+
project_root + "/.gitignore"
|
35
51
|
end
|
36
52
|
|
37
53
|
def jython_directory
|
@@ -42,6 +58,10 @@ module Mortar
|
|
42
58
|
jython_directory + "/cachedir"
|
43
59
|
end
|
44
60
|
|
61
|
+
def gitignore_template_path
|
62
|
+
File.expand_path("../../templates/project/gitignore", __FILE__)
|
63
|
+
end
|
64
|
+
|
45
65
|
# Drops a marker file for an installed package, used
|
46
66
|
# to help determine if updates should be performed
|
47
67
|
def note_install(subdirectory)
|
data/lib/mortar/local/pig.rb
CHANGED
@@ -224,6 +224,7 @@ class Mortar::Local::Pig
|
|
224
224
|
# get it to do something interesting, such as '-f some-file.pig'
|
225
225
|
def run_pig_command(cmd, parameters = nil, jython_output = true)
|
226
226
|
unset_hadoop_env_vars
|
227
|
+
delete_local_log_file
|
227
228
|
# Generate the script for running the command, then
|
228
229
|
# write it to a temp script which will be exectued
|
229
230
|
script_text = script_for_command(cmd, parameters)
|
@@ -243,6 +244,12 @@ class Mortar::Local::Pig
|
|
243
244
|
ENV['HADOOP_CONF_DIR'] = ''
|
244
245
|
end
|
245
246
|
|
247
|
+
def delete_local_log_file
|
248
|
+
if File.exists? local_pig_logfile
|
249
|
+
FileUtils.rm local_pig_logfile
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
246
253
|
# Generates a bash script which sets up the necessary environment and
|
247
254
|
# then runs the pig command
|
248
255
|
def script_for_command(cmd, parameters, jython_output = true)
|
@@ -278,6 +285,7 @@ class Mortar::Local::Pig
|
|
278
285
|
opts['fs.s3n.awsAccessKeyId'] = ENV['AWS_ACCESS_KEY']
|
279
286
|
opts['fs.s3n.awsSecretAccessKey'] = ENV['AWS_SECRET_KEY']
|
280
287
|
opts['pig.events.logformat'] = PIG_LOG_FORMAT
|
288
|
+
opts['pig.logfile'] = local_pig_logfile
|
281
289
|
opts['python.verbose'] = 'error'
|
282
290
|
opts['jython.output'] = true
|
283
291
|
opts['python.home'] = jython_directory
|
data/lib/mortar/version.rb
CHANGED
@@ -48,7 +48,7 @@ module Mortar::Command
|
|
48
48
|
|
49
49
|
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
50
50
|
:parameters => match_array([{"name" => "FIRST_PARAM", "value" => "FOO"}, {"name" => "SECOND_PARAM", "value" => "BAR"}]),
|
51
|
-
:
|
51
|
+
:cluster_type => Jobs::CLUSTER_TYPE__SINGLE_JOB,
|
52
52
|
:notify_on_job_finish => true,
|
53
53
|
:is_control_script=> false) {Excon::Response.new(:body => {"job_id" => job_id, "web_job_url" => job_url})}
|
54
54
|
|
@@ -71,7 +71,64 @@ Or by running:
|
|
71
71
|
STDOUT
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
|
+
it "handles permanentcluster parameter" do
|
76
|
+
with_git_initialized_project do |p|
|
77
|
+
# stub api requests
|
78
|
+
job_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
|
79
|
+
job_url = "http://127.0.0.1:5000/jobs/job_detail?job_id=c571a8c7f76a4fd4a67c103d753e2dd5"
|
80
|
+
cluster_size = 5
|
81
|
+
|
82
|
+
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
83
|
+
:parameters => match_array([{"name" => "FIRST_PARAM", "value" => "FOO"}, {"name" => "SECOND_PARAM", "value" => "BAR"}]),
|
84
|
+
:cluster_type => Jobs::CLUSTER_TYPE__PERMANENT,
|
85
|
+
:notify_on_job_finish => true,
|
86
|
+
:is_control_script=> false) {Excon::Response.new(:body => {"job_id" => job_id, "web_job_url" => job_url})}
|
87
|
+
|
88
|
+
write_file(File.join(p.pigscripts_path, "my_script.pig"))
|
89
|
+
stderr, stdout = execute("jobs:run my_script -2 --clustersize 5 -p FIRST_PARAM=FOO -p SECOND_PARAM=BAR", p, @git)
|
90
|
+
stdout.should == <<-STDOUT
|
91
|
+
Taking code snapshot... done
|
92
|
+
Sending code snapshot to Mortar... done
|
93
|
+
Requesting job execution... done
|
94
|
+
job_id: c571a8c7f76a4fd4a67c103d753e2dd5
|
95
|
+
|
96
|
+
Job status can be viewed on the web at:
|
97
|
+
|
98
|
+
http://127.0.0.1:5000/jobs/job_detail?job_id=c571a8c7f76a4fd4a67c103d753e2dd5
|
99
|
+
|
100
|
+
Or by running:
|
101
|
+
|
102
|
+
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5 --poll
|
103
|
+
|
104
|
+
STDOUT
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
it "throws error on singlejobcluster and permanentcluster" do
|
110
|
+
with_git_initialized_project do |p|
|
111
|
+
|
112
|
+
write_file(File.join(p.pigscripts_path, "my_script.pig"))
|
113
|
+
stderr, stdout = execute("jobs:run my_script -2 -1 --clustersize 5 -p FIRST_PARAM=FOO -p SECOND_PARAM=BAR", p, @git)
|
114
|
+
stderr.should == <<-STDERR
|
115
|
+
! Cannot declare cluster as both --singlejobcluster and --permanentcluster
|
116
|
+
STDERR
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it "throws error on clusterid and permanentcluster" do
|
121
|
+
with_git_initialized_project do |p|
|
122
|
+
cluster_id = "e2790e7e8c7d48e39157238d58191346"
|
123
|
+
|
124
|
+
write_file(File.join(p.pigscripts_path, "my_script.pig"))
|
125
|
+
stderr, stdout = execute("jobs:run my_script -2 --clusterid e2790e7e8c7d48e39157238d58191346 -p FIRST_PARAM=FOO -p SECOND_PARAM=BAR", p, @git)
|
126
|
+
stderr.should == <<-STDERR
|
127
|
+
! Option permanentcluster cannot be set when running a job on an existing cluster (with --clusterid option)
|
128
|
+
STDERR
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
75
132
|
it "runs a job on a new cluster" do
|
76
133
|
with_git_initialized_project do |p|
|
77
134
|
# stub api requests
|
@@ -81,7 +138,7 @@ STDOUT
|
|
81
138
|
|
82
139
|
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
83
140
|
:parameters => match_array([{"name" => "FIRST_PARAM", "value" => "FOO"}, {"name" => "SECOND_PARAM", "value" => "BAR"}]),
|
84
|
-
:
|
141
|
+
:cluster_type => Jobs::CLUSTER_TYPE__PERSISTENT,
|
85
142
|
:notify_on_job_finish => true,
|
86
143
|
:is_control_script=>false) {Excon::Response.new(:body => {"job_id" => job_id, "web_job_url" => job_url})}
|
87
144
|
|
@@ -146,7 +203,7 @@ STDOUT
|
|
146
203
|
mock(Mortar::Auth.api).get_clusters() {Excon::Response.new(:body => {'clusters' => []})}
|
147
204
|
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
148
205
|
:parameters => [],
|
149
|
-
:
|
206
|
+
:cluster_type => Jobs::CLUSTER_TYPE__PERSISTENT,
|
150
207
|
:notify_on_job_finish => true,
|
151
208
|
:is_control_script=>false) {Excon::Response.new(:body => {"job_id" => job_id, "web_job_url" => job_url})}
|
152
209
|
|
@@ -262,11 +319,10 @@ STDOUT
|
|
262
319
|
with_git_initialized_project do |p|
|
263
320
|
job_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
|
264
321
|
cluster_size = 5
|
265
|
-
keepalive = true
|
266
322
|
|
267
323
|
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
268
324
|
:parameters => match_array([{"name" => "FIRST", "value" => "FOO"}, {"name" => "SECOND", "value" => "BAR"}, {"name" => "THIRD", "value" => "BEAR\n"}]),
|
269
|
-
:
|
325
|
+
:cluster_type => Jobs::CLUSTER_TYPE__PERSISTENT,
|
270
326
|
:notify_on_job_finish => true,
|
271
327
|
:is_control_script=>false) {Excon::Response.new(:body => {"job_id" => job_id})}
|
272
328
|
|
@@ -288,11 +344,10 @@ PARAMS
|
|
288
344
|
with_git_initialized_project do |p|
|
289
345
|
job_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
|
290
346
|
cluster_size = 5
|
291
|
-
keepalive = true
|
292
347
|
|
293
348
|
mock(Mortar::Auth.api).post_job_new_cluster("myproject", "my_script", is_a(String), cluster_size,
|
294
349
|
:parameters => match_array([{"name" => "FIRST", "value" => "FOO"}, {"name" => "SECOND", "value" => "BAR"}, {"name" => "THIRD", "value" => "BEAR\n"}]),
|
295
|
-
:
|
350
|
+
:cluster_type => Jobs::CLUSTER_TYPE__PERSISTENT,
|
296
351
|
:notify_on_job_finish => true,
|
297
352
|
:is_control_script=>false) {Excon::Response.new(:body => {"job_id" => job_id})}
|
298
353
|
|
@@ -315,7 +370,6 @@ PARAMS
|
|
315
370
|
with_git_initialized_project do |p|
|
316
371
|
job_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
|
317
372
|
cluster_size = 5
|
318
|
-
keepalive = true
|
319
373
|
|
320
374
|
write_file(File.join(p.pigscripts_path, "my_script.pig"))
|
321
375
|
|
@@ -140,6 +140,9 @@ STDERR
|
|
140
140
|
any_instance_of(Mortar::Local::Jython) do |j|
|
141
141
|
mock(j).install_or_update.returns(true)
|
142
142
|
end
|
143
|
+
any_instance_of(Mortar::Local::Controller) do |j|
|
144
|
+
mock(j).ensure_local_install_dir_in_gitignore.returns(true)
|
145
|
+
end
|
143
146
|
stderr, stdout = execute("local:configure")
|
144
147
|
stderr.should == ""
|
145
148
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mortar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 7
|
9
|
-
-
|
10
|
-
version: 0.7.
|
9
|
+
- 3
|
10
|
+
version: 0.7.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mortar Data
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-03-
|
18
|
+
date: 2013-03-29 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: mortar-api-ruby
|
@@ -25,12 +25,12 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 1
|
29
29
|
segments:
|
30
30
|
- 0
|
31
31
|
- 6
|
32
|
-
-
|
33
|
-
version: 0.6.
|
32
|
+
- 3
|
33
|
+
version: 0.6.3
|
34
34
|
type: :runtime
|
35
35
|
version_requirements: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|