awscli 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -2
- data/lib/awscli/cli/as.rb +1 -1
- data/lib/awscli/cli/dynamo/item.rb +265 -0
- data/lib/awscli/cli/dynamo/table.rb +72 -0
- data/lib/awscli/cli/dynamo.rb +12 -0
- data/lib/awscli/cli/emr.rb +7 -7
- data/lib/awscli/connection.rb +12 -0
- data/lib/awscli/dynamo.rb +411 -0
- data/lib/awscli/emr.rb +5 -6
- data/lib/awscli/helper.rb +2 -1
- data/lib/awscli/version.rb +1 -1
- data/lib/awscli.rb +4 -0
- metadata +23 -5
- checksums.yaml +0 -15
data/README.md
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
awscli
|
2
2
|
======
|
3
3
|
|
4
|
-
Amazon Web Service Command Line Interface
|
4
|
+
Amazon Web Service(s) Command Line Interface
|
5
5
|
|
6
|
-
Provides
|
6
|
+
Provides the following interface:
|
7
7
|
|
8
8
|
- Elastic Cloud Compute (EC2)
|
9
9
|
- Auto Scaling Group (AS)
|
10
10
|
- Simple Storage Service (S3)
|
11
|
+
- AWS Identity and Access Management Interface (IAM)
|
12
|
+
- Elastic MapReduce (EMR)
|
13
|
+
- DynamoDB
|
11
14
|
|
12
15
|
More interfaces are in development.
|
13
16
|
|
data/lib/awscli/cli/as.rb
CHANGED
@@ -4,7 +4,7 @@ module AwsCli
|
|
4
4
|
require 'awscli/connection'
|
5
5
|
require 'awscli/as'
|
6
6
|
class As < Thor
|
7
|
-
class_option :region, :type => :string, :desc =>
|
7
|
+
class_option :region, :type => :string, :desc => 'region to connect to'
|
8
8
|
|
9
9
|
AwsCli::Cli.register AwsCli::CLI::As, :as, 'as [COMMAND]', 'Auto Scaling Interface'
|
10
10
|
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
module AwsCli
|
2
|
+
module CLI
|
3
|
+
module DYNAMO
|
4
|
+
require 'awscli/cli/dynamo'
|
5
|
+
class Item < Thor
|
6
|
+
|
7
|
+
conditional_item = <<-eos
|
8
|
+
Conditional Put/Delete/Update an Item:
|
9
|
+
|
10
|
+
Put/Delete/Update an element into a table using conditional put/delete/update: (The Expected parameter using
|
11
|
+
combination of -e and -x allows you to provide an attribute name, and whether or not Amazon DynamoDB
|
12
|
+
should check to see if the attribute value already exists; or if the attribute value exists and has a
|
13
|
+
particular value before changing it)
|
14
|
+
|
15
|
+
The following option combination replaces/deletes/updates the item if the "Color" attribute doesn't already
|
16
|
+
exist for that item:
|
17
|
+
`-e Color -x false`
|
18
|
+
|
19
|
+
The following option combination checks to see if the attribute with name "Color" has an existing value of
|
20
|
+
"Yellow" before replacing/deleting/updating the item
|
21
|
+
`-e Color:S:Yellow -x true`
|
22
|
+
|
23
|
+
By default, if you use the Expected parameter and provide a Value, Amazon DynamoDB assumes the attribute
|
24
|
+
exists and has a current value to be replaced. So you don't have to specify {-x true}, because it is implied.
|
25
|
+
You can shorten the request to:
|
26
|
+
`-e Color:S:Yellow`
|
27
|
+
eos
|
28
|
+
|
29
|
+
desc 'put [OPTIONS]', 'creates a new item, or replaces an old item with new item'
|
30
|
+
long_desc <<-DESC
|
31
|
+
Usage:
|
32
|
+
|
33
|
+
`awscli dynamo item put -t <table_name> -i <pk_col_name>:<type>:<value> <col_name>:<type>:<value> -a <expected_attr_name>:<type>:<value> -e <true|false> -r <return_values>`
|
34
|
+
|
35
|
+
Examples:
|
36
|
+
|
37
|
+
Put an element into a table:
|
38
|
+
|
39
|
+
`awscli dynamo item put -t test_table -i Id:N:1 UserName:S:test_user`
|
40
|
+
|
41
|
+
#{conditional_item}
|
42
|
+
|
43
|
+
`awscli dynamo item put -t test -i Id:N:1 UserName:S:test_user -a UserName:S:test -e true -r ALL_OLD`
|
44
|
+
DESC
|
45
|
+
method_option :table_name, :aliases => '-t', :desc => 'name of the table to contain the item'
|
46
|
+
method_option :item, :aliases => '-i', :type => :array, :desc => 'item to insert (must include primary key as well). Format => attribute_name:type(N|NS|S|SS|B|BS):value'
|
47
|
+
method_option :expected_attr, :aliases => '-e', :desc => 'data to check against for conditional put. Format => attribute_name:type:value'
|
48
|
+
method_option :expected_exists, :aliases => '-x', :desc => 'set as false to only allow update if attribute does not exist. Valid values: true|false'
|
49
|
+
method_option :return_values, :aliases => '-v', :default => 'NONE', :desc => 'data to return(use this parameter if you want to get the attribute name-value pairs before they were updated). Valid values in (ALL_NEW|ALL_OLD|NONE|UPDATED_NEW|UPDATED_OLD)'
|
50
|
+
def put
|
51
|
+
unless options[:table_name] and options[:item]
|
52
|
+
abort 'required options --table-name, --item'
|
53
|
+
end
|
54
|
+
if options[:expected_exists]
|
55
|
+
abort '--expected-exists only accepts true or false' unless %w(true false).include?(options[:expected_exists])
|
56
|
+
end
|
57
|
+
create_dynamo_object
|
58
|
+
@ddb.put options
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'get [OPTIONS]', 'returns a set of Attributes for an item that matches the primary key'
|
62
|
+
method_option :table_name, :aliases => '-t', :desc => ' name of the table containing the requested item'
|
63
|
+
method_option :hash_key, :aliases => '-k', :desc => 'primary key values that define the item. Format => attr_type:attr_value'
|
64
|
+
method_option :range_key, :aliases => '-r', :desc => 'optional info for range key. Format => attr_type:attr_value'
|
65
|
+
method_option :attrs_to_get, :aliases => '-g', :type => :array, :desc => 'Array of Attribute names. If attribute names are not specified then all attributes will be returned'
|
66
|
+
method_option :consistent_read, :aliases => '-c', :type => :boolean, :desc => 'If set then a consistent read is issued, otherwise eventually consistent is used'
|
67
|
+
def get
|
68
|
+
unless options[:table_name] and options[:hash_key]
|
69
|
+
abort 'required options --table-name, --hash-key'
|
70
|
+
end
|
71
|
+
create_dynamo_object
|
72
|
+
@ddb.get options
|
73
|
+
end
|
74
|
+
|
75
|
+
desc 'update [OPTIONS]', 'edits an existing items attributes'
|
76
|
+
long_desc <<-DESC
|
77
|
+
Update DynamoDB item, cannot update the primary key attributes using UpdateItem.
|
78
|
+
Instead, delete the item and use put to create a new item with new attributes
|
79
|
+
DESC
|
80
|
+
method_option :table_name, :aliases => '-t', :desc => 'name of the table containing the item to update'
|
81
|
+
method_option :hash_key, :aliases => '-k', :desc => 'primary key that defines the item. Format => attr_type:attr_value'
|
82
|
+
method_option :range_key, :aliases => '-r', :desc => 'optional info for range key. Format => attr_type:attr_value'
|
83
|
+
method_option :attr_updates, :aliases => '-u', :type =>:array, :desc => 'array of attribute name to the new value for the update. Format: attribute_name:type:value'
|
84
|
+
method_option :attr_updates_action, :aliases => '-a', :default => 'PUT', :desc => 'specifies how to perform the update. Possible values: (PUT|ADD|DELETE)'
|
85
|
+
method_option :expected_attr, :aliases => '-e', :desc => 'designates an attribute for a conditional update. Format => attribute_name:type:value'
|
86
|
+
method_option :expected_exists, :aliases => '-x', :desc => 'set as false to only allow update if attribute does not exist. Valid values: true|false'
|
87
|
+
method_option :return_values, :aliases => '-v', :default => 'NONE', :desc => 'data to return(use this parameter if you want to get the attribute name-value pairs before they were updated). Valid values in (ALL_NEW|ALL_OLD|NONE|UPDATED_NEW|UPDATED_OLD)'
|
88
|
+
def update
|
89
|
+
unless options[:table_name] and options[:hash_key] and options[:attr_updates]
|
90
|
+
abort 'required options --table-name, --hash-kye, --attr-updates'
|
91
|
+
end
|
92
|
+
if options[:expected_exists]
|
93
|
+
abort '--expected-exists only accepts true or false' unless %w(true false).include?(options[:expected_exists])
|
94
|
+
end
|
95
|
+
create_dynamo_object
|
96
|
+
@ddb.update options
|
97
|
+
end
|
98
|
+
|
99
|
+
desc 'delete [OPTIONS]', 'deletes a single item in a table by primary key'
|
100
|
+
long_desc <<-DESC
|
101
|
+
Deletes a single item in a table by primary key. You can perform a conditional delete operation that deletes
|
102
|
+
the item if it exists, or if it has an expected attribute value.
|
103
|
+
|
104
|
+
If you specify DeleteItem without attributes or values, all the attributes for the item are deleted
|
105
|
+
DESC
|
106
|
+
method_option :table_name, :aliases => '-t', :desc => 'name of the table containing the item to delete'
|
107
|
+
method_option :hash_key, :aliases => '-k', :desc => 'primary key that defines the item. Format => attr_type:attr_value'
|
108
|
+
method_option :range_key, :aliases => '-r', :desc => 'optional info for range key. Format => attr_type:attr_value'
|
109
|
+
method_option :expected_attr, :aliases => '-e', :desc => 'data to check against for conditional put. Format => attribute_name:type:value'
|
110
|
+
method_option :expected_exists, :aliases => '-x', :desc => 'set as false to only allow update if attribute does not exist. Valid values: true|false'
|
111
|
+
method_option :return_values, :aliases => '-v', :default => 'NONE', :desc => 'data to return(use this parameter if you want to get the attribute name-value pairs before they were updated). Valid values in (ALL_NEW|ALL_OLD|NONE|UPDATED_NEW|UPDATED_OLD)'
|
112
|
+
def delete
|
113
|
+
unless options[:table_name] and options[:hash_key]
|
114
|
+
abort 'required options --table-name, --hash-key'
|
115
|
+
end
|
116
|
+
if options[:expected_exists]
|
117
|
+
abort '--expected-exists only accepts true or false' unless %w(true false).include?(options[:expected_exists])
|
118
|
+
end
|
119
|
+
create_dynamo_object
|
120
|
+
@ddb.delete options
|
121
|
+
end
|
122
|
+
|
123
|
+
desc 'query [OPTIONS]', 'returns one or more items and their attributes by primary key (only available for hash-and-range primary key tables)'
|
124
|
+
method_option :table_name, :aliases => '-t', :desc => 'name of the table containing the requested items'
|
125
|
+
method_option :attrs_to_get, :aliases => '-g', :type => :array, :desc => 'array of attribute names, if attribute names are not specified then all attributes will be returned'
|
126
|
+
method_option :limit, :aliases => '-l', :type => :numeric, :desc => 'limit of total items to return'
|
127
|
+
method_option :count, :aliases => '-c', :type => :boolean, :default => false, :desc => 'if true, returns only a count of such items rather than items themselves'
|
128
|
+
method_option :hash_key_value, :aliases => '-v', :desc => 'attribute value of the hash component of the composite primary key. Format => HashKeyElementType,HashKeyElementValue'
|
129
|
+
method_option :range_key_filter, :aliases => '-f', :desc => 'A container for the attribute values and comparison operators to use for the query. Format => Operator(BETWEEN BEGINS_WITH EQ LE LT GE GT),Attr_Type(N|S|B|NS|SS|BS),Attr_Value'
|
130
|
+
method_option :scan_index_forward, :aliases => '-i', :default => 'true', :desc => 'Specifies ascending or descending traversal of the index, Possible Values: (true|false). Default: true'
|
131
|
+
method_option :start_key, :aliases => '-s', :desc => 'Primary key of the item from which to continue an earlier scan. Format => HashKeyElementType,HashKeyElementValue'
|
132
|
+
method_option :start_range_key, :aliases => '-k', :desc => 'Primary Range key of the item from which to continue an earlier scan. Format => RangeKeyElementType,RangeKeyElementValue'
|
133
|
+
def query
|
134
|
+
unless options[:table_name] and options[:hash_key_value]
|
135
|
+
abort 'options --table-name and --hash-key-value are required'
|
136
|
+
end
|
137
|
+
abort 'invalid --hash-key-value format' unless options[:hash_key_value] =~ /^(.*?),(.*?)$/
|
138
|
+
if options[:scan_index_forward]
|
139
|
+
abort 'invalid option --scan-index-forward value' unless options[:scan_index_forward] =~ /true|false/
|
140
|
+
end
|
141
|
+
if options[:range_key_filter]
|
142
|
+
abort 'invalid --range-key-filter format' unless options[:range_key_filter] =~ /^(BETWEEN|BEGINS_WITH|EQ|LE|LT|GE|GT),(N|S|B|NS|SS|BS),(.*?)$/
|
143
|
+
end
|
144
|
+
if options[:start_key]
|
145
|
+
abort 'Invalid --start-key format' unless options[:start_key] =~ /^(.*?),(.*?)$/
|
146
|
+
end
|
147
|
+
if options[:start_range_key]
|
148
|
+
abort 'Invalid --start-range-key format' unless options[:start_range_key] =~ /^(.*?),(.*?)$/
|
149
|
+
end
|
150
|
+
create_dynamo_object
|
151
|
+
@ddb.query options
|
152
|
+
end
|
153
|
+
|
154
|
+
desc 'scan [OPTIONS]', 'returns one or more items and its attributes by performing a full scan of a table'
|
155
|
+
long_desc <<-DESC
|
156
|
+
|
157
|
+
DESC
|
158
|
+
method_option :table_name, :aliases => '-t', :desc => 'name of the table containing the requested items'
|
159
|
+
method_option :attrs_to_get, :aliases => '-g', :type => :array, :desc => 'array of attribute names, if attribute names are not specified then all attributes will be returned'
|
160
|
+
method_option :limit, :aliases => '-l', :type => :numeric, :desc => 'limit of total items to return'
|
161
|
+
method_option :count, :aliases => '-c', :type => :boolean, :default => false, :desc => 'if true, returns only a count of such items rather than items themselves'
|
162
|
+
method_option :consistent_read, :type => :boolean, :default => false, :desc => 'whether to wait for consistency, defaults to false'
|
163
|
+
method_option :scan_filter, :aliases => '-f', :desc => 'Evaluates the scan results and returns only the desired values. Format=> Operator(BETWEEN BEGINS_WITH EQ LE LT GE GT),Attr_Name,Attr_Type(N|S|B|NS|SS|BS),Attr_Value'
|
164
|
+
method_option :start_key, :aliases => '-s', :desc => 'Primary key of the item from which to continue an earlier scan. Format => HashKeyElementType,HashKeyElementValue'
|
165
|
+
method_option :start_range_key, :aliases => '-k', :desc => 'Primary Range key of the item from which to continue an earlier scan. Format => RangeKeyElementType,RangeKeyElementValue'
|
166
|
+
def scan
|
167
|
+
unless options[:table_name]
|
168
|
+
abort 'option --table-name is required.'
|
169
|
+
end
|
170
|
+
if options[:scan_filter]
|
171
|
+
abort 'Invalid --scan-filter format' unless options[:scan_filter] =~ /^(BETWEEN|BEGINS_WITH|EQ|LE|LT|GE|GT),(.*?),(N|S|B|NS|SS|BS),(.*?)$/
|
172
|
+
end
|
173
|
+
if options[:start_key]
|
174
|
+
abort 'Invalid --start-key format' unless options[:start_key] =~ /^(.*?),(.*?)$/
|
175
|
+
end
|
176
|
+
if options[:start_range_key]
|
177
|
+
abort 'Invalid --start-range-key format' unless options[:start_range_key] =~ /^(.*?),(.*?)$/
|
178
|
+
end
|
179
|
+
create_dynamo_object
|
180
|
+
@ddb.scan options
|
181
|
+
end
|
182
|
+
|
183
|
+
desc 'batch_get [OPTIONS]', 'returns the attributes for multiple items from multiple tables using their primary keys'
|
184
|
+
long_desc <<-DESC
|
185
|
+
batch_get fetches items in parallel to minimize response latencies
|
186
|
+
This operation has following limitations:
|
187
|
+
The maximum number of items that can be retrieved for a single operation is 100. Also, the number of items.
|
188
|
+
Retrieved is constrained by a 1 MB size limit.
|
189
|
+
|
190
|
+
Usage Examples:
|
191
|
+
|
192
|
+
The following example will get the data from two different tables: comp2 & comp1. From table comp2 get username and friends
|
193
|
+
whose primary hash keys are Julie & Mingus and of type S(String). From table comp1 get username and status whose primary keys
|
194
|
+
are Casey & Dave of type S(String) and also match data based on range key 1319509152 & 1319509155 respectively for users.
|
195
|
+
|
196
|
+
`awscli dynamo item batch_get -r comp2,S=Julie,S=Mingus comp1,S=Casey:N=1319509152,S=Dave:N=1319509155 -g user:friends user:status`
|
197
|
+
DESC
|
198
|
+
method_option :requests, :aliases => '-r', :type => :array, :desc => 'A container of the table name and corresponding items to get by primary key. Format => tbl1_name*,KeySet1(hash_key_type*=hash_key_value*:range_key_type=range_key_value),KeySet2,KeySetN'
|
199
|
+
method_option :attrs_to_get, :aliases => '-g', :type => :array, :desc => 'Attributes to get from each respective table. Format => tbl1_attr1:tbl1_attr2:tbl1_attr3 tbl2_attr1:tbl2_attr2:tbl2_attr3 ..'
|
200
|
+
method_option :consistent_read, :aliases => '-c', :type => :boolean, :desc => 'If set then a consistent read is issued, otherwise eventually consistent is used'
|
201
|
+
def batch_get
|
202
|
+
unless options[:requests]
|
203
|
+
abort 'option --requests is required'
|
204
|
+
end
|
205
|
+
options[:requests].each do |request|
|
206
|
+
unless request =~ /^(.*?)(?:,((N|S|B|NS|SS|BS)=(.*?))(:(N|S|B|NS|SS|BS)=(.*?))*)+$/
|
207
|
+
abort 'Invalid --request format, see `awscli dynamo item help batch_get` for usage examples'
|
208
|
+
end
|
209
|
+
end
|
210
|
+
create_dynamo_object
|
211
|
+
@ddb.batch_get options
|
212
|
+
end
|
213
|
+
|
214
|
+
desc 'batch_write [OPTIONS]', 'performs put or delete several items across multiple tables'
|
215
|
+
long_desc <<-DESC
|
216
|
+
`batch_write` enables you to put or delete several items across multiple tables in a single API call
|
217
|
+
This operation has following limitations:
|
218
|
+
Maximum operations in a single request: You can specify a total of up to 25 put or delete operations.
|
219
|
+
Unlike the put and delete, batch_write does not allow you to specify conditions on individual write requests in the operation.
|
220
|
+
|
221
|
+
Usage Examples:
|
222
|
+
|
223
|
+
The following batch_write operation will put an item into User, Item tables and deletes item from User, Thread tables
|
224
|
+
|
225
|
+
`bundle exec bin/awscli dynamo item batch_write --put-requests User,Id:S:003,UserName:S:user123,Password:S:secret123 Item,Id:S:'Amazon Dynamo DB#Thread 5',ReplyDateTime:S:'2012-04-03T11:04:47.034Z' --delete-requests User,S=003 Thread,S='Amazon DynamoDB#Thread 4':S='oops - accidental row'`
|
226
|
+
DESC
|
227
|
+
method_option :put_requests, :aliases => '-p', :type => :array, :desc => 'Format=> table_name,col_name1:col_type1:col_value1,col_name2:col_type2:col_value2 ..'
|
228
|
+
method_option :delete_requests, :aliases => '-d', :type => :array, :desc => 'Format=> table_name,hash_key_type*=hash_key_value*:range_key_type=range_key_value ..'
|
229
|
+
def batch_write
|
230
|
+
unless options[:put_requests] or options[:delete_requests]
|
231
|
+
abort 'option --put-requests or --delete-requests is required to perform batch_write'
|
232
|
+
end
|
233
|
+
options[:put_requests] and options[:put_requests].each do |put_request|
|
234
|
+
unless put_request =~ /^(.*?)(?:,((.*?):(N|S|B|NS|SS|BS):(.*?))*)+$/
|
235
|
+
abort 'Invalid --put-requests format, see `awscli dynamo item help batch_write` for usage examples'
|
236
|
+
end
|
237
|
+
end
|
238
|
+
options[:delete_requests] and options[:delete_requests].each do |delete_request|
|
239
|
+
unless delete_request =~ /^(.*?)(?:,((N|S|B|NS|SS|BS)=(.*?))(:(N|S|B|NS|SS|BS)=(.*?))*)+$/
|
240
|
+
abort 'Invalid --delete-requests format, see `awscli dynamo item help batch_write` for usage examples'
|
241
|
+
end
|
242
|
+
end
|
243
|
+
create_dynamo_object
|
244
|
+
@ddb.batch_write options
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
|
249
|
+
def create_dynamo_object
|
250
|
+
puts 'Dynamo Establishing Connection...'
|
251
|
+
$dynamo_conn = if parent_options[:region]
|
252
|
+
Awscli::Connection.new.request_dynamo(parent_options[:region])
|
253
|
+
else
|
254
|
+
Awscli::Connection.new.request_dynamo
|
255
|
+
end
|
256
|
+
puts 'Dynamo Establishing Connection... OK'
|
257
|
+
@ddb = Awscli::DynamoDB::Items.new($dynamo_conn)
|
258
|
+
end
|
259
|
+
|
260
|
+
AwsCli::CLI::Dynamo.register AwsCli::CLI::DYNAMO::Item, :item, 'item [COMMAND]', 'Dynamo DB Item(s) Management'
|
261
|
+
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module AwsCli
|
2
|
+
module CLI
|
3
|
+
module DYNAMO
|
4
|
+
require 'awscli/cli/dynamo'
|
5
|
+
class Table < Thor
|
6
|
+
|
7
|
+
desc 'list', 'list available tables'
|
8
|
+
method_option :limit, :aliases => '-l', :type => :numeric, :desc => 'A number of maximum table names to return.'
|
9
|
+
#method_option :exclusive_start_table_name, :aliases => '-e', :banner => 'NAME', :desc => 'The name of the table that starts the list'
|
10
|
+
def list
|
11
|
+
create_dynamo_object
|
12
|
+
@ddb.list options
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'info', 'returns information about the table'
|
16
|
+
method_option :name, :aliases => '-n', :required => true, :desc => 'name of the table to list information for'
|
17
|
+
def info
|
18
|
+
create_dynamo_object
|
19
|
+
@ddb.describe options[:name]
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'create', 'create a new table'
|
23
|
+
method_option :name, :aliases => '-n', :required => true, :desc => 'name of the table to create, name should be unique among your account'
|
24
|
+
method_option :pk_name, :aliases => '-k', :required => true, :desc => 'primary key hash attribute name for the table'
|
25
|
+
method_option :pk_type, :aliases => '-t', :required => true, :desc => 'type of the hash attribute, valid values in [N, NS, S, SS]. N-Number, NS-NumberSet, S-String, SS-StringSet'
|
26
|
+
method_option :rk_name, :desc => 'range attribute name for the table (if specified will create a composite primary key)'
|
27
|
+
method_option :rk_type, :desc => 'type of the range attribute, valid values in [N, NS, S, SS]'
|
28
|
+
method_option :read_capacity, :aliases => '-r', :required => true, :type => :numeric, :desc => 'minimum number of consistent ReadCapacityUnits consumed per second for the specified table'
|
29
|
+
method_option :write_capacity, :aliases => '-w', :required => true, :type => :numeric, :desc => 'minimum number of WriteCapacityUnits consumed per second for the specified table'
|
30
|
+
def create
|
31
|
+
#name should be > 3 and can contain a-z, A-Z, 0-9, _, .
|
32
|
+
#type should be in N, NS, S, SS
|
33
|
+
#read and write capacity in between 5..10000
|
34
|
+
create_dynamo_object
|
35
|
+
@ddb.create options
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'delete', 'deletes a table and all its items'
|
39
|
+
method_option :name, :aliases => '-n', :required => true, :desc => 'name of the table to delete'
|
40
|
+
def delete
|
41
|
+
create_dynamo_object
|
42
|
+
@ddb.delete options[:name]
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'update', 'updates existing dynamo db table provisioned throughput'
|
46
|
+
method_option :name, :aliases => '-n', :required => true, :desc => 'name of the table to update'
|
47
|
+
method_option :read_capacity, :aliases => '-r', :required => true, :type => :numeric, :desc => 'minimum number of consistent ReadCapacityUnits consumed per second for the specified table'
|
48
|
+
method_option :write_capacity, :aliases => '-w', :required => true, :type => :numeric, :desc => 'minimum number of WriteCapacityUnits consumed per second for the specified table'
|
49
|
+
def update
|
50
|
+
create_dynamo_object
|
51
|
+
@ddb.update options
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def create_dynamo_object
|
57
|
+
puts 'Dynamo Establishing Connection...'
|
58
|
+
$dynamo_conn = if parent_options[:region]
|
59
|
+
Awscli::Connection.new.request_dynamo(parent_options[:region])
|
60
|
+
else
|
61
|
+
Awscli::Connection.new.request_dynamo
|
62
|
+
end
|
63
|
+
puts 'Dynamo Establishing Connection... OK'
|
64
|
+
@ddb = Awscli::DynamoDB::Table.new($dynamo_conn)
|
65
|
+
end
|
66
|
+
|
67
|
+
AwsCli::CLI::Dynamo.register AwsCli::CLI::DYNAMO::Table, :table, 'table [COMMAND]', 'Dynamo Table Management'
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module AwsCli
|
2
|
+
module CLI
|
3
|
+
require 'awscli/cli'
|
4
|
+
require 'awscli/connection'
|
5
|
+
require 'awscli/dynamo'
|
6
|
+
class Dynamo < Thor
|
7
|
+
class_option :region, :type => :string, :desc => 'region to connect to', :default => 'us-west-1'
|
8
|
+
|
9
|
+
AwsCli::Cli.register AwsCli::CLI::Dynamo, :dynamo, 'dynamo [COMMAND]', 'Amazons NoSQL DynamoDB Interface'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/awscli/cli/emr.rb
CHANGED
@@ -4,7 +4,7 @@ module AwsCli
|
|
4
4
|
require 'awscli/connection'
|
5
5
|
require 'awscli/emr'
|
6
6
|
class Emr < Thor
|
7
|
-
class_option :region, :type => :string, :desc =>
|
7
|
+
class_option :region, :type => :string, :desc => 'region to connect to', :default => 'us-west-1'
|
8
8
|
|
9
9
|
desc 'usage', 'show the usage examples'
|
10
10
|
def usage
|
@@ -75,7 +75,6 @@ module AwsCli
|
|
75
75
|
end
|
76
76
|
|
77
77
|
desc 'create [OPTIONS]', 'creates and starts running a new job flow'
|
78
|
-
#TODO: update Long Desc
|
79
78
|
long_desc <<-DESC
|
80
79
|
Creates and starts running a new job flow.
|
81
80
|
|
@@ -113,7 +112,7 @@ module AwsCli
|
|
113
112
|
method_option :hbase_backup_schedule, :desc => 'Specify whether to schedule automatic incremental backups. Format=> frequency*,frequency_unit*(Days|Hours|Mins),path(s3)*,start_time*(now|date)'
|
114
113
|
method_option :hbase_consistent_backup, :type => :boolean, :default => false, :desc => 'Perform a consistent backup'
|
115
114
|
def create
|
116
|
-
|
115
|
+
unless options[:name]
|
117
116
|
puts 'These options are required --name'
|
118
117
|
exit
|
119
118
|
end
|
@@ -126,7 +125,7 @@ module AwsCli
|
|
126
125
|
method_option :instance_groups, :type => :array, :aliases => '-g', :desc => 'Add instance groups. Format => "instance_count,instance_role(MASTER | CORE | TASK),instance_type,name,bid_price"'
|
127
126
|
def add_ig
|
128
127
|
unless options[:job_flow_id] and options[:instance_groups]
|
129
|
-
abort
|
128
|
+
abort '--job-flow-id and --instance-groups are required'
|
130
129
|
end
|
131
130
|
create_emr_object
|
132
131
|
@emr.add_instance_groups options[:job_flow_id], options[:instance_groups]
|
@@ -137,17 +136,18 @@ module AwsCli
|
|
137
136
|
method_option :steps, :aliases => '-s', :type => :array, :desc => 'Add list of steps to be executed by job flow. Format=> jar_path(s3)*,name_of_step*,main_class,action_on_failure(TERMINATE_JOB_FLOW | CANCEL_AND_WAIT | CONTINUE),arg1=agr2=arg3,properties(k=v,k=v)'
|
138
137
|
def add_steps
|
139
138
|
unless options[:job_flow_id] and options[:steps]
|
140
|
-
abort
|
139
|
+
abort '--job-flow-id and --steps are required'
|
141
140
|
end
|
142
141
|
create_emr_object
|
143
142
|
@emr.add_steps options[:job_flow_id], options[:steps]
|
144
143
|
end
|
144
|
+
|
145
145
|
private
|
146
146
|
|
147
147
|
def create_emr_object
|
148
|
-
puts 'EMR Establishing
|
148
|
+
puts 'EMR Establishing Connection...'
|
149
149
|
$emr_conn = Awscli::Connection.new.request_emr
|
150
|
-
puts 'EMR Establishing
|
150
|
+
puts 'EMR Establishing Connection... OK'
|
151
151
|
@emr = Awscli::Emr::EMR.new($emr_conn)
|
152
152
|
end
|
153
153
|
|
data/lib/awscli/connection.rb
CHANGED
@@ -71,5 +71,17 @@ module Awscli
|
|
71
71
|
Fog::AWS::EMR.new(@config)
|
72
72
|
end
|
73
73
|
|
74
|
+
def request_dynamo(region=nil)
|
75
|
+
# => returns AWS DynamoDB object
|
76
|
+
if region
|
77
|
+
Awscli::Errors.invalid_region unless Awscli::Instances::REGIONS.include?(region)
|
78
|
+
@config.reject!{ |key| key == 'region' } if @config['region']
|
79
|
+
@config.merge!(:region => region)
|
80
|
+
else
|
81
|
+
Awscli::Errors.invalid_region unless Awscli::Instances::REGIONS.include?(@config['region']) if @config['region']
|
82
|
+
end
|
83
|
+
Fog::AWS::DynamoDB.new(@config)
|
84
|
+
end
|
85
|
+
|
74
86
|
end
|
75
87
|
end
|
@@ -0,0 +1,411 @@
|
|
1
|
+
module Awscli
|
2
|
+
module DynamoDB
|
3
|
+
class Table
|
4
|
+
def initialize(connection)
|
5
|
+
@conn = connection
|
6
|
+
end
|
7
|
+
|
8
|
+
def list(options)
|
9
|
+
opts = {}
|
10
|
+
table_data = []
|
11
|
+
opts['Limit'] = options[:limit] if options[:limit]
|
12
|
+
@conn.list_tables(opts).body['TableNames'].each do |table|
|
13
|
+
table_data << { :table => table }
|
14
|
+
end
|
15
|
+
if table_data.empty?
|
16
|
+
puts 'No tables found'
|
17
|
+
else
|
18
|
+
Formatador.display_table(table_data)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(options)
|
23
|
+
key_schema, provisioned_throughput = {}, {}
|
24
|
+
abort 'Invalid key type' unless %w(N NS S SS).include?(options[:pk_type])
|
25
|
+
key_schema['HashKeyElement'] = {
|
26
|
+
'AttributeName' => options[:pk_name],
|
27
|
+
'AttributeType' => options[:pk_type]
|
28
|
+
}
|
29
|
+
if options[:rk_name]
|
30
|
+
abort '--rk_type is required if --rk-name is passed' unless options[:rk_name]
|
31
|
+
abort 'Invalid key type' unless %w(N NS S SS).include?(options[:rk_type])
|
32
|
+
key_schema['RangeKeyElement'] = {
|
33
|
+
'AttributeName' => options[:rk_name],
|
34
|
+
'AttributeType' => options[:rk_type]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
provisioned_throughput['ReadCapacityUnits'] = options[:read_capacity]
|
38
|
+
provisioned_throughput['WriteCapacityUnits'] = options[:write_capacity]
|
39
|
+
@conn.create_table(options[:name], key_schema, provisioned_throughput)
|
40
|
+
rescue Excon::Errors::BadRequest
|
41
|
+
puts "[Error] Failed to create table. #{parse_excon_error_response($!)}"
|
42
|
+
else
|
43
|
+
puts "Create table #{options[:name]} successfully."
|
44
|
+
end
|
45
|
+
|
46
|
+
def describe(table_name)
|
47
|
+
puts @conn.describe_table(table_name).body.to_yaml
|
48
|
+
rescue Excon::Errors::BadRequest
|
49
|
+
puts 'Table not found'
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(table_name)
|
53
|
+
@conn.delete_table(table_name)
|
54
|
+
rescue Excon::Errors::BadRequest
|
55
|
+
puts "[Error] Failed to delete table. #{parse_excon_error_response($!)}"
|
56
|
+
else
|
57
|
+
puts "Delete table #{table_name} successfully."
|
58
|
+
end
|
59
|
+
|
60
|
+
def update(options)
|
61
|
+
provisioned_throughput = {}
|
62
|
+
provisioned_throughput['ReadCapacityUnits'] = options[:read_capacity]
|
63
|
+
provisioned_throughput['WriteCapacityUnits'] = options[:write_capacity]
|
64
|
+
@conn.update_table(options[:name], provisioned_throughput)
|
65
|
+
rescue Excon::Errors::BadRequest
|
66
|
+
puts "[Error] Failed to update table. #{parse_excon_error_response($!)}"
|
67
|
+
else
|
68
|
+
puts "Table #{options[:name]} provisioned capacity updated successfully."
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def parse_excon_error_response(response)
|
74
|
+
response.data[:body].match(/message.*/)[0].gsub(/[^A-Za-z0-9: ]/, '')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Items
|
79
|
+
def initialize(connection)
|
80
|
+
@conn = connection
|
81
|
+
end
|
82
|
+
|
83
|
+
def query(options)
|
84
|
+
opts = {}
|
85
|
+
hash_key_type, hash_key_value = options[:hash_key_value].split(',')
|
86
|
+
hash_key = { hash_key_type => hash_key_value }
|
87
|
+
opts['AttributesToGet'] = options[:attrs_to_get] if options[:attrs_to_get]
|
88
|
+
opts['Limit'] = options[:limit] if options[:limit]
|
89
|
+
opts['Count'] = options[:count] if options[:count]
|
90
|
+
opts['ConsistentRead'] = options[:consistent_read] if options[:consistent_read]
|
91
|
+
if options[:range_key_filter]
|
92
|
+
operator, attr_type, attr_value = options[:range_key_filter].split(',')
|
93
|
+
opts['RangeKeyCondition'] = {
|
94
|
+
'AttributeValueList' => [{ attr_type => attr_value }],
|
95
|
+
'ComparisonOperator' => operator
|
96
|
+
}
|
97
|
+
end
|
98
|
+
opts['ScanIndexForward'] = options[:scan_index_forward]
|
99
|
+
if options[:start_key]
|
100
|
+
opts['ExclusiveStartKey'] = {}
|
101
|
+
hash_key_type, hash_key_value = options[:start_key].split(',')
|
102
|
+
opts['ExclusiveStartKey']['HashKeyElement'] = { hash_key_type => hash_key_value }
|
103
|
+
if options[:start_range_key]
|
104
|
+
range_key_type, range_key_value = options[:start_range_key].split(',')
|
105
|
+
opts['ExclusiveStartKey']['RangeKeyElement'] = { range_key_type => range_key_value }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
p opts
|
109
|
+
data = @conn.query(options[:table_name], hash_key, opts)
|
110
|
+
rescue Excon::Errors::BadRequest
|
111
|
+
puts "[Error] Failed to perform scan on table. #{parse_excon_error_response($!)}"
|
112
|
+
else
|
113
|
+
total_items = data.data[:body]['Count']
|
114
|
+
items = data.data[:body]['Items']
|
115
|
+
if not options[:count]
|
116
|
+
puts "Retrieved #{total_items} Items"
|
117
|
+
Formatador.display_table(items)
|
118
|
+
else
|
119
|
+
puts "Items Count: #{total_items}"
|
120
|
+
end
|
121
|
+
puts "LastEvaluatedKey: #{data.data[:body]['LastEvaluatedKey']}" if data.data[:body]['LastEvaluatedKey']
|
122
|
+
end
|
123
|
+
|
124
|
+
def scan(options)
|
125
|
+
opts = {}
|
126
|
+
opts['AttributesToGet'] = options[:attrs_to_get] if options[:attrs_to_get]
|
127
|
+
opts['Limit'] = options[:limit] if options[:limit]
|
128
|
+
opts['ConsistentRead'] = options[:consistent_read] if options[:consistent_read]
|
129
|
+
opts['Count'] = options[:count] if options[:count]
|
130
|
+
if options[:scan_filter]
|
131
|
+
#Operator(BETWEEN BEGINS_WITH EQ LE LT GE GT),Attr_Name,Attr_Type(N|S|B|NS|SS|BS),Attr_Value
|
132
|
+
operator, attr_name, attr_type, attr_value = options[:scan_filter].split(',')
|
133
|
+
#case operator
|
134
|
+
# when 'EQ', 'NE', 'LE', 'LT', 'GE', 'GT', 'CONTAINS', 'NOT_CONTAINS', 'BEGINS_WITH'
|
135
|
+
# #can contain only one AttributeValue element
|
136
|
+
# when 'BETWEEN'
|
137
|
+
# #contain two AttributeValue elements
|
138
|
+
# else
|
139
|
+
# #IN - can contain any number of AttributeValue elements
|
140
|
+
#end
|
141
|
+
opts['ScanFilter'] = {
|
142
|
+
attr_name => {
|
143
|
+
'AttributeValueList' => [{ attr_type => attr_value }],
|
144
|
+
'ComparisonOperator' => operator
|
145
|
+
}
|
146
|
+
}
|
147
|
+
end
|
148
|
+
if options[:start_key]
|
149
|
+
opts['ExclusiveStartKey'] = {}
|
150
|
+
hash_key_type, hash_key_value = options[:start_key].split(',')
|
151
|
+
opts['ExclusiveStartKey']['HashKeyElement'] = { hash_key_type => hash_key_value }
|
152
|
+
if options[:start_range_key]
|
153
|
+
range_key_type, range_key_value = options[:start_range_key].split(',')
|
154
|
+
opts['ExclusiveStartKey']['RangeKeyElement'] = { range_key_type => range_key_value }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
data = @conn.scan(options[:table_name], opts)
|
158
|
+
rescue Excon::Errors::BadRequest
|
159
|
+
puts "[Error] Failed to perform scan on table. #{parse_excon_error_response($!)}"
|
160
|
+
else
|
161
|
+
total_items = data.data[:body]['Count']
|
162
|
+
items = data.data[:body]['Items']
|
163
|
+
if not options[:count]
|
164
|
+
puts "Retrieved #{total_items} Items"
|
165
|
+
Formatador.display_table(items)
|
166
|
+
else
|
167
|
+
puts "Items Count: #{total_items}"
|
168
|
+
end
|
169
|
+
puts "LastEvaluatedKey: #{data.data[:body]['LastEvaluatedKey']}" if data.data[:body]['LastEvaluatedKey']
|
170
|
+
end
|
171
|
+
|
172
|
+
def put(options)
|
173
|
+
items = {}
|
174
|
+
opts = {}
|
175
|
+
options[:item].each do |item|
|
176
|
+
abort "invalid item format: #{item}" unless item =~ /(.*):(N|S|NS|SS|B|BS):(.*)/
|
177
|
+
attr_name, attr_type, attr_value = item.split(':')
|
178
|
+
items[attr_name] = { attr_type => attr_value }
|
179
|
+
end
|
180
|
+
if options[:expected_attr] #-a
|
181
|
+
expected_attr_name, expected_attr_type, expected_attr_value = options[:expected_attr].split(':')
|
182
|
+
if expected_attr_name and expected_attr_type and expected_attr_value
|
183
|
+
if options[:expected_exists] and options[:expected_exists] == 'true' #-a Id:S:001 -e true
|
184
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value }, 'Exists' => options[:expected_exists] } }
|
185
|
+
else #-a Id:S:001
|
186
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value } } }
|
187
|
+
end
|
188
|
+
elsif expected_attr_name and not expected_attr_type and not expected_attr_value
|
189
|
+
if options[:expected_exists] and options[:expected_exists] == 'false' #-a Id -e false
|
190
|
+
opts['Expected'] = { expected_attr_name => { 'Exists' => options[:expected_exists] } }
|
191
|
+
else
|
192
|
+
abort 'Invalid option combination, see help for usage examples'
|
193
|
+
end
|
194
|
+
else
|
195
|
+
abort 'Invalid option combination, see help for usage examples'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
if options[:return_values]
|
199
|
+
abort 'Invalid return type' unless %w(ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD).include?(options[:return_values])
|
200
|
+
opts['ReturnValues'] = options[:return_values]
|
201
|
+
end
|
202
|
+
@conn.put_item(options[:table_name], items, opts)
|
203
|
+
rescue Excon::Errors::BadRequest
|
204
|
+
puts "[Error] Failed to put item into table. #{parse_excon_error_response($!)}"
|
205
|
+
else
|
206
|
+
puts 'Item put succeeded.'
|
207
|
+
end
|
208
|
+
|
209
|
+
def get(options)
|
210
|
+
#get_item(table_name, key, options = {})
|
211
|
+
opts = {}
|
212
|
+
key = {}
|
213
|
+
abort 'Invalid --hash-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
214
|
+
hash_key_type, hash_key_name = options[:hash_key].split(':')
|
215
|
+
key['HashKeyElement'] = { hash_key_type => hash_key_name }
|
216
|
+
if options[:range_key]
|
217
|
+
abort 'Invalid --range-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
218
|
+
range_key_type, range_key_name = options[:range_key].split(':')
|
219
|
+
key['RangeKeyElement'] = { range_key_type => range_key_name }
|
220
|
+
end
|
221
|
+
|
222
|
+
opts['AttributesToGet'] = options[:attrs_to_get] if options[:attrs_to_get]
|
223
|
+
|
224
|
+
opts['ConsistentRead'] = true if options[:consistent_read]
|
225
|
+
data = @conn.get_item(options[:table_name], key, opts)
|
226
|
+
rescue Excon::Errors::BadRequest
|
227
|
+
puts "[Error] Failed to get item from table. #{parse_excon_error_response($!)}"
|
228
|
+
else
|
229
|
+
#TODO: Pretty print this
|
230
|
+
if not data.body['Item'].nil?
|
231
|
+
puts 'Retrieved Items:'
|
232
|
+
puts "ColumnName \t Type \t Value"
|
233
|
+
data.body['Item'].each do |attr, pair|
|
234
|
+
print "#{attr} \t"
|
235
|
+
pair.map {|type,value| print "#{type} \t #{value}"}
|
236
|
+
puts
|
237
|
+
end
|
238
|
+
else
|
239
|
+
puts 'No data retrieved'
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def batch_get(options)
|
244
|
+
request_items = {}
|
245
|
+
map = options[:requests].zip(options[:attrs_to_get])
|
246
|
+
map.each do |request_attrs_mapping|
|
247
|
+
#tbl1_name*,KeySet1(hash_key_type*=hash_key_value*:range_key_type=range_key_value),KeySet2,KeySetN
|
248
|
+
table_name, *keys = request_attrs_mapping.first.split(',')
|
249
|
+
attrs = request_attrs_mapping.last.split(':') unless request_attrs_mapping.last.nil?
|
250
|
+
request_items[table_name] = {}
|
251
|
+
request_items[table_name]['Keys'] = []
|
252
|
+
keys.each do |key|
|
253
|
+
parsed_key = {}
|
254
|
+
hash_key, range_key = key.split(':')
|
255
|
+
hash_key_type, hash_key_value = hash_key.split('=')
|
256
|
+
parsed_key['HashKeyElement'] = { hash_key_type => hash_key_value }
|
257
|
+
unless range_key.nil?
|
258
|
+
range_key_type, range_key_value = range_key.split('=')
|
259
|
+
parsed_key['RangeKeyElement'] = { range_key_type => range_key_value }
|
260
|
+
end
|
261
|
+
request_items[table_name]['Keys'] << parsed_key
|
262
|
+
end
|
263
|
+
request_items[table_name]['AttributesToGet'] = attrs unless attrs.nil?
|
264
|
+
end
|
265
|
+
puts @conn.batch_get_item(request_items).data[:body]['Responses'].to_yaml
|
266
|
+
rescue Excon::Errors::BadRequest
|
267
|
+
puts "[Error] Failed to get item from table. #{parse_excon_error_response($!)}"
|
268
|
+
end
|
269
|
+
|
270
|
+
def batch_write(options)
|
271
|
+
request_items = {}
|
272
|
+
#request_items['RequestItems'] = {}
|
273
|
+
options[:put_requests] and options[:put_requests].each do |request|
|
274
|
+
#table_name,col_name1:col_type1:col_value1,col_name2:col_type2:col_value2 ..
|
275
|
+
table_name, *cols = request.split(',')
|
276
|
+
request_items[table_name] ||= []
|
277
|
+
put_request = {}
|
278
|
+
put_request['PutRequest'] = {}
|
279
|
+
put_request['PutRequest']['Item'] = {}
|
280
|
+
cols.each do |col|
|
281
|
+
col_name, col_type, col_value = col.split(':')
|
282
|
+
put_request['PutRequest']['Item'][col_name] = { col_type => col_value }
|
283
|
+
end
|
284
|
+
request_items[table_name] << put_request
|
285
|
+
end
|
286
|
+
options[:delete_requests] and options[:delete_requests].each do |request|
|
287
|
+
#table_name,KeySet1(hash_key_type*=hash_key_value*:range_key_type=range_key_value),KeySet2,KeySetN
|
288
|
+
table_name, *keys = request.split(',')
|
289
|
+
request_items[table_name] ||= []
|
290
|
+
delete_request = {}
|
291
|
+
delete_request['DeleteRequest'] = {}
|
292
|
+
delete_request['DeleteRequest']['Key'] = {}
|
293
|
+
keys.each do |key_set|
|
294
|
+
hash_key, range_key = key_set.split(':')
|
295
|
+
hash_key_type, hash_key_value = hash_key.split('=')
|
296
|
+
delete_request['DeleteRequest']['Key']['HashKeyElement'] = { hash_key_type => hash_key_value }
|
297
|
+
if range_key
|
298
|
+
range_key_type, range_key_value = range_key.split('=')
|
299
|
+
delete_request['DeleteRequest']['Key']['RangeKeyElement'] = { range_key_type => range_key_value }
|
300
|
+
end
|
301
|
+
end
|
302
|
+
request_items[table_name] << delete_request
|
303
|
+
end
|
304
|
+
@conn.batch_write_item(request_items)
|
305
|
+
rescue Excon::Errors::BadRequest
|
306
|
+
puts "[Error] Failed to batch put/delete item to/from table. #{parse_excon_error_response($!)}"
|
307
|
+
else
|
308
|
+
puts 'Batch Put/Delete Succeeded'
|
309
|
+
end
|
310
|
+
|
311
|
+
def update(options)
|
312
|
+
opts = {}
|
313
|
+
key = {}
|
314
|
+
attribute_updates = {}
|
315
|
+
#Build and validate key
|
316
|
+
abort 'Invalid --hash-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
317
|
+
hash_key_type, hash_key_name = options[:hash_key].split(':')
|
318
|
+
key['HashKeyElement'] = { hash_key_type => hash_key_name }
|
319
|
+
if options[:range_key]
|
320
|
+
abort 'Invalid --range-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
321
|
+
range_key_type, range_key_name = options[:range_key].split(':')
|
322
|
+
key['RangeKeyElement'] = { range_key_type => range_key_name }
|
323
|
+
end
|
324
|
+
#Build and validate attribute_updates
|
325
|
+
options[:attr_updates].each do |attr_update|
|
326
|
+
abort "invalid item format: #{attr_update}" unless attr_update =~ /(.*):(N|S|NS|SS|B|BS):(.*)/
|
327
|
+
attr_name, attr_type, attr_value = attr_update.split(':')
|
328
|
+
attribute_updates[attr_name] = {
|
329
|
+
'Value' => {attr_type => attr_value},
|
330
|
+
'Action' => options[:attr_updates_action]
|
331
|
+
}
|
332
|
+
end
|
333
|
+
#Build and validate options if any
|
334
|
+
if options[:expected_attr] #-a
|
335
|
+
expected_attr_name, expected_attr_type, expected_attr_value = options[:expected_attr].split(':')
|
336
|
+
if expected_attr_name and expected_attr_type and expected_attr_value
|
337
|
+
if options[:expected_exists] and options[:expected_exists] == 'true' #-a Id:S:001 -e true
|
338
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value }, 'Exists' => options[:expected_exists] } }
|
339
|
+
else #-a Id:S:001
|
340
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value } } }
|
341
|
+
end
|
342
|
+
elsif expected_attr_name and not expected_attr_type and not expected_attr_value
|
343
|
+
if options[:expected_exists] and options[:expected_exists] == 'false' #-a Id -e false
|
344
|
+
opts['Expected'] = { expected_attr_name => { 'Exists' => options[:expected_exists] } }
|
345
|
+
else
|
346
|
+
abort 'Invalid option combination, see help for usage examples'
|
347
|
+
end
|
348
|
+
else
|
349
|
+
abort 'Invalid option combination, see help for usage examples'
|
350
|
+
end
|
351
|
+
end
|
352
|
+
if options[:return_values]
|
353
|
+
abort 'Invalid return type' unless %w(ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD).include?(options[:return_values])
|
354
|
+
opts['ReturnValues'] = options[:return_values]
|
355
|
+
end
|
356
|
+
@conn.update_item(options[:table_name], key, attribute_updates, opts)
|
357
|
+
rescue Excon::Errors::BadRequest
|
358
|
+
puts "[Error] Failed to update item. #{parse_excon_error_response($!)}"
|
359
|
+
else
|
360
|
+
puts 'Item update succeeded.'
|
361
|
+
end
|
362
|
+
|
363
|
+
def delete(options)
|
364
|
+
key = {}
|
365
|
+
opts = {}
|
366
|
+
#Build and validate key
|
367
|
+
abort 'Invalid --hash-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
368
|
+
hash_key_type, hash_key_name = options[:hash_key].split(':')
|
369
|
+
key['HashKeyElement'] = { hash_key_type => hash_key_name }
|
370
|
+
if options[:range_key]
|
371
|
+
abort 'Invalid --range-key format' unless options[:hash_key] =~ /(N|S|NS|SS|B|BS):(.*)/
|
372
|
+
range_key_type, range_key_name = options[:range_key].split(':')
|
373
|
+
key['RangeKeyElement'] = { range_key_type => range_key_name }
|
374
|
+
end
|
375
|
+
if options[:expected_attr] #-e
|
376
|
+
expected_attr_name, expected_attr_type, expected_attr_value = options[:expected_attr].split(':')
|
377
|
+
if expected_attr_name and expected_attr_type and expected_attr_value
|
378
|
+
if options[:expected_exists] and options[:expected_exists] == 'true' #-e Id:S:001 -x true
|
379
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value }, 'Exists' => options[:expected_exists] } }
|
380
|
+
else #-e Id:S:001
|
381
|
+
opts['Expected'] = { expected_attr_name => { 'Value' => { expected_attr_type => expected_attr_value } } }
|
382
|
+
end
|
383
|
+
elsif expected_attr_name and not expected_attr_type and not expected_attr_value
|
384
|
+
if options[:expected_exists] and options[:expected_exists] == 'false' #-e Id -x false
|
385
|
+
opts['Expected'] = { expected_attr_name => { 'Exists' => options[:expected_exists] } }
|
386
|
+
else
|
387
|
+
abort 'Invalid option combination, see help for usage examples'
|
388
|
+
end
|
389
|
+
else
|
390
|
+
abort 'Invalid option combination, see help for usage examples'
|
391
|
+
end
|
392
|
+
end
|
393
|
+
if options[:return_values]
|
394
|
+
abort 'Invalid return type' unless %w(ALL_NEW ALL_OLD NONE UPDATED_NEW UPDATED_OLD).include?(options[:return_values])
|
395
|
+
opts['ReturnValues'] = options[:return_values]
|
396
|
+
end
|
397
|
+
@conn.delete_item(options[:table_name], key, opts)
|
398
|
+
rescue Excon::Errors::BadRequest
|
399
|
+
puts "[Error] Failed to delete item. #{parse_excon_error_response($!)}"
|
400
|
+
else
|
401
|
+
puts 'Item delete succeeded.'
|
402
|
+
end
|
403
|
+
|
404
|
+
private
|
405
|
+
|
406
|
+
def parse_excon_error_response(response)
|
407
|
+
response.response.data[:body].match(/message.*|Message.*/)[0].gsub(/[^A-Za-z0-9: ]/, '')
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
data/lib/awscli/emr.rb
CHANGED
@@ -5,7 +5,7 @@ module Awscli
|
|
5
5
|
@conn = connection
|
6
6
|
end
|
7
7
|
|
8
|
-
def list
|
8
|
+
def list(options)
|
9
9
|
validate_job_ids options[:job_flow_ids] if options[:job_flow_ids]
|
10
10
|
opts = Marshal.load(Marshal.dump(options))
|
11
11
|
opts.reject! { |k| k == 'table' } if options[:table]
|
@@ -69,7 +69,7 @@ module Awscli
|
|
69
69
|
if options[:pig_steps]
|
70
70
|
steps << pig_install unless options[:pig_interactive]
|
71
71
|
options[:pig_steps].each do |step|
|
72
|
-
steps << parse_pig_steps(step
|
72
|
+
steps << parse_pig_steps(step)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
if options[:streaming_steps]
|
@@ -81,7 +81,7 @@ module Awscli
|
|
81
81
|
boot_strap_actions << hbase_install_boot_strap
|
82
82
|
steps << hbase_install_steps
|
83
83
|
#validate hadoop version and instance size
|
84
|
-
abort "Invalid hadoop version #{options[:hadoop_version]}, supported Hadoop Versions for HBase are: #{Awscli::EMR::
|
84
|
+
abort "Invalid hadoop version #{options[:hadoop_version]}, supported Hadoop Versions for HBase are: #{Awscli::EMR::HBASE_SUPPORTED_HADOOP.join(',')}" unless Awscli::EMR::HBASE_SUPPORTED_HADOOP.include?(options[:hadoop_version])
|
85
85
|
options[:instance_groups] && parse_instance_groups(options[:instance_groups]).each do |group|
|
86
86
|
unless is_valid_instance_type?(group['InstanceType'])
|
87
87
|
abort "Instance type #{group['InstanceType']} is not compatible with HBase, instance size should be equal or greater than m1.large"
|
@@ -235,7 +235,7 @@ module Awscli
|
|
235
235
|
#parse instance_groups => instance_count,instance_role(MASTER | CORE | TASK),instance_type,name,bid_price
|
236
236
|
instance_groups = []
|
237
237
|
groups.each do |group|
|
238
|
-
instance_count, instance_role, instance_size, name, bid_price =
|
238
|
+
instance_count, instance_role, instance_size, name, bid_price = group.split(',')
|
239
239
|
if instance_count.empty? or instance_role.empty? or instance_size.empty?
|
240
240
|
abort 'instance_count, instance_role and instance_size are required'
|
241
241
|
end
|
@@ -276,7 +276,6 @@ module Awscli
|
|
276
276
|
'Path' => path
|
277
277
|
}
|
278
278
|
}
|
279
|
-
boot_strap_actions
|
280
279
|
end
|
281
280
|
|
282
281
|
def parse_custom_jar(steps)
|
@@ -333,7 +332,7 @@ module Awscli
|
|
333
332
|
hive_step
|
334
333
|
end
|
335
334
|
|
336
|
-
def parse_pig_steps(step
|
335
|
+
def parse_pig_steps(step)
|
337
336
|
#parse script_path(s3)*,input_path(s3),output_path(s3),'-p','args1','-p','args2','-p','arg3'
|
338
337
|
path, input_path, output_path, *args = step.split(',')
|
339
338
|
abort 'path to the hive script is required' if path.empty?
|
data/lib/awscli/helper.rb
CHANGED
@@ -5,6 +5,7 @@ module Awscli
|
|
5
5
|
INSTANCE_TYPES = %w(on-demand spot)
|
6
6
|
REGIONS = %w(eu-west-1 sa-east-1 us-east-1 ap-northeast-1 us-west-2 us-west-1 ap-southeast-1 ap-southeast-2)
|
7
7
|
end
|
8
|
+
|
8
9
|
module EMR
|
9
10
|
VALID_JOB_FLOW_STATUS = %w(RUNNING WAITING SHUTTING_DOWN STARTING)
|
10
11
|
HADOOP_HIVE_COMPATIBILITY = {
|
@@ -19,7 +20,7 @@ module Awscli
|
|
19
20
|
'0.20' => '1.0',
|
20
21
|
'0.18' => '1.0'
|
21
22
|
}
|
22
|
-
|
23
|
+
HBASE_SUPPORTED_HADOOP = %w(0.20.205 1.0.3)
|
23
24
|
HBASE_INVALID_INSTANCES = %w(m1.small c1.medium)
|
24
25
|
end
|
25
26
|
end
|
data/lib/awscli/version.rb
CHANGED
data/lib/awscli.rb
CHANGED
metadata
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awscli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Ashrith
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-15 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rake
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
19
|
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
@@ -20,6 +22,7 @@ dependencies:
|
|
20
22
|
type: :development
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
27
|
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
@@ -27,6 +30,7 @@ dependencies:
|
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: rdoc
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
35
|
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
@@ -34,6 +38,7 @@ dependencies:
|
|
34
38
|
type: :development
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
43
|
- - ! '>='
|
39
44
|
- !ruby/object:Gem::Version
|
@@ -41,6 +46,7 @@ dependencies:
|
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: aruba
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
51
|
- - ! '>='
|
46
52
|
- !ruby/object:Gem::Version
|
@@ -48,6 +54,7 @@ dependencies:
|
|
48
54
|
type: :development
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
59
|
- - ! '>='
|
53
60
|
- !ruby/object:Gem::Version
|
@@ -55,6 +62,7 @@ dependencies:
|
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: thor
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
58
66
|
requirements:
|
59
67
|
- - ! '>='
|
60
68
|
- !ruby/object:Gem::Version
|
@@ -62,6 +70,7 @@ dependencies:
|
|
62
70
|
type: :runtime
|
63
71
|
prerelease: false
|
64
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
65
74
|
requirements:
|
66
75
|
- - ! '>='
|
67
76
|
- !ruby/object:Gem::Version
|
@@ -69,6 +78,7 @@ dependencies:
|
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: fog
|
71
80
|
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
72
82
|
requirements:
|
73
83
|
- - ! '>='
|
74
84
|
- !ruby/object:Gem::Version
|
@@ -76,6 +86,7 @@ dependencies:
|
|
76
86
|
type: :runtime
|
77
87
|
prerelease: false
|
78
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
79
90
|
requirements:
|
80
91
|
- - ! '>='
|
81
92
|
- !ruby/object:Gem::Version
|
@@ -83,6 +94,7 @@ dependencies:
|
|
83
94
|
- !ruby/object:Gem::Dependency
|
84
95
|
name: highline
|
85
96
|
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
86
98
|
requirements:
|
87
99
|
- - ! '>='
|
88
100
|
- !ruby/object:Gem::Version
|
@@ -90,6 +102,7 @@ dependencies:
|
|
90
102
|
type: :runtime
|
91
103
|
prerelease: false
|
92
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
93
106
|
requirements:
|
94
107
|
- - ! '>='
|
95
108
|
- !ruby/object:Gem::Version
|
@@ -111,6 +124,9 @@ files:
|
|
111
124
|
- lib/awscli/cli/as/instances.rb
|
112
125
|
- lib/awscli/cli/as/policies.rb
|
113
126
|
- lib/awscli/cli/as.rb
|
127
|
+
- lib/awscli/cli/dynamo/item.rb
|
128
|
+
- lib/awscli/cli/dynamo/table.rb
|
129
|
+
- lib/awscli/cli/dynamo.rb
|
114
130
|
- lib/awscli/cli/ec2/ami.rb
|
115
131
|
- lib/awscli/cli/ec2/ebs.rb
|
116
132
|
- lib/awscli/cli/ec2/eip.rb
|
@@ -147,6 +163,7 @@ files:
|
|
147
163
|
- lib/awscli/cli/UsageExamples/emr
|
148
164
|
- lib/awscli/cli.rb
|
149
165
|
- lib/awscli/connection.rb
|
166
|
+
- lib/awscli/dynamo.rb
|
150
167
|
- lib/awscli/ec2.rb
|
151
168
|
- lib/awscli/emr.rb
|
152
169
|
- lib/awscli/errors.rb
|
@@ -160,27 +177,28 @@ files:
|
|
160
177
|
homepage: http://github.com/ashrithr/awscli
|
161
178
|
licenses:
|
162
179
|
- MIT
|
163
|
-
metadata: {}
|
164
180
|
post_install_message: Thanks for installing!, This gem is still in development.
|
165
181
|
rdoc_options: []
|
166
182
|
require_paths:
|
167
183
|
- lib
|
168
184
|
- lib
|
169
185
|
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
170
187
|
requirements:
|
171
188
|
- - ! '>='
|
172
189
|
- !ruby/object:Gem::Version
|
173
190
|
version: '0'
|
174
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
|
+
none: false
|
175
193
|
requirements:
|
176
194
|
- - ! '>='
|
177
195
|
- !ruby/object:Gem::Version
|
178
196
|
version: '0'
|
179
197
|
requirements: []
|
180
198
|
rubyforge_project:
|
181
|
-
rubygems_version:
|
199
|
+
rubygems_version: 1.8.25
|
182
200
|
signing_key:
|
183
|
-
specification_version:
|
201
|
+
specification_version: 3
|
184
202
|
summary: Command Line Interface for Amazon Web Services built in Ruby, using Fog and
|
185
203
|
Thor
|
186
204
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
---
|
2
|
-
!binary "U0hBMQ==":
|
3
|
-
metadata.gz: !binary |-
|
4
|
-
ZjE2MzQxYjhkMTc5NDc5NzIyMjc2NDNiNzMxYjdiMTI4OThhOWJmNw==
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YjdlZjExYTBhMjAzNDE1ZjJiY2RlZWMyMjM1N2QyMzMyYjQxZGIyNQ==
|
7
|
-
!binary "U0hBNTEy":
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
M2VjYWEyOTBkNmZjYThiZTdmOTdhODQxZjc1Zjc0NDM2NmU1MDMwMDMxNTYx
|
10
|
-
MGQ2NmZkZjJkODFiN2I4Y2JmNWZjZWI1ZTExYmIyMTQ0NjY0YjI3YzgyMmY1
|
11
|
-
MzA1OGRkOTdmN2FlZTAxOWNhY2NiYmJlNzhlN2ZiNTJlMGFkODM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MmQ2OWM5MGUxNWU4MmJmZWI5NDliMmE3YzNiOWQ5M2M4Nzg3NDZlOTkxNzIw
|
14
|
-
N2I2NTY3MDM4N2RmYzRjYTAwNzgwMGJlMTY2YzBmYjUxNWNmNTEzNzhiMDZh
|
15
|
-
MGFmOTczMmQ0N2ZhYTlhZjIxMDU3MmM5NDhmMzBlMDZjOWI3ODY=
|