elasticity 2.2 → 2.3
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.
- data/HISTORY.md +5 -0
- data/README.md +3 -2
- data/lib/elasticity/aws_request.rb +3 -3
- data/lib/elasticity/job_flow.rb +19 -8
- data/lib/elasticity/version.rb +1 -1
- data/spec/lib/elasticity/aws_request_spec.rb +36 -21
- data/spec/lib/elasticity/job_flow_integration_spec.rb +4 -1
- data/spec/lib/elasticity/job_flow_spec.rb +24 -12
- metadata +2 -2
data/HISTORY.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 2.3 - July 28, 2012
|
2
|
+
|
3
|
+
+ ```JobFlow``` now supports specifying availbility zone instance specification via ```JobFlow#placement=```.
|
4
|
+
+ ```JobFlow::from_jobflow_id``` now supports region specification so that jobs created in regions other than us-east-1 can be recreated.
|
5
|
+
|
1
6
|
## 2.2 - July 23, 2012
|
2
7
|
|
3
8
|
+ Hadoop streaming jobs are now supported via ```Elasticity::StreamingStep```.
|
data/README.md
CHANGED
@@ -70,10 +70,10 @@ jobflow = Elasticity::JobFlow.new('AWS access key', 'AWS secret key')
|
|
70
70
|
If you want to access a job flow that's already running:
|
71
71
|
|
72
72
|
```ruby
|
73
|
-
jobflow = Elasticity::JobFlow.from_jobflow_id('AWS access key', 'AWS secret key', 'jobflow ID')
|
73
|
+
jobflow = Elasticity::JobFlow.from_jobflow_id('AWS access key', 'AWS secret key', 'jobflow ID', 'region')
|
74
74
|
```
|
75
75
|
|
76
|
-
This is useful if you'd like to attach to a running job flow and add more steps, etc.
|
76
|
+
This is useful if you'd like to attach to a running job flow and add more steps, etc. The ```region``` parameter is necessary because job flows are only accessible from the the API when you connect to the same endpoint that created them (e.g. us-west-1). If you don't specify the ```region``` parameter, us-east-1 is assumed.
|
77
77
|
|
78
78
|
## 2 - Specifying Job Flow Options
|
79
79
|
|
@@ -90,6 +90,7 @@ jobflow.hadoop_version = '0.20.205'
|
|
90
90
|
jobflow.keep_job_flow_alive_when_no_steps = true
|
91
91
|
jobflow.log_uri = nil
|
92
92
|
jobflow.name = 'Elasticity Job Flow'
|
93
|
+
jobflow.placement = 'us-east-1a'
|
93
94
|
jobflow.instance_count = 2
|
94
95
|
jobflow.master_instance_type = 'm1.small'
|
95
96
|
jobflow.slave_instance_type = 'm1.small'
|
@@ -4,7 +4,6 @@ module Elasticity
|
|
4
4
|
|
5
5
|
attr_reader :access_key
|
6
6
|
attr_reader :secret_key
|
7
|
-
attr_reader :options
|
8
7
|
attr_reader :host
|
9
8
|
attr_reader :protocol
|
10
9
|
|
@@ -14,7 +13,7 @@ module Elasticity
|
|
14
13
|
def initialize(access, secret, options = {})
|
15
14
|
@access_key = access
|
16
15
|
@secret_key = secret
|
17
|
-
@host =
|
16
|
+
@host = "elasticmapreduce.#{{:region => 'us-east-1'}.merge(options)[:region]}.amazonaws.com"
|
18
17
|
@protocol = {:secure => true}.merge(options)[:secure] ? 'https' : 'http'
|
19
18
|
end
|
20
19
|
|
@@ -32,7 +31,8 @@ module Elasticity
|
|
32
31
|
return false unless other.is_a? AwsRequest
|
33
32
|
return false unless @access_key == other.access_key
|
34
33
|
return false unless @secret_key == other.secret_key
|
35
|
-
return false unless @
|
34
|
+
return false unless @host == other.host
|
35
|
+
return false unless @protocol == other.protocol
|
36
36
|
true
|
37
37
|
end
|
38
38
|
|
data/lib/elasticity/job_flow.rb
CHANGED
@@ -17,6 +17,7 @@ module Elasticity
|
|
17
17
|
attr_accessor :ami_version
|
18
18
|
attr_accessor :keep_job_flow_alive_when_no_steps
|
19
19
|
attr_accessor :ec2_subnet_id
|
20
|
+
attr_accessor :placement
|
20
21
|
|
21
22
|
def initialize(access, secret)
|
22
23
|
@action_on_failure = 'TERMINATE_JOB_FLOW'
|
@@ -25,6 +26,10 @@ module Elasticity
|
|
25
26
|
@name = 'Elasticity Job Flow'
|
26
27
|
@ami_version = 'latest'
|
27
28
|
@keep_job_flow_alive_when_no_steps = false
|
29
|
+
@placement = 'us-east-1a'
|
30
|
+
|
31
|
+
@access = access
|
32
|
+
@secret = secret
|
28
33
|
|
29
34
|
@bootstrap_actions = []
|
30
35
|
@jobflow_steps = []
|
@@ -33,23 +38,24 @@ module Elasticity
|
|
33
38
|
@instance_groups = {}
|
34
39
|
set_master_instance_group(Elasticity::InstanceGroup.new)
|
35
40
|
set_core_instance_group(Elasticity::InstanceGroup.new)
|
36
|
-
|
37
41
|
@instance_count = 2
|
38
42
|
@master_instance_type = 'm1.small'
|
39
43
|
@slave_instance_type = 'm1.small'
|
40
44
|
|
41
|
-
@
|
45
|
+
@access = access
|
46
|
+
@secret = secret
|
42
47
|
end
|
43
48
|
|
44
|
-
def self.from_jobflow_id(access, secret, jobflow_id)
|
49
|
+
def self.from_jobflow_id(access, secret, jobflow_id, region = 'us-east-1')
|
45
50
|
JobFlow.new(access, secret).tap do |j|
|
51
|
+
j.instance_variable_set(:@region, region)
|
46
52
|
j.instance_variable_set(:@jobflow_id, jobflow_id)
|
47
53
|
j.instance_variable_set(:@installed_steps, j.status.installed_steps)
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
51
57
|
def instance_count=(count)
|
52
|
-
raise ArgumentError,
|
58
|
+
raise ArgumentError, "Instance count cannot be set to less than 2 (requested #{count})" unless count > 1
|
53
59
|
@instance_groups[:core].count = count - 1
|
54
60
|
@instance_count = count
|
55
61
|
end
|
@@ -91,7 +97,7 @@ module Elasticity
|
|
91
97
|
jobflow_steps << jobflow_step.aws_installation_step
|
92
98
|
end
|
93
99
|
jobflow_steps << jobflow_step.to_aws_step(self)
|
94
|
-
|
100
|
+
emr.add_jobflow_steps(@jobflow_id, {:steps => jobflow_steps})
|
95
101
|
else
|
96
102
|
@jobflow_steps << jobflow_step
|
97
103
|
end
|
@@ -100,21 +106,26 @@ module Elasticity
|
|
100
106
|
def run
|
101
107
|
raise_if @jobflow_steps.empty?, JobFlowMissingStepsError, 'Cannot run a job flow without adding steps. Please use #add_step.'
|
102
108
|
raise_if is_jobflow_running?, JobFlowRunningError, 'Cannot run a job flow multiple times. To do more with this job flow, please use #add_step.'
|
103
|
-
@jobflow_id =
|
109
|
+
@jobflow_id = emr.run_job_flow(jobflow_config)
|
104
110
|
end
|
105
111
|
|
106
112
|
def shutdown
|
107
113
|
raise_unless is_jobflow_running?, JobFlowNotStartedError, 'Cannot #shutdown a job flow that has not yet been #run.'
|
108
|
-
|
114
|
+
emr.terminate_jobflows(@jobflow_id)
|
109
115
|
end
|
110
116
|
|
111
117
|
def status
|
112
118
|
raise_unless is_jobflow_running?, JobFlowNotStartedError, 'Please #run this job flow before attempting to retrieve status.'
|
113
|
-
|
119
|
+
emr.describe_jobflow(@jobflow_id)
|
114
120
|
end
|
115
121
|
|
116
122
|
private
|
117
123
|
|
124
|
+
def emr
|
125
|
+
@region ||= @placement.match(/(\w+-\w+-\d+)/)[0]
|
126
|
+
@emr ||= Elasticity::EMR.new(@access, @secret, :region => @region)
|
127
|
+
end
|
128
|
+
|
118
129
|
def is_jobflow_running?
|
119
130
|
!@jobflow_id.nil?
|
120
131
|
end
|
data/lib/elasticity/version.rb
CHANGED
@@ -14,7 +14,7 @@ describe Elasticity::AwsRequest do
|
|
14
14
|
describe '#host' do
|
15
15
|
|
16
16
|
context 'when the region is not specified' do
|
17
|
-
its(:host) { should == 'elasticmapreduce.amazonaws.com' }
|
17
|
+
its(:host) { should == 'elasticmapreduce.us-east-1.amazonaws.com' }
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'when the region is specified' do
|
@@ -60,7 +60,7 @@ describe Elasticity::AwsRequest do
|
|
60
60
|
describe '#sign_params' do
|
61
61
|
it 'should sign according to AWS rules' do
|
62
62
|
signed_params = subject.send(:sign_params, {})
|
63
|
-
signed_params.should == 'AWSAccessKeyId=access&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-04-10T18%3A44%3A56.000Z&Signature=
|
63
|
+
signed_params.should == 'AWSAccessKeyId=access&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-04-10T18%3A44%3A56.000Z&Signature=t%2BccC38VxCKyk2ROTKo9vnECsntKoU0RBAFklHWP5bE%3D'
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
@@ -85,13 +85,13 @@ describe Elasticity::AwsRequest do
|
|
85
85
|
context 'when there is an EMR error with the request' do
|
86
86
|
let(:error_message) { 'ERROR_MESSAGE' }
|
87
87
|
let(:error_xml) do
|
88
|
-
<<-
|
88
|
+
<<-XML
|
89
89
|
<ErrorResponse xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
|
90
90
|
<Error>
|
91
91
|
<Message>#{error_message}</Message>
|
92
92
|
</Error>
|
93
93
|
</ErrorResponse>
|
94
|
-
|
94
|
+
XML
|
95
95
|
end
|
96
96
|
let(:error) do
|
97
97
|
RestClient::BadRequest.new.tap do |error|
|
@@ -110,24 +110,39 @@ describe Elasticity::AwsRequest do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
describe '#==' do
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
113
|
+
|
114
|
+
describe 'basic equality checks with subject' do
|
115
|
+
let(:same_object) { subject }
|
116
|
+
let(:same_values) { Elasticity::AwsRequest.new('access', 'secret', {}) }
|
117
|
+
let(:diff_type) { Object.new }
|
118
|
+
|
119
|
+
it { should == same_object }
|
120
|
+
it { should == same_values }
|
121
|
+
it { should_not == diff_type }
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'deep comparisons' do
|
125
|
+
|
126
|
+
it 'should fail on access key check' do
|
127
|
+
Elasticity::AwsRequest.new('access', '_').should_not == Elasticity::AwsRequest.new('_', '_')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should fail on secret key check' do
|
131
|
+
Elasticity::AwsRequest.new('_', 'secret').should_not == Elasticity::AwsRequest.new('_', '_')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should fail on host check' do
|
135
|
+
aws1 = Elasticity::AwsRequest.new('_', '_', :region => 'us-east-1')
|
136
|
+
aws2 = Elasticity::AwsRequest.new('_', '_', :region => 'us-west-1')
|
137
|
+
aws1.should_not == aws2
|
130
138
|
end
|
139
|
+
|
140
|
+
it 'should fail on protocol check' do
|
141
|
+
aws1 = Elasticity::AwsRequest.new('_', '_', :secure => true)
|
142
|
+
aws2 = Elasticity::AwsRequest.new('_', '_', :secure => false)
|
143
|
+
aws1.should_not == aws2
|
144
|
+
end
|
145
|
+
|
131
146
|
end
|
132
147
|
|
133
148
|
end
|
@@ -3,7 +3,7 @@ describe 'Elasticity::JobFlow Integration Examples' do
|
|
3
3
|
let(:emr) { double('Elasticity::EMR') }
|
4
4
|
|
5
5
|
before do
|
6
|
-
Elasticity::EMR.should_receive(:new).with('access', 'secret').and_return(emr)
|
6
|
+
Elasticity::EMR.should_receive(:new).with('access', 'secret', :region => 'us-west-1').and_return(emr)
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'Hive' do
|
@@ -17,6 +17,7 @@ describe 'Elasticity::JobFlow Integration Examples' do
|
|
17
17
|
|
18
18
|
let(:hive_jobflow) do
|
19
19
|
Elasticity::JobFlow.new('access', 'secret').tap do |jf|
|
20
|
+
jf.placement = 'us-west-1b'
|
20
21
|
jf.log_uri = 's3n://slif-test/output/logs'
|
21
22
|
jf.add_step(hive_step)
|
22
23
|
end
|
@@ -93,6 +94,7 @@ describe 'Elasticity::JobFlow Integration Examples' do
|
|
93
94
|
|
94
95
|
let(:pig_jobflow) do
|
95
96
|
Elasticity::JobFlow.new('access', 'secret').tap do |jf|
|
97
|
+
jf.placement = 'us-west-1b'
|
96
98
|
jf.instance_count = 8
|
97
99
|
jf.slave_instance_type = 'm1.xlarge'
|
98
100
|
jf.log_uri = 's3n://slif-test/output/logs'
|
@@ -177,6 +179,7 @@ describe 'Elasticity::JobFlow Integration Examples' do
|
|
177
179
|
|
178
180
|
let(:custom_jar_jobflow) do
|
179
181
|
Elasticity::JobFlow.new('access', 'secret').tap do |jf|
|
182
|
+
jf.placement = 'us-west-1b'
|
180
183
|
jf.log_uri = 's3n://slif-test/output/logs'
|
181
184
|
jf.add_step(custom_jar_step)
|
182
185
|
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
describe Elasticity::JobFlow do
|
2
2
|
|
3
|
-
before do
|
4
|
-
# Ensure we don't accidentally submit to EMR for all of these examples
|
5
|
-
Elasticity::EMR.stub(:new).and_return(double('Elasticity::EMR', :run_job_flow => '_'))
|
6
|
-
end
|
7
|
-
|
8
3
|
subject do
|
9
4
|
Elasticity::JobFlow.new('access', 'secret')
|
10
5
|
end
|
@@ -19,6 +14,7 @@ describe Elasticity::JobFlow do
|
|
19
14
|
its(:slave_instance_type) { should == 'm1.small' }
|
20
15
|
its(:ami_version) { should == 'latest' }
|
21
16
|
its(:keep_job_flow_alive_when_no_steps) { should == false }
|
17
|
+
its(:placement) { should == 'us-east-1a' }
|
22
18
|
|
23
19
|
describe '#instance_count=' do
|
24
20
|
|
@@ -102,6 +98,7 @@ describe Elasticity::JobFlow do
|
|
102
98
|
|
103
99
|
context 'when the jobflow is already started' do
|
104
100
|
before do
|
101
|
+
Elasticity::EMR.any_instance.stub(:run_job_flow => '_')
|
105
102
|
subject.add_step(Elasticity::CustomJarStep.new('_'))
|
106
103
|
subject.run
|
107
104
|
end
|
@@ -127,7 +124,7 @@ describe Elasticity::JobFlow do
|
|
127
124
|
end
|
128
125
|
|
129
126
|
before do
|
130
|
-
Elasticity::EMR.
|
127
|
+
Elasticity::EMR.stub(:new).and_return(emr)
|
131
128
|
running_jobflow.run
|
132
129
|
end
|
133
130
|
|
@@ -380,20 +377,20 @@ describe Elasticity::JobFlow do
|
|
380
377
|
let(:emr) { double('Elasticity::EMR', :run_job_flow => 'JOBFLOW_ID') }
|
381
378
|
|
382
379
|
it 'should run the job with the supplied EMR credentials' do
|
383
|
-
Elasticity::EMR.
|
380
|
+
Elasticity::EMR.stub(:new).with('STEP_TEST_ACCESS', 'STEP_TEST_SECRET', :region => 'us-east-1').and_return(emr)
|
384
381
|
emr.should_receive(:run_job_flow)
|
385
382
|
jobflow_with_steps.run
|
386
383
|
end
|
387
384
|
|
388
385
|
it 'should run the job with the jobflow config' do
|
389
|
-
Elasticity::EMR.stub(:new).
|
386
|
+
Elasticity::EMR.stub(:new).and_return(emr)
|
390
387
|
jobflow_with_steps.stub(:jobflow_config).and_return('JOBFLOW_CONFIG')
|
391
388
|
emr.should_receive(:run_job_flow).with('JOBFLOW_CONFIG')
|
392
389
|
jobflow_with_steps.run
|
393
390
|
end
|
394
391
|
|
395
392
|
it 'should return the jobflow ID' do
|
396
|
-
Elasticity::EMR.stub(:new).
|
393
|
+
Elasticity::EMR.stub(:new).and_return(emr)
|
397
394
|
jobflow_with_steps.run.should == 'JOBFLOW_ID'
|
398
395
|
end
|
399
396
|
|
@@ -401,6 +398,7 @@ describe Elasticity::JobFlow do
|
|
401
398
|
|
402
399
|
context 'when the jobflow has already been run' do
|
403
400
|
before do
|
401
|
+
Elasticity::EMR.any_instance.stub(:run_job_flow => '_')
|
404
402
|
jobflow_with_steps.run
|
405
403
|
end
|
406
404
|
it 'should raise an error' do
|
@@ -484,15 +482,29 @@ describe Elasticity::JobFlow do
|
|
484
482
|
end
|
485
483
|
|
486
484
|
describe '.from_jobflow_id' do
|
485
|
+
|
487
486
|
before do
|
488
487
|
Elasticity::JobFlow.any_instance.stub_chain(:status, :installed_steps => [])
|
489
488
|
end
|
490
489
|
|
491
490
|
let(:jobflow) { Elasticity::JobFlow.from_jobflow_id('ACCESS', 'SECRET', 'JOBFLOW_ID') }
|
492
491
|
|
493
|
-
|
494
|
-
|
495
|
-
|
492
|
+
describe 'creating a jobflow with the specified credentials' do
|
493
|
+
|
494
|
+
context 'when the region is not specified' do
|
495
|
+
it 'should use the default of us-east-1a' do
|
496
|
+
j = Elasticity::JobFlow.from_jobflow_id('ACCESS', 'SECRET', '_')
|
497
|
+
j.send(:emr).should == Elasticity::EMR.new('ACCESS', 'SECRET', :region => 'us-east-1')
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
context 'when the region is specified' do
|
502
|
+
it 'should use the specified region' do
|
503
|
+
j = Elasticity::JobFlow.from_jobflow_id('ACCESS', 'SECRET', '_', 'us-west-1')
|
504
|
+
j.send(:emr).should == Elasticity::EMR.new('ACCESS', 'SECRET', :region => 'us-west-1')
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
496
508
|
end
|
497
509
|
|
498
510
|
it 'should create a jobflow' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|