awscli 0.1.3 → 0.1.4
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/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=
|