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 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
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ gems.locked
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --require spec_helper
3
+ --format progress
4
+ --profile
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
@@ -0,0 +1,4 @@
1
+ ## Changelog
2
+
3
+ #### 1.0.0
4
+ - initial version
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Awshark
2
+
3
+ [![GitHub Actions Test Status](https://github.com/jdahlke/awshark/workflows/Tests/badge.svg?branch=develop)](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
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'awshark'
6
+
7
+ Awshark::Cli.start(ARGV)
data/gems.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in awshark.gemspec
6
+ gemspec
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'
@@ -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