awshark 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +4 -0
- data/.rubocop.yml +130 -0
- data/CHANGELOG.md +4 -0
- data/README.md +62 -0
- data/awshark.gemspec +47 -0
- data/exe/awshark +7 -0
- data/gems.rb +6 -0
- data/lib/awshark.rb +35 -0
- data/lib/awshark/cli.rb +45 -0
- data/lib/awshark/cloud_formation/file_loading.rb +23 -0
- data/lib/awshark/cloud_formation/inferrer.rb +24 -0
- data/lib/awshark/cloud_formation/manager.rb +93 -0
- data/lib/awshark/cloud_formation/parameters.rb +43 -0
- data/lib/awshark/cloud_formation/stack.rb +94 -0
- data/lib/awshark/cloud_formation/stack_events.rb +46 -0
- data/lib/awshark/cloud_formation/template.rb +102 -0
- data/lib/awshark/configuration.rb +34 -0
- data/lib/awshark/ec2/instance.rb +46 -0
- data/lib/awshark/ec2/manager.rb +40 -0
- data/lib/awshark/profile_resolver.rb +54 -0
- data/lib/awshark/rds/check_reservations.rb +59 -0
- data/lib/awshark/rds/manager.rb +62 -0
- data/lib/awshark/s3/artifact.rb +38 -0
- data/lib/awshark/s3/bucket.rb +59 -0
- data/lib/awshark/s3/manager.rb +64 -0
- data/lib/awshark/subcommands/class_options.rb +28 -0
- data/lib/awshark/subcommands/cloud_formation.rb +81 -0
- data/lib/awshark/subcommands/ec2.rb +38 -0
- data/lib/awshark/subcommands/ecs.rb +38 -0
- data/lib/awshark/subcommands/rds.rb +88 -0
- data/lib/awshark/subcommands/s3.rb +93 -0
- data/lib/awshark/version.rb +5 -0
- metadata +277 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1893ca9f5ab0defd36515f70c621d987d2981c01b8c70bab0735ff422ec7c588
|
4
|
+
data.tar.gz: dd4c8992a1c8c5aec6e978f60e5d8f879f46e4013fe1fe5ea45e274d426f3b81
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31f09cd910a4b782c4ba1e142d89446fb92259eafbb51cbbdbbc2d0108aa9bce50bd24c9dd5f01740bc5f5ec560fc7703554df347b7b4279bce8a6a38c2ce666
|
7
|
+
data.tar.gz: fd69d7cd781331e6a25d2d1c5615b66bfae57796a8f16bd441888a348951a3e9cb157b5def2df3f4214517c7b5f71b85b2affcb76af78771b995843fbe360236
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# RuboCop will start looking for the configuration file in the directory
|
2
|
+
# where the inspected file is and continue its way up to the root directory.
|
3
|
+
#
|
4
|
+
# See https://docs.rubocop.org/rubocop/configuration
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
TargetRubyVersion: 2.6
|
8
|
+
Exclude:
|
9
|
+
- 'bin/*'
|
10
|
+
- 'node_modules/**/*'
|
11
|
+
- 'vendor/**/*'
|
12
|
+
- 'spec/**/*'
|
13
|
+
- 'tmp/*'
|
14
|
+
|
15
|
+
|
16
|
+
Layout/BeginEndAlignment:
|
17
|
+
Enabled: true
|
18
|
+
EnforcedStyleAlignWith: begin
|
19
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
20
|
+
Enabled: true
|
21
|
+
Layout/SpaceAroundMethodCallOperator:
|
22
|
+
Enabled: true
|
23
|
+
|
24
|
+
Lint/DeprecatedOpenSSLConstant:
|
25
|
+
Enabled: true
|
26
|
+
Lint/MixedRegexpCaptureTypes:
|
27
|
+
Enabled: true
|
28
|
+
Lint/RaiseException:
|
29
|
+
Enabled: true
|
30
|
+
Lint/StructNewOverride:
|
31
|
+
Enabled: true
|
32
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
33
|
+
Enabled: true
|
34
|
+
Lint/ConstantDefinitionInBlock:
|
35
|
+
Enabled: true
|
36
|
+
Lint/DuplicateElsifCondition:
|
37
|
+
Enabled: true
|
38
|
+
Lint/DuplicateRequire:
|
39
|
+
Enabled: true
|
40
|
+
Lint/DuplicateRescueException:
|
41
|
+
Enabled: true
|
42
|
+
Lint/EmptyConditionalBody:
|
43
|
+
Enabled: true
|
44
|
+
Lint/EmptyFile:
|
45
|
+
Enabled: true
|
46
|
+
Lint/FloatComparison:
|
47
|
+
Enabled: true
|
48
|
+
Lint/HashCompareByIdentity:
|
49
|
+
Enabled: true
|
50
|
+
Lint/IdentityComparison:
|
51
|
+
Enabled: true
|
52
|
+
Lint/MissingSuper:
|
53
|
+
Enabled: true
|
54
|
+
Lint/OutOfRangeRegexpRef:
|
55
|
+
Enabled: true
|
56
|
+
Lint/RedundantSafeNavigation:
|
57
|
+
Enabled: true
|
58
|
+
Lint/SelfAssignment:
|
59
|
+
Enabled: true
|
60
|
+
Lint/TopLevelReturnWithArgument:
|
61
|
+
Enabled: true
|
62
|
+
Lint/TrailingCommaInAttributeDeclaration:
|
63
|
+
Enabled: true
|
64
|
+
Lint/UnreachableLoop:
|
65
|
+
Enabled: true
|
66
|
+
Lint/UselessMethodDefinition:
|
67
|
+
Enabled: true
|
68
|
+
Lint/UselessTimes:
|
69
|
+
Enabled: true
|
70
|
+
|
71
|
+
Metrics/AbcSize:
|
72
|
+
Enabled: true
|
73
|
+
Max: 20
|
74
|
+
Metrics/MethodLength:
|
75
|
+
Enabled: false
|
76
|
+
Metrics/ModuleLength:
|
77
|
+
Enabled: false
|
78
|
+
|
79
|
+
Style/Documentation:
|
80
|
+
Enabled: false
|
81
|
+
Style/ExponentialNotation:
|
82
|
+
Enabled: true
|
83
|
+
Style/HashEachMethods:
|
84
|
+
Enabled: true
|
85
|
+
Style/HashTransformKeys:
|
86
|
+
Enabled: true
|
87
|
+
Style/HashTransformValues:
|
88
|
+
Enabled: true
|
89
|
+
Style/RedundantFetchBlock:
|
90
|
+
Enabled: true
|
91
|
+
Style/RedundantRegexpCharacterClass:
|
92
|
+
Enabled: true
|
93
|
+
Style/RedundantRegexpEscape:
|
94
|
+
Enabled: true
|
95
|
+
Style/SlicingWithRange:
|
96
|
+
Enabled: true
|
97
|
+
Style/AccessorGrouping:
|
98
|
+
Enabled: false
|
99
|
+
Style/BisectedAttrAccessor:
|
100
|
+
Enabled: true
|
101
|
+
Style/CaseLikeIf:
|
102
|
+
Enabled: true
|
103
|
+
Style/ClassEqualityComparison:
|
104
|
+
Enabled: true
|
105
|
+
Style/CombinableLoops:
|
106
|
+
Enabled: true
|
107
|
+
Style/ExplicitBlockArgument:
|
108
|
+
Enabled: true
|
109
|
+
Style/GlobalStdStream:
|
110
|
+
Enabled: true
|
111
|
+
Style/HashAsLastArrayItem:
|
112
|
+
Enabled: true
|
113
|
+
Style/HashLikeCase:
|
114
|
+
Enabled: true
|
115
|
+
Style/KeywordParametersOrder:
|
116
|
+
Enabled: true
|
117
|
+
Style/OptionalBooleanParameter:
|
118
|
+
Enabled: true
|
119
|
+
Style/RedundantAssignment:
|
120
|
+
Enabled: true
|
121
|
+
Style/RedundantFileExtensionInRequire:
|
122
|
+
Enabled: true
|
123
|
+
Style/RedundantSelfAssignment:
|
124
|
+
Enabled: true
|
125
|
+
Style/SingleArgumentDig:
|
126
|
+
Enabled: true
|
127
|
+
Style/SoleNestedConditional:
|
128
|
+
Enabled: true
|
129
|
+
Style/StringConcatenation:
|
130
|
+
Enabled: true
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Awshark
|
2
|
+
|
3
|
+
[](https://github.com/jdahlke/awshark/actions)
|
4
|
+
|
5
|
+
Simple command-line tool for some useful tasks for AWS *EC2*, *S3* and *CloudFormation*.
|
6
|
+
|
7
|
+
|
8
|
+
### Installation
|
9
|
+
|
10
|
+
```
|
11
|
+
gem install awshark
|
12
|
+
```
|
13
|
+
|
14
|
+
|
15
|
+
### Usage
|
16
|
+
|
17
|
+
#### S3 commands
|
18
|
+
|
19
|
+
List all S3 buckets
|
20
|
+
```
|
21
|
+
awshark s3 list --profile=AWS_PROFILE
|
22
|
+
```
|
23
|
+
|
24
|
+
List all objects in a specific S3 bucket
|
25
|
+
```
|
26
|
+
awshark s3 objects BUCKET_NAME fonts/ --profile=AWS_PROFILE
|
27
|
+
```
|
28
|
+
|
29
|
+
#### EC2 commands
|
30
|
+
|
31
|
+
List all EC2 instances in a region
|
32
|
+
```
|
33
|
+
awshark ec2 list --profile=AWS_PROFILE
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Cloud Formation commands
|
37
|
+
|
38
|
+
Update (diff) Cloud Formation stack
|
39
|
+
```
|
40
|
+
awshark cf deploy TEMPLATE_PATH --stage=STAGE --bucket=S3_BUCKET.bundesimmo.de --profile=AWS_PROFILE
|
41
|
+
|
42
|
+
awshark cf diff TEMPLATE_PATH --stage=STAGE --bucket=S3_BUCKET.bundesimmo.de --profile=AWS_PROFILE
|
43
|
+
```
|
44
|
+
|
45
|
+
For a further information visit the [Wiki](https://github.com/jdahlke/awshark/wiki).
|
46
|
+
|
47
|
+
|
48
|
+
### Development
|
49
|
+
|
50
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
51
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
52
|
+
|
53
|
+
To install this gem onto your local machine, run
|
54
|
+
|
55
|
+
gem build awshark.gemspec
|
56
|
+
gem install --local awshark-0.1.0.gem
|
57
|
+
rm awshark-0.1.0.gem
|
58
|
+
|
59
|
+
|
60
|
+
### Contributing
|
61
|
+
|
62
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jdahlke/awshark.
|
data/awshark.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'awshark/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'awshark'
|
9
|
+
spec.version = Awshark::VERSION
|
10
|
+
spec.authors = ['Joergen Dahlke']
|
11
|
+
spec.email = ['joergen.dahlke@infopark.de']
|
12
|
+
|
13
|
+
spec.summary = 'Custom CLI for for AWS related tasks'
|
14
|
+
spec.description = 'Custom CLI for for AWS to simplify common tasks with EC2, S3 and Cloud Formation'
|
15
|
+
spec.homepage = 'https://github.com/jdahlke/awshark'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/jdahlke/awshark'
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/jdahlke/awshark/blob/develop/CHANGELOG.md'
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|spec)/}) }
|
26
|
+
end
|
27
|
+
spec.bindir = 'exe'
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ['lib']
|
30
|
+
spec.required_ruby_version = '>= 2.6'
|
31
|
+
|
32
|
+
spec.add_dependency 'activesupport'
|
33
|
+
spec.add_dependency 'aws-sdk-cloudformation'
|
34
|
+
spec.add_dependency 'aws-sdk-cloudwatch'
|
35
|
+
spec.add_dependency 'aws-sdk-ec2'
|
36
|
+
spec.add_dependency 'aws-sdk-ecr'
|
37
|
+
spec.add_dependency 'aws-sdk-rds'
|
38
|
+
spec.add_dependency 'aws-sdk-s3'
|
39
|
+
spec.add_dependency 'diffy'
|
40
|
+
spec.add_dependency 'mini_mime'
|
41
|
+
spec.add_dependency 'recursive-open-struct'
|
42
|
+
spec.add_dependency 'thor', '~> 1.0'
|
43
|
+
|
44
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
45
|
+
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
46
|
+
spec.add_development_dependency 'rubocop', '0.93.1'
|
47
|
+
end
|
data/exe/awshark
ADDED
data/gems.rb
ADDED
data/lib/awshark.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'logger'
|
5
|
+
require 'thor'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require 'awshark/version'
|
9
|
+
require 'awshark/configuration'
|
10
|
+
|
11
|
+
module Awshark
|
12
|
+
class GracefulFail < StandardError; end
|
13
|
+
|
14
|
+
def self.config
|
15
|
+
@config ||= Configuration.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configure
|
19
|
+
yield config
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.logger
|
23
|
+
return @logger if @logger
|
24
|
+
|
25
|
+
@logger = ::Logger.new($stdout)
|
26
|
+
@logger.level = Logger::INFO
|
27
|
+
@logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
28
|
+
"[awshark] #{msg}\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
@logger
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'awshark/cli'
|
data/lib/awshark/cli.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'awshark/profile_resolver'
|
4
|
+
|
5
|
+
require 'awshark/subcommands/class_options'
|
6
|
+
require 'awshark/subcommands/cloud_formation'
|
7
|
+
require 'awshark/subcommands/ec2'
|
8
|
+
require 'awshark/subcommands/ecs'
|
9
|
+
require 'awshark/subcommands/rds'
|
10
|
+
require 'awshark/subcommands/s3'
|
11
|
+
|
12
|
+
module Awshark
|
13
|
+
class Cli < Thor
|
14
|
+
package_name 'Awshark'
|
15
|
+
|
16
|
+
map '-v' => :version
|
17
|
+
|
18
|
+
class_option :help, type: :boolean, desc: 'Prints this help'
|
19
|
+
class_option :profile, type: :string, desc: 'Load the AWS credentials profile named PROFILE.'
|
20
|
+
class_option :region, type: :string, desc: 'Sets the AWS region name REGION.'
|
21
|
+
|
22
|
+
desc 'cf COMMAND', 'Run CloudFormation command'
|
23
|
+
subcommand 'cf', Awshark::Subcommands::CloudFormation
|
24
|
+
|
25
|
+
desc 'ec2 COMMAND', 'Run EC2 command'
|
26
|
+
subcommand 'ec2', Awshark::Subcommands::EC2
|
27
|
+
|
28
|
+
desc 'ecs COMMAND', 'Run ECS command'
|
29
|
+
subcommand 'ecs', Awshark::Subcommands::Ecs
|
30
|
+
|
31
|
+
desc 'rds COMMAND', 'Run RDS command'
|
32
|
+
subcommand 'rds', Awshark::Subcommands::Rds
|
33
|
+
|
34
|
+
desc 's3 COMMAND', 'Run CloudFormation command'
|
35
|
+
subcommand 's3', Awshark::Subcommands::S3
|
36
|
+
|
37
|
+
desc 'version', 'Displays current version of AwsShark'
|
38
|
+
long_desc <<-LONGDESC
|
39
|
+
Displays current version of AwsShark.
|
40
|
+
LONGDESC
|
41
|
+
def version
|
42
|
+
puts "AwShark version: #{Awshark::VERSION}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Awshark
|
4
|
+
module CloudFormation
|
5
|
+
module FileLoading
|
6
|
+
def load_file(filepath, context = nil)
|
7
|
+
return nil if filepath.blank?
|
8
|
+
|
9
|
+
content = File.read(filepath)
|
10
|
+
content = ERB.new(content).result_with_hash(context) if context.present?
|
11
|
+
|
12
|
+
case File.extname(filepath)
|
13
|
+
when '.json'
|
14
|
+
JSON.parse(content)
|
15
|
+
when '.yml', '.yaml'
|
16
|
+
YAML.safe_load(content, permitted_classes: [Date, Time], aliases: true)
|
17
|
+
else
|
18
|
+
raise ArgumentError, "Unsupported file extension for #{filepath}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/CloudFormation/Client.html
|
5
|
+
#
|
6
|
+
module Awshark
|
7
|
+
module CloudFormation
|
8
|
+
class Inferrer
|
9
|
+
attr_reader :path, :stage
|
10
|
+
|
11
|
+
def initialize(path, stage = nil)
|
12
|
+
@path = path
|
13
|
+
@stage = stage
|
14
|
+
end
|
15
|
+
|
16
|
+
def stack_name
|
17
|
+
file_extension = File.extname(path)
|
18
|
+
name = File.basename(path, file_extension)
|
19
|
+
|
20
|
+
[name, stage].compact.join('-').gsub('_', '-')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/CloudFormation/Client.html
|
5
|
+
#
|
6
|
+
module Awshark
|
7
|
+
module CloudFormation
|
8
|
+
class Manager
|
9
|
+
attr_reader :path, :options
|
10
|
+
attr_reader :stack, :stage, :capabilities
|
11
|
+
|
12
|
+
def initialize(path, options = {})
|
13
|
+
@path = path
|
14
|
+
@options = options
|
15
|
+
@stage = options[:stage]
|
16
|
+
|
17
|
+
@capabilities = if options[:iam]
|
18
|
+
%w[CAPABILITY_IAM CAPABILITY_NAMED_IAM]
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
|
23
|
+
@stack = Stack.new(name: inferrer.stack_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def diff_stack_template
|
27
|
+
new_template = template.body
|
28
|
+
old_template = stack.template
|
29
|
+
options = { context: 2 }
|
30
|
+
|
31
|
+
diff = Diffy::Diff.new(old_template, new_template, options)
|
32
|
+
diff.to_s(:color)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_stack
|
36
|
+
stack.create_or_update(
|
37
|
+
capabilities: capabilities,
|
38
|
+
stack_name: stack.name,
|
39
|
+
template_url: template.url,
|
40
|
+
parameters: parameters.stack_parameters
|
41
|
+
)
|
42
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
43
|
+
raise GracefulFail, e.message if e.message.match(/No updates are to be performed/)
|
44
|
+
raise GracefulFail, e.message if e.message.match(/ROLLBACK_COMPLETE state and can not be updated/)
|
45
|
+
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
|
49
|
+
def tail_stack_events
|
50
|
+
stack.reload
|
51
|
+
stack_events = StackEvents.new(stack)
|
52
|
+
|
53
|
+
loop do
|
54
|
+
events = stack_events.new_events
|
55
|
+
print_stack_events(events)
|
56
|
+
|
57
|
+
break if stack_events.done?
|
58
|
+
|
59
|
+
sleep(event_polling)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def event_polling
|
66
|
+
Awshark.config.cloud_formation.event_polling || 3
|
67
|
+
end
|
68
|
+
|
69
|
+
def inferrer
|
70
|
+
@inferrer ||= Inferrer.new(path, stage)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parameters
|
74
|
+
@parameters ||= Parameters.new(path: path, stage: stage)
|
75
|
+
end
|
76
|
+
|
77
|
+
def template
|
78
|
+
@template ||= Template.new(path, options.merge(name: stack.name))
|
79
|
+
end
|
80
|
+
|
81
|
+
def print_stack_events(events)
|
82
|
+
$stdout.sync
|
83
|
+
events.each do |event|
|
84
|
+
printf "%-50<type>s %-30<logical_id>s %-20<status>s %<reason>s\n",
|
85
|
+
type: event.resource_type,
|
86
|
+
logical_id: event.logical_resource_id,
|
87
|
+
status: event.resource_status,
|
88
|
+
reason: event.resource_status_reason
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|