tailstack 0.0.1

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/tailstack +182 -0
  3. metadata +45 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b0157e2f5e14279fee2665aa8f66d6c23dc01395
4
+ data.tar.gz: 9b8b81217097bc57aa4ebb0b8043d29cab3a7bc1
5
+ SHA512:
6
+ metadata.gz: 52de217db800b434c5521ae3f5b3ebe24007da01358a4cefb7c602d1088b3a5a04d1db65858180d7f5892068ad4d5f32074f3beff21ee672786a95b3f24e7d4d
7
+ data.tar.gz: 6a348d21656d70f614dc37ac79f652fc520e9964b8bb411e0d1ba8ae0e3056e36a154661b287cece664423cd21d49a2d1514ff3c0c0a3997b5faf479eb538c81
@@ -0,0 +1,182 @@
1
+ #!/usr/local/bin/ruby
2
+ require 'rubygems'
3
+ require 'aws-sdk'
4
+ require 'json'
5
+ require 'optparse'
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: tailstack [options]"
10
+ opts.on('-r', '--region REGION', 'AWS Region such as "us-west-2"'){ |o| options[:region] = o }
11
+ opts.on('-s', '--stack STACK_NAME', 'CloudFormation Stack to tail'){ |o| options[:stack] = o }
12
+ opts.on('-p', '--profile PROFILE', 'Specify AWS profile from config file'){ |o| options[:profile] = o }
13
+ opts.on('-l', '--list', 'Lists stacks in environtment and exits'){ |o| options[:list] = o }
14
+ opts.on('-o', '--outputs', 'Combine with --list also list outputs'){ |o| options[:outputs] = o }
15
+ opts.on('-d', '--parms', 'Combine with --list also list parameters'){ |o| options[:parms] = o }
16
+ end.parse!
17
+
18
+ using_env_creds = true
19
+ aws_access_key_id = nil
20
+ aws_secret_access_key = nil
21
+ options[:profile] ||= 'default'
22
+
23
+ if !options.key?(:region)
24
+ found_profile = false
25
+
26
+ if File.exists?(File.expand_path('~/.aws/config'))
27
+ File.read(File.expand_path('~/.aws/config')).each_line do |line|
28
+ if found_profile
29
+ options[:region] = line.split('=').last.strip
30
+ puts "Using region #{options[:region]}"
31
+ break;
32
+ end
33
+ if line.match("#{options[:profile]}\\]")
34
+ found_profile = true
35
+ end
36
+ end
37
+ else
38
+ puts "~/.aws/config file not found for reading the region"
39
+ end
40
+ end
41
+
42
+ if (!ENV.key?('AWS_ACCESS_KEY_ID') || !ENV.key?('AWS_SECRET_ACCESS_KEY')) || options.key?(:profile)
43
+ found_profile = false
44
+ found_key = false
45
+ found_secret = false
46
+
47
+ if File.exist?(File.expand_path('~/.aws/credentials'))
48
+ File.read(File.expand_path('~/.aws/credentials')).each_line do |line|
49
+ if found_profile && line.match('aws_access_key_id')
50
+ aws_access_key_id = line.split('=').last.strip
51
+ found_key = true
52
+ if found_secret
53
+ break
54
+ end
55
+ end
56
+ if found_profile && line.match('aws_secret_access_key')
57
+ aws_secret_access_key = line.split('=').last.strip
58
+ found_secret = true
59
+ using_env_creds = false
60
+ if found_key
61
+ break
62
+ end
63
+ end
64
+ if line.match("\\[#{options[:profile]}\\]")
65
+ found_profile = true
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ if found_key && using_env_creds == false
72
+ Aws.config.update({
73
+ region: options[:region],
74
+ credentials: Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
75
+ })
76
+ else
77
+ Aws.config.update({ region: options[:region] })
78
+ end
79
+
80
+ # Color stuff
81
+ class String
82
+ def black; "\e[30m#{self}\e[0m" end
83
+ def red; "\e[31m#{self}\e[0m" end
84
+ def green; "\e[32m#{self}\e[0m" end
85
+ def brown; "\e[33m#{self}\e[0m" end
86
+ def blue; "\e[34m#{self}\e[0m" end
87
+ def magenta; "\e[35m#{self}\e[0m" end
88
+ def cyan; "\e[36m#{self}\e[0m" end
89
+ def gray; "\e[37m#{self}\e[0m" end
90
+
91
+ def bg_black; "\e[40m#{self}\e[0m" end
92
+ def bg_red; "\e[41m#{self}\e[0m" end
93
+ def bg_green; "\e[42m#{self}\e[0m" end
94
+ def bg_brown; "\e[43m#{self}\e[0m" end
95
+ def bg_blue; "\e[44m#{self}\e[0m" end
96
+ def bg_magenta; "\e[45m#{self}\e[0m" end
97
+ def bg_cyan; "\e[46m#{self}\e[0m" end
98
+ def bg_gray; "\e[47m#{self}\e[0m" end
99
+
100
+ def bold; "\e[1m#{self}\e[22m" end
101
+ def italic; "\e[3m#{self}\e[23m" end
102
+ def underline; "\e[4m#{self}\e[24m" end
103
+ def blink; "\e[5m#{self}\e[25m" end
104
+ def reverse_color; "\e[7m#{self}\e[27m" end
105
+ end
106
+
107
+ def event_color(resource_status)
108
+ event_green = %w[ UPDATE_COMPLETE CREATE_COMPLETE DELETE_COMPLETE UPDATE_COMPLETE_CLEANUP_IN_PROGRESS UPDATE_ROLLBACK_COMPLETE ]
109
+ event_yellow = %w[ UPDATE_IN_PROGRESS CREATE_IN_PROGRESS DELETE_IN_PROGRESS UPDATE_ROLLBACK_IN_PROGRESS UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS ]
110
+
111
+ case
112
+ when event_green.include?(resource_status)
113
+ return resource_status.green
114
+ when event_yellow.include?(resource_status)
115
+ return resource_status.brown
116
+ else
117
+ return resource_status.red
118
+ end
119
+ end
120
+
121
+ # AWS Calls now
122
+ cfn = Aws::CloudFormation::Client.new()
123
+
124
+ def isThisTheEnd? event
125
+ events_good = %w[ CREATE_COMPLETE UPDATE_COMPLETE DELETE_COMPLETE ]
126
+ events_bad = %w[ CREATE_FAILED UPDATE_ROLLBACK_COMPLETE ROLLBACK_COMPLETE ]
127
+
128
+ unless event[:resource_type] == 'AWS::CloudFormation::Stack'
129
+ return false
130
+ end
131
+
132
+ if events_bad.include? event[:resource_status]
133
+ exit 1
134
+ end
135
+
136
+ return events_good.include? event[:resource_status]
137
+ end
138
+
139
+ if options.key?(:list)
140
+ stack_details = cfn.describe_stacks.to_h[:stacks]
141
+ cfn.list_stacks.to_h[:stack_summaries].uniq{|s| s[:stack_name]}.collect do |s|
142
+ if s[:stack_status] != 'DELETE_COMPLETE'
143
+ puts "#{s[:stack_name].bold} - #{s[:template_description].cyan}"
144
+ outputs = stack_details.find{|stack| stack[:stack_name] == s[:stack_name]}[:outputs]
145
+ parms = stack_details.find{|stack| stack[:stack_name] == s[:stack_name]}[:parameters]
146
+ if options.key?(:parms) && parms
147
+ puts " #{"Parameters:".green}"
148
+ parms.each do |parm|
149
+ puts " #{parm[:parameter_key].blue}: #{parm[:parameter_value].gray}"
150
+ end
151
+ end
152
+ if options.key?(:outputs) && outputs
153
+ puts " #{"Outputs:".magenta}"
154
+ outputs.each do |output|
155
+ puts " #{output[:output_key].brown}: #{output[:output_value].gray}"
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ exit 0
162
+ end
163
+
164
+ events_seen = []
165
+ loop do
166
+ # Does the stack exist?
167
+ unless cfn.list_stacks.to_h[:stack_summaries].map{|s| s[:stack_name]}.include? options[:stack]
168
+ puts "Stack '#{options[:stack]}' not found."
169
+ exit 1
170
+ end
171
+ # Get the events from the stack
172
+ stack_out = cfn.describe_stack_events({ stack_name: options[:stack] })
173
+ stack_out.to_h[:stack_events].reverse.each do |event|
174
+ unless events_seen.include? event[:event_id]
175
+ puts "#{event[:timestamp]} #{event[:resource_type]} #{event_color(event[:resource_status])} #{event[:resource_status_reason]}"
176
+ #puts "#{event[:resource_properties]}"
177
+ events_seen << event[:event_id]
178
+ end
179
+ end
180
+ break if isThisTheEnd? stack_out.to_h[:stack_events].first
181
+ sleep 2
182
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tailstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tony Fruzza
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: aws sdk based tool for watching CloudFormation stacks being created,
14
+ updated, or deleted.
15
+ email: anthony.fruzza@sturdynetworks.com
16
+ executables:
17
+ - tailstack
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/tailstack
22
+ homepage:
23
+ licenses: []
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.6.8
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: Tails the event output of AWS CloudFormation stacks
45
+ test_files: []