stax 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/stax.rb +4 -1
- data/lib/stax/aws/apigw.rb +24 -0
- data/lib/stax/aws/dynamodb.rb +77 -0
- data/lib/stax/aws/ecs.rb +10 -1
- data/lib/stax/aws/firehose.rb +19 -0
- data/lib/stax/aws/lambda.rb +4 -0
- data/lib/stax/aws/logs.rb +4 -0
- data/lib/stax/cfer.rb +18 -0
- data/lib/stax/meta.rb +39 -0
- data/lib/stax/mixin/apigw.rb +41 -0
- data/lib/stax/mixin/dynamodb.rb +44 -7
- data/lib/stax/mixin/dynamodb/backup.rb +41 -0
- data/lib/stax/mixin/dynamodb/throughput.rb +67 -0
- data/lib/stax/mixin/ecs.rb +139 -59
- data/lib/stax/mixin/firehose.rb +34 -0
- data/lib/stax/mixin/lambda.rb +27 -0
- data/lib/stax/mixin/logs.rb +12 -0
- data/lib/stax/stack/crud.rb +5 -0
- data/lib/stax/staxfile.rb +6 -0
- data/lib/stax/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0444c2ae4f050d73ba7cfd720eca476667102bf2
|
4
|
+
data.tar.gz: 764f80db2e413eade8840ef8f04c33d93003e190
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb84fb5b04019ef607f8f4a6658414fdda2b3dbf641a31bbedadfb785ab20f1e76c8d039529c71a52d5f18419ead4c5594297bdfc7303efef8ccb4f8d0ef0191
|
7
|
+
data.tar.gz: f65676b1870954bcc39c5d53a0ecd7b238d5b2fafd7bd2ea5761fc993dece0e33c7b8c2205ebf6a61021b148ba01f84f8856a523fd4d4c2fa6ff3bbfcea6fb41
|
data/lib/stax.rb
CHANGED
@@ -8,6 +8,7 @@ require 'stax/staxfile'
|
|
8
8
|
require 'stax/base'
|
9
9
|
require 'stax/git'
|
10
10
|
require 'stax/cli'
|
11
|
+
require 'stax/meta'
|
11
12
|
require 'stax/subcommand'
|
12
13
|
require 'stax/cfer'
|
13
14
|
require 'stax/stack'
|
@@ -32,4 +33,6 @@ require 'stax/mixin/emr'
|
|
32
33
|
require 'stax/mixin/ssh'
|
33
34
|
require 'stax/mixin/lambda'
|
34
35
|
require 'stax/mixin/dynamodb'
|
35
|
-
require 'stax/mixin/logs'
|
36
|
+
require 'stax/mixin/logs'
|
37
|
+
require 'stax/mixin/apigw'
|
38
|
+
require 'stax/mixin/firehose'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module Stax
|
3
|
+
module Aws
|
4
|
+
class APIGateway < Sdk
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def client
|
9
|
+
@_client ||= ::Aws::APIGateway::Client.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def api(id)
|
13
|
+
client.get_rest_api(rest_api_id: id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def stages(id, deployment = nil)
|
17
|
+
client.get_stages(rest_api_id: id, deployment_id: deployment).item
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/stax/aws/dynamodb.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Stax
|
2
4
|
module Aws
|
3
5
|
class DynamoDB < Sdk
|
@@ -20,6 +22,81 @@ module Stax
|
|
20
22
|
client.describe_table(table_name: name).table.local_secondary_indexes || []
|
21
23
|
end
|
22
24
|
|
25
|
+
def key_schema(name)
|
26
|
+
client.describe_table(table_name: name).table.key_schema
|
27
|
+
end
|
28
|
+
|
29
|
+
## key schema as a hash
|
30
|
+
def keys(name)
|
31
|
+
key_schema(name).each_with_object({}) do |s, h|
|
32
|
+
h[s.key_type.downcase.to_sym] = s.attribute_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def do_scan(opt)
|
37
|
+
exclusive_start_key = nil
|
38
|
+
loop do
|
39
|
+
r = client.scan(opt.merge(exclusive_start_key: exclusive_start_key))
|
40
|
+
yield r
|
41
|
+
exclusive_start_key = r.last_evaluated_key
|
42
|
+
break unless exclusive_start_key
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def scan(opt)
|
47
|
+
do_scan(opt) do |r|
|
48
|
+
r.items.each do |item|
|
49
|
+
puts JSON.generate(item)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def count(opt)
|
55
|
+
total = 0
|
56
|
+
do_scan(opt.merge(select: 'COUNT')) do |r|
|
57
|
+
total += r.count
|
58
|
+
end
|
59
|
+
return total
|
60
|
+
end
|
61
|
+
|
62
|
+
def query(opt)
|
63
|
+
exclusive_start_key = nil
|
64
|
+
loop do
|
65
|
+
r = client.query(opt.merge(exclusive_start_key: exclusive_start_key))
|
66
|
+
r.items.each do |item|
|
67
|
+
puts JSON.generate(item)
|
68
|
+
end
|
69
|
+
exclusive_start_key = r.last_evaluated_key
|
70
|
+
break unless exclusive_start_key
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def list_backups(opt = {})
|
75
|
+
last_arn = nil
|
76
|
+
backups = []
|
77
|
+
loop do
|
78
|
+
r = client.list_backups(opt.merge(exclusive_start_backup_arn: last_arn))
|
79
|
+
backups += r.backup_summaries
|
80
|
+
last_arn = r.last_evaluated_backup_arn
|
81
|
+
break unless last_arn
|
82
|
+
end
|
83
|
+
backups
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_backup(table_name, backup_name)
|
87
|
+
client.create_backup(
|
88
|
+
table_name: table_name,
|
89
|
+
backup_name: backup_name,
|
90
|
+
).backup_details
|
91
|
+
end
|
92
|
+
|
93
|
+
def restore_backup(table_name, backup_arn)
|
94
|
+
client.restore_table_from_backup(
|
95
|
+
target_table_name: table_name,
|
96
|
+
backup_arn: backup_arn,
|
97
|
+
).table_description
|
98
|
+
end
|
99
|
+
|
23
100
|
end
|
24
101
|
|
25
102
|
end
|
data/lib/stax/aws/ecs.rb
CHANGED
@@ -16,6 +16,10 @@ module Stax
|
|
16
16
|
client.describe_services(cluster: cluster, services: services).services
|
17
17
|
end
|
18
18
|
|
19
|
+
def update_service(opt)
|
20
|
+
client.update_service(opt).service
|
21
|
+
end
|
22
|
+
|
19
23
|
def task_definition(name)
|
20
24
|
client.describe_task_definition(task_definition: name).task_definition
|
21
25
|
end
|
@@ -27,7 +31,12 @@ module Stax
|
|
27
31
|
end
|
28
32
|
|
29
33
|
def tasks(cluster, status = :RUNNING)
|
30
|
-
|
34
|
+
tasks = list_tasks(cluster, status)
|
35
|
+
if tasks.empty?
|
36
|
+
[]
|
37
|
+
else
|
38
|
+
client.describe_tasks(cluster: cluster, tasks: tasks).tasks
|
39
|
+
end
|
31
40
|
end
|
32
41
|
|
33
42
|
def list_instances(cluster)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Stax
|
2
|
+
module Aws
|
3
|
+
class Firehose < Sdk
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def client
|
8
|
+
@_client ||= ::Aws::Firehose::Client.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def describe(name)
|
12
|
+
client.describe_delivery_stream(delivery_stream_name: name).delivery_stream_description
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/stax/aws/lambda.rb
CHANGED
data/lib/stax/aws/logs.rb
CHANGED
data/lib/stax/cfer.rb
CHANGED
@@ -5,6 +5,7 @@ module Stax
|
|
5
5
|
class_option :use_previous_value, aliases: '-u', type: :array, default: [], desc: 'params to use previous value'
|
6
6
|
|
7
7
|
no_commands do
|
8
|
+
|
8
9
|
def cfer_parameters
|
9
10
|
{}
|
10
11
|
end
|
@@ -48,11 +49,28 @@ module Stax
|
|
48
49
|
Cfer.generate!(cfer_template, opts)
|
49
50
|
end
|
50
51
|
|
52
|
+
## generate method does puts, so steal stdout into a string
|
53
|
+
def cfer_generate_string
|
54
|
+
capture_stdout do
|
55
|
+
cfer_generate
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
51
59
|
def cfer_tail
|
52
60
|
Cfer.tail!(stack_name, follow: true, number: 1)
|
53
61
|
rescue ::Aws::CloudFormation::Errors::ValidationError => e
|
54
62
|
puts e.message
|
55
63
|
end
|
64
|
+
|
65
|
+
## temporarily grab stdout to a string
|
66
|
+
def capture_stdout
|
67
|
+
stdout, $stdout = $stdout, StringIO.new
|
68
|
+
yield
|
69
|
+
$stdout.string
|
70
|
+
ensure
|
71
|
+
$stdout = stdout
|
72
|
+
end
|
73
|
+
|
56
74
|
end
|
57
75
|
|
58
76
|
end
|
data/lib/stax/meta.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Stax
|
2
|
+
class Cli < Base
|
3
|
+
|
4
|
+
no_commands do
|
5
|
+
## create order: default to stacks from Staxfile, override if needed
|
6
|
+
## delete will be this, in reverse order
|
7
|
+
def stack_order
|
8
|
+
Stax.stack_list
|
9
|
+
end
|
10
|
+
|
11
|
+
def stack_objects
|
12
|
+
stack_order.map(&method(:stack))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'create', 'meta create task'
|
17
|
+
def create
|
18
|
+
stack_objects.each do |s|
|
19
|
+
if s.exists?
|
20
|
+
say("Skipping: #{s.stack_name} exists", :yellow)
|
21
|
+
elsif y_or_n?("Create #{s.stack_name}?", :yellow)
|
22
|
+
s.create
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'delete', 'meta delete task'
|
28
|
+
def delete
|
29
|
+
stack_objects.reverse.each do |s|
|
30
|
+
if s.exists?
|
31
|
+
s.delete
|
32
|
+
else
|
33
|
+
say("#{s.stack_name} does not exist", :green)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'stax/aws/apigw'
|
2
|
+
|
3
|
+
module Stax
|
4
|
+
module Apigw
|
5
|
+
def self.included(thor)
|
6
|
+
thor.desc(:apigw, 'API Gateway subcommands')
|
7
|
+
thor.subcommand(:apigw, Cmd::Apigw)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Cmd
|
12
|
+
class Apigw < SubCommand
|
13
|
+
|
14
|
+
no_commands do
|
15
|
+
def stack_apis
|
16
|
+
Aws::Cfn.resources_by_type(my.stack_name, 'AWS::ApiGateway::RestApi')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'ls', 'list APIS'
|
21
|
+
def ls
|
22
|
+
print_table stack_apis.map { |r|
|
23
|
+
a = Aws::APIGateway.api(r.physical_resource_id)
|
24
|
+
[a.name, a.id, a.endpoint_configuration.types.join(','), a.created_date, a.description]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'stages', 'list API stages'
|
29
|
+
def stages
|
30
|
+
stack_apis.each do |r|
|
31
|
+
api = Aws::APIGateway.api(r.physical_resource_id)
|
32
|
+
debug("Stages for API #{api.name} #{api.id}")
|
33
|
+
print_table Aws::APIGateway.stages(api.id).map { |s|
|
34
|
+
[s.stage_name, s.deployment_id, s.created_date, s.last_updated_date, s.description]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/stax/mixin/dynamodb.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
require 'stax/aws/dynamodb'
|
3
|
+
require_relative 'dynamodb/throughput'
|
4
|
+
require_relative 'dynamodb/backup'
|
2
5
|
|
3
6
|
module Stax
|
4
7
|
module DynamoDB
|
@@ -12,16 +15,25 @@ module Stax
|
|
12
15
|
class DynamoDB < SubCommand
|
13
16
|
|
14
17
|
COLORS = {
|
15
|
-
CREATING:
|
16
|
-
UPDATING:
|
17
|
-
DELETING:
|
18
|
-
ACTIVE:
|
18
|
+
CREATING: :yellow,
|
19
|
+
UPDATING: :yellow,
|
20
|
+
DELETING: :red,
|
21
|
+
ACTIVE: :green,
|
22
|
+
DELETED: :red,
|
23
|
+
AVAILABLE: :green,
|
19
24
|
}
|
20
25
|
|
21
26
|
no_commands do
|
22
27
|
def stack_tables
|
23
28
|
Aws::Cfn.resources_by_type(my.stack_name, 'AWS::DynamoDB::Table')
|
24
29
|
end
|
30
|
+
|
31
|
+
## get table names from logical IDs, return all tables if nil
|
32
|
+
def stack_table_names(logical_ids)
|
33
|
+
stack_tables.tap do |tables|
|
34
|
+
tables.select! { |t| logical_ids.include?(t.logical_resource_id) } if logical_ids
|
35
|
+
end.map(&:physical_resource_id)
|
36
|
+
end
|
25
37
|
end
|
26
38
|
|
27
39
|
desc 'tables', 'list tables for stack'
|
@@ -52,9 +64,34 @@ module Stax
|
|
52
64
|
|
53
65
|
desc 'keys ID', 'get hash and range keys of table with ID'
|
54
66
|
def keys(id)
|
55
|
-
print_table Aws::DynamoDB.
|
56
|
-
|
57
|
-
|
67
|
+
print_table Aws::DynamoDB.keys(my.resource(id))
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'scan ID', 'scan table with given logical id from this stack'
|
71
|
+
def scan(id)
|
72
|
+
Aws::DynamoDB.scan(table_name: my.resource(id))
|
73
|
+
end
|
74
|
+
|
75
|
+
desc 'count ID', 'count items in table with given id'
|
76
|
+
def count(id)
|
77
|
+
puts Aws::DynamoDB.count(table_name: my.resource(id))
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'query ID HASH_VALUE [RANGE_VALUE]', 'query table with id'
|
81
|
+
def query(id, hash_value, range_value = nil)
|
82
|
+
name = my.resource(id)
|
83
|
+
k = Aws::DynamoDB.keys(name)
|
84
|
+
Aws::DynamoDB.query(
|
85
|
+
table_name: name,
|
86
|
+
expression_attribute_values: {
|
87
|
+
':h' => hash_value,
|
88
|
+
':r' => range_value,
|
89
|
+
}.compact,
|
90
|
+
key_condition_expression: [
|
91
|
+
"#{k[:hash]} = :h",
|
92
|
+
range_value ? "#{k[:range]} = :r" : nil,
|
93
|
+
].compact.join(' and '),
|
94
|
+
)
|
58
95
|
end
|
59
96
|
|
60
97
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Stax
|
2
|
+
module Cmd
|
3
|
+
class DynamoDB < SubCommand
|
4
|
+
|
5
|
+
no_commands do
|
6
|
+
def list_backups(name)
|
7
|
+
debug("Backups for #{name}")
|
8
|
+
print_table Aws::DynamoDB.list_backups(table_name: name).map { |b|
|
9
|
+
[b.backup_name, color(b.backup_status, COLORS), b.table_name, b.backup_creation_date_time, human_bytes(b.backup_size_bytes)]
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_backup(table_name, backup_name)
|
14
|
+
backup_name = Time.now.utc.strftime("#{table_name}-%Y%m%d%H%M%S") if backup_name == 'create' # thor option empty
|
15
|
+
debug("Creating backup #{backup_name} from #{table_name}")
|
16
|
+
Aws::DynamoDB.create_backup(table_name, backup_name).tap do |b|
|
17
|
+
puts YAML.dump(stringify_keys(b.to_hash))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'backup ID', 'table backups'
|
23
|
+
method_option :create, aliases: '-c', type: :string, default: nil, desc: 'create new backup from table'
|
24
|
+
def backup(id = nil)
|
25
|
+
name = my.resource(id)
|
26
|
+
if options[:create]
|
27
|
+
create_backup(name, options[:create])
|
28
|
+
else
|
29
|
+
list_backups(name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'restore ARN TABLE', 'restore backup to a new table'
|
34
|
+
def restore(arn, table)
|
35
|
+
debug("Creating table #{table} from backup #{arn}")
|
36
|
+
Aws::DynamoDB.restore_backup(table, arn)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Stax
|
2
|
+
module Cmd
|
3
|
+
class DynamoDB < SubCommand
|
4
|
+
|
5
|
+
no_commands do
|
6
|
+
def print_throughput(ids)
|
7
|
+
output = [['NAME', 'INDEX NAME', 'READ CAPACITY', 'WRITE CAPACITY', 'DECREASES TODAY']]
|
8
|
+
stack_table_names(ids).each do |name|
|
9
|
+
table = Aws::DynamoDB.table(name)
|
10
|
+
t = table.provisioned_throughput
|
11
|
+
output << [table.table_name, nil, t.read_capacity_units, t.write_capacity_units, t.number_of_decreases_today]
|
12
|
+
(table.global_secondary_indexes || []).each do |gsi|
|
13
|
+
t = gsi.provisioned_throughput
|
14
|
+
output << [table.table_name, gsi.index_name, t.read_capacity_units, t.write_capacity_units, t.number_of_decreases_today]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
print_table(output)
|
18
|
+
end
|
19
|
+
|
20
|
+
def update_throughput(ids, read, write)
|
21
|
+
debug("Updating throughput on #{ids ? ids.count : 'all'} tables")
|
22
|
+
stack_table_names(ids).each do |name|
|
23
|
+
puts name
|
24
|
+
table = Aws::DynamoDB.table(name)
|
25
|
+
begin
|
26
|
+
Aws::DynamoDB.client.update_table(
|
27
|
+
table_name: name,
|
28
|
+
provisioned_throughput: {
|
29
|
+
read_capacity_units: read || table.provisioned_throughput.read_capacity_units,
|
30
|
+
write_capacity_units: write || table.provisioned_throughput.write_capacity_units,
|
31
|
+
},
|
32
|
+
global_secondary_index_updates: table.global_secondary_indexes&.map do |gsi|
|
33
|
+
{
|
34
|
+
update: {
|
35
|
+
index_name: gsi.index_name,
|
36
|
+
provisioned_throughput: {
|
37
|
+
read_capacity_units: read || gsi.provisioned_throughput.read_capacity_units,
|
38
|
+
write_capacity_units: write || gsi.provisioned_throughput.write_capacity_units,
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
)
|
44
|
+
rescue ::Aws::DynamoDB::Errors::ValidationException
|
45
|
+
puts 'no change'
|
46
|
+
rescue ::Aws::DynamoDB::Errors::ResourceInUseException => e
|
47
|
+
warn(e.message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'throughput ID', 'throughput'
|
54
|
+
method_option :tables, aliases: '-t', type: :array, default: nil, desc: 'limit to given table IDs'
|
55
|
+
method_option :read, aliases: '-r', type: :numeric, default: nil, desc: 'set read capacity units'
|
56
|
+
method_option :write, aliases: '-w', type: :numeric, default: nil, desc: 'set write capacity units'
|
57
|
+
def throughput
|
58
|
+
if options[:write] || options[:read]
|
59
|
+
update_throughput(options[:tables], options[:read], options[:write])
|
60
|
+
else
|
61
|
+
print_throughput(options[:tables])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/stax/mixin/ecs.rb
CHANGED
@@ -6,6 +6,42 @@ module Stax
|
|
6
6
|
thor.desc(:ecs, 'ECS subcommands')
|
7
7
|
thor.subcommand(:ecs, Cmd::Ecs)
|
8
8
|
end
|
9
|
+
|
10
|
+
def ecs_cluster_name
|
11
|
+
'default'
|
12
|
+
end
|
13
|
+
|
14
|
+
def ecs_services
|
15
|
+
@_ecs_services ||= Aws::Cfn.resources_by_type(stack_name, 'AWS::ECS::Service')
|
16
|
+
end
|
17
|
+
|
18
|
+
def ecs_task_definitions
|
19
|
+
@_ecs_task_definitions ||= Aws::Cfn.resources_by_type(stack_name, 'AWS::ECS::TaskDefinition')
|
20
|
+
end
|
21
|
+
|
22
|
+
def ecs_service_objects
|
23
|
+
Aws::Ecs.services(ecs_cluster_name, ecs_services.map(&:physical_resource_id))
|
24
|
+
end
|
25
|
+
|
26
|
+
## register a new revision of existing task definition
|
27
|
+
def ecs_update_taskdef(id)
|
28
|
+
taskdef = Aws::Ecs.task_definition(resource(id))
|
29
|
+
debug("Registering new revision of #{taskdef.family}")
|
30
|
+
args = %i[family cpu memory requires_compatibilities task_role_arn execution_role_arn network_mode container_definitions volumes placement_constraints]
|
31
|
+
Aws::Ecs.client.register_task_definition(taskdef.to_hash.slice(*args)).task_definition.tap do |t|
|
32
|
+
puts t.task_definition_arn
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
## update service to use a new task definition
|
37
|
+
def ecs_update_service(id, taskdef)
|
38
|
+
service_name = resource(id).split('/').last
|
39
|
+
taskdef_name = taskdef.task_definition_arn.split('/').last
|
40
|
+
debug("Updating #{service_name} to #{taskdef_name}")
|
41
|
+
Aws::Ecs.update_service(service: service_name, task_definition: taskdef_name).tap do |s|
|
42
|
+
puts s.task_definition
|
43
|
+
end
|
44
|
+
end
|
9
45
|
end
|
10
46
|
|
11
47
|
module Cmd
|
@@ -18,26 +54,14 @@ module Stax
|
|
18
54
|
}
|
19
55
|
|
20
56
|
no_commands do
|
21
|
-
def ecs_cluster_name
|
22
|
-
@_ecs_cluster_name ||= my.stack_name
|
23
|
-
end
|
24
|
-
|
25
|
-
def ecs_task_definitions
|
26
|
-
@_ecs_task_definitions ||= Aws::Cfn.resources_by_type(my.stack_name, 'AWS::ECS::TaskDefinition' )
|
27
|
-
end
|
28
|
-
|
29
57
|
def ecs_task_definition(id)
|
30
58
|
Aws::Cfn.id(my.stack_name, id)
|
31
59
|
end
|
32
|
-
|
33
|
-
def ecs_services
|
34
|
-
@_ecs_services ||= Aws::Cfn.resources_by_type(my.stack_name, 'AWS::ECS::Service')
|
35
|
-
end
|
36
60
|
end
|
37
61
|
|
38
62
|
desc 'clusters', 'ECS cluster for stack'
|
39
63
|
def clusters
|
40
|
-
print_table Aws::Ecs.clusters(ecs_cluster_name).map { |c|
|
64
|
+
print_table Aws::Ecs.clusters(my.ecs_cluster_name).map { |c|
|
41
65
|
[
|
42
66
|
c.cluster_name,
|
43
67
|
color(c.status, COLORS),
|
@@ -50,63 +74,119 @@ module Stax
|
|
50
74
|
|
51
75
|
desc 'services', 'ECS services for stack'
|
52
76
|
def services
|
53
|
-
print_table
|
77
|
+
print_table my.ecs_service_objects.map { |s|
|
54
78
|
[s.service_name, color(s.status, COLORS), s.task_definition.split('/').last, "#{s.running_count}/#{s.desired_count}"]
|
55
79
|
}
|
56
80
|
end
|
57
81
|
|
82
|
+
desc 'events', 'show service events'
|
83
|
+
method_option :number, aliases: '-n', type: :numeric, default: 10, desc: 'number of events to show'
|
84
|
+
def events
|
85
|
+
my.ecs_service_objects.each do |s|
|
86
|
+
debug("Events for #{s.service_name}")
|
87
|
+
print_table s.events.first(options[:number]).map { |e|
|
88
|
+
[set_color(e.created_at, :green), e.message]
|
89
|
+
}.reverse
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
desc 'deployments', 'show service deployments'
|
94
|
+
def deployments
|
95
|
+
my.ecs_service_objects.each do |s|
|
96
|
+
debug("Deployments for #{s.service_name}")
|
97
|
+
print_table s.deployments.map { |d|
|
98
|
+
count = "#{d.running_count}/#{d.desired_count} (#{d.pending_count})"
|
99
|
+
[d.id, d.status, count, d.created_at, d.updated_at, d.task_definition.split('/').last]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
58
104
|
desc 'definitions', 'ECS task definitions for stack'
|
59
105
|
def definitions
|
60
|
-
print_table ecs_task_definitions.map { |r|
|
106
|
+
print_table my.ecs_task_definitions.map { |r|
|
61
107
|
t = Aws::Ecs.task_definition(r.physical_resource_id)
|
62
108
|
[r.logical_resource_id, t.family, t.revision, color(t.status, COLORS)]
|
63
109
|
}
|
64
110
|
end
|
65
111
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
112
|
+
desc 'tasks', 'ECS tasks for stack'
|
113
|
+
method_option :status, aliases: '-s', type: :string, default: 'RUNNING', desc: 'status to list'
|
114
|
+
def tasks
|
115
|
+
print_table Aws::Ecs.tasks(my.ecs_cluster_name, options[:status].upcase).map { |t|
|
116
|
+
[
|
117
|
+
t.task_arn.split('/').last,
|
118
|
+
t.task_definition_arn.split('/').last,
|
119
|
+
t.container_instance_arn&.split('/')&.last || '--',
|
120
|
+
color(t.last_status, COLORS),
|
121
|
+
"(#{t.desired_status})",
|
122
|
+
t.started_by,
|
123
|
+
]
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
desc 'containers', 'containers for running tasks'
|
128
|
+
method_option :status, aliases: '-s', type: :string, default: 'RUNNING', desc: 'status to list'
|
129
|
+
def containers
|
130
|
+
debug("Containers for cluster #{my.ecs_cluster_name}")
|
131
|
+
print_table Aws::Ecs.tasks(my.ecs_cluster_name, options[:status].upcase).map { |task|
|
132
|
+
task_defn = task.task_definition_arn.split('/').last
|
133
|
+
task.containers.map { |c|
|
134
|
+
[
|
135
|
+
c.container_arn.split('/').last,
|
136
|
+
c.name,
|
137
|
+
color(c.last_status, COLORS),
|
138
|
+
c.network_interfaces.map(&:private_ipv_4_address).join(','),
|
139
|
+
task_defn,
|
140
|
+
c.exit_code,
|
141
|
+
c.reason,
|
142
|
+
]
|
143
|
+
}
|
144
|
+
}.flatten(1)
|
145
|
+
end
|
146
|
+
|
147
|
+
desc 'instances', 'ECS instances'
|
148
|
+
def instances
|
149
|
+
print_table Aws::Ecs.instances(my.ecs_cluster_name).map { |i|
|
150
|
+
[
|
151
|
+
i.container_instance_arn.split('/').last,
|
152
|
+
i.ec2_instance_id,
|
153
|
+
i.agent_connected,
|
154
|
+
color(i.status, COLORS),
|
155
|
+
i.running_tasks_count,
|
156
|
+
"(#{i.pending_tasks_count})",
|
157
|
+
"agent #{i.version_info.agent_version}",
|
158
|
+
i.version_info.docker_version,
|
159
|
+
]
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
desc 'run_task [ID]', 'run task by id'
|
164
|
+
def run_task(id)
|
165
|
+
Aws::Ecs.run(my.ecs_cluster_name, Aws::Cfn.id(my.stack_name, id)).tap do |tasks|
|
166
|
+
puts tasks.map(&:container_instance_arn)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
desc 'stop_task [TASK]', 'stop task'
|
171
|
+
def stop_task(task)
|
172
|
+
Aws::Ecs.stop(my.ecs_cluster_name, task).tap do |task|
|
173
|
+
puts task.container_instance_arn
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
desc 'scale', 'scale containers for service'
|
178
|
+
method_option :desired, aliases: '-d', type: :numeric, default: nil, desc: 'desired container count'
|
179
|
+
def scale
|
180
|
+
my.ecs_services.each do |s|
|
181
|
+
debug("Scaling service #{s.logical_resource_id}")
|
182
|
+
Aws::Ecs.update_service(
|
183
|
+
service: s.physical_resource_id,
|
184
|
+
desired_count: options[:desired],
|
185
|
+
).tap do |s|
|
186
|
+
puts "desired: #{s.desired_count}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
110
190
|
|
111
191
|
end
|
112
192
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'stax/aws/firehose'
|
2
|
+
|
3
|
+
module Stax
|
4
|
+
module Firehose
|
5
|
+
def self.included(thor)
|
6
|
+
thor.desc(:firehose, 'Firehose subcommands')
|
7
|
+
thor.subcommand(:firehose, Cmd::Firehose)
|
8
|
+
|
9
|
+
def stack_firehoses
|
10
|
+
Aws::Cfn.resources_by_type(stack_name, 'AWS::KinesisFirehose::DeliveryStream')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Cmd
|
16
|
+
class Firehose < SubCommand
|
17
|
+
|
18
|
+
COLORS = {
|
19
|
+
ACTIVE: :green,
|
20
|
+
CREATING: :yellow,
|
21
|
+
DELETING: :red,
|
22
|
+
}
|
23
|
+
|
24
|
+
desc 'ls', 'list stack firehoses'
|
25
|
+
def ls
|
26
|
+
print_table my.stack_firehoses.map { |r|
|
27
|
+
f = Aws::Firehose.describe(r.physical_resource_id)
|
28
|
+
[f.delivery_stream_name, color(f.delivery_stream_status, COLORS), f.create_timestamp, f.delivery_stream_type]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/stax/mixin/lambda.rb
CHANGED
@@ -18,6 +18,21 @@ module Stax
|
|
18
18
|
def stack_lambdas
|
19
19
|
Aws::Cfn.resources_by_type(my.stack_name, 'AWS::Lambda::Function')
|
20
20
|
end
|
21
|
+
|
22
|
+
## return zip file contents, make it if necessary
|
23
|
+
def zip_thing(thing)
|
24
|
+
if File.directory?(thing)
|
25
|
+
Dir.chdir(thing) do
|
26
|
+
%x[zip -q -r - .] # zip dir contents
|
27
|
+
end
|
28
|
+
elsif thing.match(/\.zip$/i)
|
29
|
+
File.read(thing) # raw zipfile contents
|
30
|
+
elsif File.file?(thing)
|
31
|
+
%x[zip -q -j - #{thing}] # zip a single file
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
21
36
|
end
|
22
37
|
|
23
38
|
desc 'ls', 'list lambdas for stack'
|
@@ -52,6 +67,18 @@ module Stax
|
|
52
67
|
end
|
53
68
|
end
|
54
69
|
|
70
|
+
desc 'update ID FILE', 'update code for lambda function with ID'
|
71
|
+
method_option :publish, aliases: '-p', type: :boolean, default: false, desc: 'publish as a new version'
|
72
|
+
def update(id, file)
|
73
|
+
Aws::Lambda.update_code(
|
74
|
+
function_name: my.resource(id),
|
75
|
+
publish: options[:publish],
|
76
|
+
zip_file: zip_thing(file),
|
77
|
+
)&.version.tap do |v|
|
78
|
+
puts "version: #{v}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
55
82
|
desc 'test ID', 'run lambda with ID'
|
56
83
|
method_option :type, type: :string, default: nil, desc: 'invocation type: RequestResponse, Event'
|
57
84
|
method_option :tail, type: :boolean, default: false, desc: 'tail log for RequestResponse'
|
data/lib/stax/mixin/logs.rb
CHANGED
@@ -89,6 +89,18 @@ module Stax
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
## lambdas create their own log groups, and when we delete stack they are left behind;
|
93
|
+
## this task looks up their names by stack prefix, and deletes them
|
94
|
+
desc 'cleanup', 'cleanup lambda log groups named for stack'
|
95
|
+
method_option :test, aliases: '-t', type: :boolean, default: false, desc: 'show group names without deleting'
|
96
|
+
def cleanup
|
97
|
+
debug("Cleaning up log groups for stack #{my.stack_name}")
|
98
|
+
Aws::Logs.groups("/aws/lambda/#{my.stack_name}").map(&:log_group_name).each do |name|
|
99
|
+
puts name
|
100
|
+
Aws::Logs.delete_group(name) unless options[:test]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
92
104
|
end
|
93
105
|
end
|
94
106
|
end
|
data/lib/stax/stack/crud.rb
CHANGED
@@ -75,6 +75,11 @@ module Stax
|
|
75
75
|
cfer_tail
|
76
76
|
end
|
77
77
|
|
78
|
+
desc 'generate', 'generate cloudformation template'
|
79
|
+
def generate
|
80
|
+
cfer_generate
|
81
|
+
end
|
82
|
+
|
78
83
|
desc 'protection', 'show/set termination protection for stack'
|
79
84
|
method_option :enable, aliases: '-e', type: :boolean, default: nil, desc: 'enable termination protection'
|
80
85
|
method_option :disable, aliases: '-d', type: :boolean, default: nil, desc: 'disable termination protection'
|
data/lib/stax/staxfile.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
module Stax
|
2
|
+
@@_stack_list = []
|
3
|
+
|
4
|
+
def self.stack_list
|
5
|
+
@@_stack_list
|
6
|
+
end
|
2
7
|
|
3
8
|
## search up the dir tree for nearest Staxfile
|
4
9
|
def self.load_staxfile
|
@@ -14,6 +19,7 @@ module Stax
|
|
14
19
|
|
15
20
|
## add a stack by name, creates class as needed
|
16
21
|
def self.add_stack(name, opt = {})
|
22
|
+
@@_stack_list << name
|
17
23
|
c = name.capitalize
|
18
24
|
|
19
25
|
## create the class if it does not exist yet
|
data/lib/stax/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Lister
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -131,6 +131,7 @@ files:
|
|
131
131
|
- lib/stax.rb
|
132
132
|
- lib/stax/asg.rb
|
133
133
|
- lib/stax/aws/alb.rb
|
134
|
+
- lib/stax/aws/apigw.rb
|
134
135
|
- lib/stax/aws/asg.rb
|
135
136
|
- lib/stax/aws/cfn.rb
|
136
137
|
- lib/stax/aws/dynamodb.rb
|
@@ -139,6 +140,7 @@ files:
|
|
139
140
|
- lib/stax/aws/ecs.rb
|
140
141
|
- lib/stax/aws/elb.rb
|
141
142
|
- lib/stax/aws/emr.rb
|
143
|
+
- lib/stax/aws/firehose.rb
|
142
144
|
- lib/stax/aws/iam.rb
|
143
145
|
- lib/stax/aws/keypair.rb
|
144
146
|
- lib/stax/aws/kms.rb
|
@@ -159,13 +161,18 @@ files:
|
|
159
161
|
- lib/stax/github.rb
|
160
162
|
- lib/stax/iam.rb
|
161
163
|
- lib/stax/keypair.rb
|
164
|
+
- lib/stax/meta.rb
|
162
165
|
- lib/stax/mixin/alb.rb
|
166
|
+
- lib/stax/mixin/apigw.rb
|
163
167
|
- lib/stax/mixin/asg.rb
|
164
168
|
- lib/stax/mixin/dynamodb.rb
|
169
|
+
- lib/stax/mixin/dynamodb/backup.rb
|
170
|
+
- lib/stax/mixin/dynamodb/throughput.rb
|
165
171
|
- lib/stax/mixin/ec2.rb
|
166
172
|
- lib/stax/mixin/ecs.rb
|
167
173
|
- lib/stax/mixin/elb.rb
|
168
174
|
- lib/stax/mixin/emr.rb
|
175
|
+
- lib/stax/mixin/firehose.rb
|
169
176
|
- lib/stax/mixin/keypair.rb
|
170
177
|
- lib/stax/mixin/kms.rb
|
171
178
|
- lib/stax/mixin/lambda.rb
|