cyclone_lariat 0.3.10 → 0.4.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 +4 -4
- data/.gitignore +6 -0
- data/.rubocop.yml +26 -1
- data/CHANGELOG.md +11 -1
- data/Gemfile.lock +26 -21
- data/README.md +466 -91
- data/Rakefile +2 -5
- data/bin/cyclone_lariat +174 -0
- data/config/initializers/sequel.rb +7 -0
- data/cyclone_lariat.gemspec +4 -0
- data/db/migrate/03_add_versions.rb +9 -0
- data/docs/_imgs/graphviz_01.png +0 -0
- data/docs/_imgs/graphviz_02.png +0 -0
- data/docs/_imgs/graphviz_03.png +0 -0
- data/docs/_imgs/logic.png +0 -0
- data/docs/_imgs/sqs_sns_diagram.png +0 -0
- data/lib/cyclone_lariat/abstract/client.rb +20 -14
- data/lib/cyclone_lariat/abstract/message.rb +20 -5
- data/lib/cyclone_lariat/configure.rb +1 -1
- data/lib/cyclone_lariat/errors.rb +22 -0
- data/lib/cyclone_lariat/middleware.rb +2 -1
- data/lib/cyclone_lariat/migration.rb +214 -0
- data/lib/cyclone_lariat/queue.rb +147 -0
- data/lib/cyclone_lariat/sns_client.rb +125 -14
- data/lib/cyclone_lariat/sqs_client.rb +69 -15
- data/lib/cyclone_lariat/topic.rb +113 -0
- data/lib/cyclone_lariat/version.rb +1 -1
- data/lib/cyclone_lariat.rb +1 -0
- data/lib/tasks/console.rake +13 -0
- data/lib/tasks/cyclone_lariat.rake +44 -0
- data/lib/tasks/db.rake +1 -1
- metadata +45 -4
- data/docs/_imgs/diagram.png +0 -0
data/bin/cyclone_lariat
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative '../lib/cyclone_lariat'
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'dry/cli'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
module CycloneLariat
|
10
|
+
module CLI
|
11
|
+
module Commands
|
12
|
+
extend Dry::CLI::Registry
|
13
|
+
|
14
|
+
INITIALIZERS_DIR = './config/initializers'
|
15
|
+
RAKE_TASKS_DIR = './lib/tasks'
|
16
|
+
|
17
|
+
class Version < Dry::CLI::Command
|
18
|
+
desc 'Print version'
|
19
|
+
|
20
|
+
def call(*)
|
21
|
+
puts CycloneLariat::VERSION
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Install < Dry::CLI::Command
|
26
|
+
desc 'Install cyclone lariat to current directory'
|
27
|
+
|
28
|
+
def call(*)
|
29
|
+
create_config
|
30
|
+
create_rake_task
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_config
|
34
|
+
FileUtils.mkdir_p RAKE_TASKS_DIR unless Dir.exist? RAKE_TASKS_DIR
|
35
|
+
config_path = "#{RAKE_TASKS_DIR}/cyclone_lariat.rake"
|
36
|
+
config_file = File.open(config_path, 'w')
|
37
|
+
config_file.puts rake_task_context
|
38
|
+
puts "Created rake task: #{config_path}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_rake_task
|
42
|
+
FileUtils.mkdir_p INITIALIZERS_DIR unless Dir.exist? INITIALIZERS_DIR
|
43
|
+
config_path = "#{INITIALIZERS_DIR}/cyclone_lariat.rb"
|
44
|
+
config_file = File.open(config_path, 'w')
|
45
|
+
config_file.puts config_contents
|
46
|
+
puts "Created config: #{config_path}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def config_contents
|
50
|
+
<<~CONFIG
|
51
|
+
# frozen_string_literal: true
|
52
|
+
|
53
|
+
CycloneLariat.tap do |cl|
|
54
|
+
cl.default_version = 1 # api version
|
55
|
+
cl.aws_key = ENV['AWS_KEY'] # aws key
|
56
|
+
cl.aws_account_id = ENV['AWS_ACCOUNT_ID'] # aws account id
|
57
|
+
cl.aws_secret_key = ENV['AWS_SECRET_KEY'] # aws secret
|
58
|
+
cl.aws_default_region = ENV['AWS_REGION'] # aws default region
|
59
|
+
cl.publisher = ENV['APP_NAME'] # name of your publishers, usually name of your application
|
60
|
+
cl.default_instance = ENV['INSTANCE'] # stage, production, test
|
61
|
+
cl.events_dataset = DB[:events] # sequel dataset for store income messages, for receiver
|
62
|
+
cl.versions_dataset = DB[:lariat_versions] # sequel dataset for migrations, for publisher
|
63
|
+
end
|
64
|
+
CONFIG
|
65
|
+
end
|
66
|
+
|
67
|
+
def rake_task_context
|
68
|
+
<<~TASKS
|
69
|
+
# frozen_string_literal: true
|
70
|
+
|
71
|
+
require 'cyclone_lariat'
|
72
|
+
|
73
|
+
namespace :cyclone_lariat do
|
74
|
+
desc 'Migrate topics for SQS/SNS'
|
75
|
+
task migrate: :config do
|
76
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
77
|
+
CycloneLariat::Migration.migrate
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'Rollback topics for SQS/SNS'
|
81
|
+
task :rollback, [:version] => :config do |_, args|
|
82
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
83
|
+
target_version = args[:version] ? args[:version].to_i : nil
|
84
|
+
CycloneLariat::Migration.rollback(target_version)
|
85
|
+
end
|
86
|
+
|
87
|
+
namespace :list do
|
88
|
+
desc 'List all topics'
|
89
|
+
task :topics do
|
90
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
91
|
+
CycloneLariat::Migration.list_topics
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'List all queues'
|
95
|
+
task :queues do
|
96
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
97
|
+
CycloneLariat::Migration.list_queues
|
98
|
+
end
|
99
|
+
|
100
|
+
desc 'List all subscriptions'
|
101
|
+
task :subscriptions do
|
102
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
103
|
+
CycloneLariat::Migration.list_subscriptions
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
desc 'Build graphviz graph for whole system'
|
108
|
+
task :graph do
|
109
|
+
require_relative '../../config/initializers/cyclone_lariat'
|
110
|
+
CycloneLariat::Migration.build_graph
|
111
|
+
end
|
112
|
+
end
|
113
|
+
TASKS
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
module Generate
|
118
|
+
class Migration < Dry::CLI::Command
|
119
|
+
desc 'Generate migration'
|
120
|
+
|
121
|
+
argument :title, type: :string, required: true, desc: 'Title of migration use only a-z and _'
|
122
|
+
|
123
|
+
def call(title:, **)
|
124
|
+
abort('Use only a-z and _ in your title') unless title_correct? title
|
125
|
+
|
126
|
+
FileUtils.mkdir_p CycloneLariat::Migration::DIR unless Dir.exist? CycloneLariat::Migration::DIR
|
127
|
+
|
128
|
+
file_name = generate_filename title
|
129
|
+
class_name = generate_class_name title
|
130
|
+
file = File.open(file_name, 'w')
|
131
|
+
file.puts file_contents(class_name)
|
132
|
+
puts "Migration successful created:\n\t#{file_name}"
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def title_correct?(title)
|
138
|
+
/^(?!.*__.*)[a-z]?[a-z_]+[a-z]+$/.match? title
|
139
|
+
end
|
140
|
+
|
141
|
+
def generate_filename(title)
|
142
|
+
"#{CycloneLariat::Migration::DIR}/#{Time.now.to_i}_#{title}.rb"
|
143
|
+
end
|
144
|
+
|
145
|
+
def generate_class_name(title)
|
146
|
+
title.split('_').collect(&:capitalize).join
|
147
|
+
end
|
148
|
+
|
149
|
+
def file_contents(klass_name)
|
150
|
+
<<~MIGRATION
|
151
|
+
# frozen_string_literal: true
|
152
|
+
|
153
|
+
class #{klass_name} < CycloneLariat::Migration
|
154
|
+
def up
|
155
|
+
end
|
156
|
+
|
157
|
+
def down
|
158
|
+
end
|
159
|
+
end
|
160
|
+
MIGRATION
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
register 'version', Version, aliases: %w[v -v --version]
|
166
|
+
register 'install', Install
|
167
|
+
register 'generate', aliases: %w[g] do |prefix|
|
168
|
+
prefix.register 'migration', Generate::Migration
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
Dry::CLI.new(CycloneLariat::CLI::Commands).call
|
data/cyclone_lariat.gemspec
CHANGED
@@ -30,11 +30,15 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
31
31
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
32
|
end
|
33
|
+
|
33
34
|
spec.require_paths = ['lib']
|
35
|
+
spec.executables = ['cyclone_lariat']
|
34
36
|
|
35
37
|
spec.add_dependency 'aws-sdk-sns'
|
36
38
|
spec.add_dependency 'aws-sdk-sqs'
|
39
|
+
spec.add_dependency 'dry-cli', '~> 0.6'
|
37
40
|
spec.add_dependency 'luna_park', '~> 0.11'
|
41
|
+
spec.add_dependency 'terminal-table', '~> 3.0'
|
38
42
|
|
39
43
|
spec.add_development_dependency 'bundler', '~> 1.17'
|
40
44
|
spec.add_development_dependency 'byebug', '~> 11.1'
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -14,36 +14,42 @@ module CycloneLariat
|
|
14
14
|
dependency(:aws_client_class) { raise ArgumentError, 'Client class should be defined' }
|
15
15
|
dependency(:aws_credentials_class) { Aws::Credentials }
|
16
16
|
|
17
|
-
def initialize(key: nil, secret_key: nil, region: nil, version: nil, publisher: nil, instance: nil,
|
17
|
+
def initialize(key: nil, secret_key: nil, region: nil, version: nil, publisher: nil, instance: nil, account_id: nil)
|
18
18
|
@key = key
|
19
19
|
@secret_key = secret_key
|
20
20
|
@region = region
|
21
21
|
@version = version
|
22
22
|
@publisher = publisher
|
23
23
|
@instance = instance
|
24
|
-
@
|
24
|
+
@account_id = account_id
|
25
25
|
end
|
26
26
|
|
27
|
-
def event(type, data: {}, version: self.version, uuid: SecureRandom.uuid)
|
28
|
-
|
27
|
+
def event(type, data: {}, version: self.version, request_id: nil, uuid: SecureRandom.uuid)
|
28
|
+
params = {
|
29
29
|
uuid: uuid,
|
30
30
|
type: type,
|
31
|
-
sent_at: Time.now.iso8601,
|
31
|
+
sent_at: Time.now.iso8601(3),
|
32
32
|
version: version,
|
33
33
|
publisher: publisher,
|
34
|
-
data: data
|
35
|
-
|
34
|
+
data: data,
|
35
|
+
request_id: request_id
|
36
|
+
}
|
37
|
+
|
38
|
+
Event.wrap(params.compact)
|
36
39
|
end
|
37
40
|
|
38
|
-
def command(type, data: {}, version: self.version, uuid: SecureRandom.uuid)
|
39
|
-
|
41
|
+
def command(type, data: {}, version: self.version, request_id: nil, uuid: SecureRandom.uuid)
|
42
|
+
params = {
|
40
43
|
uuid: uuid,
|
41
44
|
type: type,
|
42
|
-
sent_at: Time.now.iso8601,
|
45
|
+
sent_at: Time.now.iso8601(3),
|
43
46
|
version: version,
|
44
47
|
publisher: publisher,
|
45
|
-
data: data
|
46
|
-
|
48
|
+
data: data,
|
49
|
+
request_id: request_id
|
50
|
+
}
|
51
|
+
|
52
|
+
Command.wrap(params.compact)
|
47
53
|
end
|
48
54
|
|
49
55
|
def publish
|
@@ -88,8 +94,8 @@ module CycloneLariat
|
|
88
94
|
@region ||= CycloneLariat.aws_default_region
|
89
95
|
end
|
90
96
|
|
91
|
-
def
|
92
|
-
@
|
97
|
+
def account_id
|
98
|
+
@account_id ||= CycloneLariat.aws_account_id
|
93
99
|
end
|
94
100
|
|
95
101
|
private
|
@@ -6,10 +6,10 @@ require_relative '../errors'
|
|
6
6
|
module CycloneLariat
|
7
7
|
module Abstract
|
8
8
|
class Message < LunaPark::Entities::Attributable
|
9
|
-
attr :uuid,
|
10
|
-
attr :publisher,
|
11
|
-
attr :type,
|
12
|
-
attrs :client_error, :version, :data,
|
9
|
+
attr :uuid, String, :new
|
10
|
+
attr :publisher, String, :new
|
11
|
+
attr :type, String, :new
|
12
|
+
attrs :client_error, :version, :data, :request_id,
|
13
13
|
:sent_at, :processed_at, :received_at
|
14
14
|
|
15
15
|
def kind
|
@@ -32,6 +32,10 @@ module CycloneLariat
|
|
32
32
|
@processed_at = wrap_time(value)
|
33
33
|
end
|
34
34
|
|
35
|
+
def request_at=(value)
|
36
|
+
@request_id = wrap_string(value)
|
37
|
+
end
|
38
|
+
|
35
39
|
def processed?
|
36
40
|
!@processed_at.nil?
|
37
41
|
end
|
@@ -64,7 +68,10 @@ module CycloneLariat
|
|
64
68
|
|
65
69
|
def to_json(*args)
|
66
70
|
hash = serialize
|
67
|
-
hash[:type]
|
71
|
+
hash[:type] = [kind, hash[:type]].join '_'
|
72
|
+
hash[:sent_at] = hash[:sent_at].iso8601(3) if hash[:sent_at]
|
73
|
+
hash[:received_at] = hash[:received_at].iso8601(3) if hash[:received_at]
|
74
|
+
hash[:processed_at] = hash[:processed_at].iso8601(3) if hash[:processed_at]
|
68
75
|
hash.to_json(*args)
|
69
76
|
end
|
70
77
|
|
@@ -78,6 +85,14 @@ module CycloneLariat
|
|
78
85
|
else raise ArgumentError, "Unknown type `#{value.class}`"
|
79
86
|
end
|
80
87
|
end
|
88
|
+
|
89
|
+
def wrap_string(value)
|
90
|
+
case value
|
91
|
+
when String then String(value)
|
92
|
+
when NilClass then nil
|
93
|
+
else raise ArgumentError, "Unknown type `#{value.class}`"
|
94
|
+
end
|
95
|
+
end
|
81
96
|
end
|
82
97
|
end
|
83
98
|
end
|
@@ -5,7 +5,7 @@ module CycloneLariat
|
|
5
5
|
DEFAULT_VERSION = 1
|
6
6
|
|
7
7
|
attr_accessor :aws_key, :aws_secret_key, :publisher, :aws_default_region, :default_instance,
|
8
|
-
:
|
8
|
+
:aws_account_id, :events_dataset, :versions_dataset
|
9
9
|
attr_writer :default_version
|
10
10
|
|
11
11
|
def default_version
|
@@ -18,5 +18,27 @@ module CycloneLariat
|
|
18
18
|
other.details == details
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
class TopicAlreadyExists < LunaPark::Errors::System
|
23
|
+
message { |d| "Topic already exists: `#{d[:expected_topic]}`" }
|
24
|
+
end
|
25
|
+
|
26
|
+
class TopicDoesNotExists < LunaPark::Errors::System
|
27
|
+
message { |d| "Topic does not exists: `#{d[:expected_topic]}`" }
|
28
|
+
end
|
29
|
+
|
30
|
+
class QueueAlreadyExists < LunaPark::Errors::System
|
31
|
+
message { |d| "Queue already exists: `#{d[:expected_queue]}`" }
|
32
|
+
end
|
33
|
+
|
34
|
+
class QueueDoesNotExists < LunaPark::Errors::System
|
35
|
+
message { |d| "Queue does not exists: `#{d[:expected_queue]}`" }
|
36
|
+
end
|
37
|
+
class SubscriptionAlreadyExists < LunaPark::Errors::System
|
38
|
+
message { |d| "Subscription for topic `#{d[:topic].name}`, on endpoint `#{d[:endpoint].name}` already exists" }
|
39
|
+
end
|
40
|
+
class SubscriptionDoesNotExists < LunaPark::Errors::System
|
41
|
+
message { |d| "Subscription for topic `#{d[:topic].name}`, on endpoint `#{d[:endpoint].name}` does not exists" }
|
42
|
+
end
|
21
43
|
end
|
22
44
|
end
|
@@ -7,7 +7,8 @@ require 'json'
|
|
7
7
|
module CycloneLariat
|
8
8
|
class Middleware
|
9
9
|
def initialize(dataset: nil, errors_notifier: nil, message_notifier: nil, repo: MessagesRepo)
|
10
|
-
|
10
|
+
events_dataset = dataset || CycloneLariat.events_dataset
|
11
|
+
@events_repo = repo.new(events_dataset) if events_dataset
|
11
12
|
@message_notifier = message_notifier
|
12
13
|
@errors_notifier = errors_notifier
|
13
14
|
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'forwardable'
|
5
|
+
require_relative 'sns_client'
|
6
|
+
require_relative 'sqs_client'
|
7
|
+
require 'luna_park/errors'
|
8
|
+
require 'terminal-table'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
module CycloneLariat
|
12
|
+
class Migration
|
13
|
+
extend Forwardable
|
14
|
+
include LunaPark::Extensions::Injector
|
15
|
+
|
16
|
+
dependency(:sns) { CycloneLariat::SnsClient.new }
|
17
|
+
dependency(:sqs) { CycloneLariat::SqsClient.new }
|
18
|
+
|
19
|
+
DIR = './lariat/migrate'
|
20
|
+
|
21
|
+
def up
|
22
|
+
raise LunaPark::Errors::Abstract, "Up method should be defined in #{self.class.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def down
|
26
|
+
raise LunaPark::Errors::Abstract, "Down method should be defined in #{self.class.name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def_delegators :sqs, :queue, :custom_queue
|
30
|
+
def_delegators :sns, :topic, :custom_topic
|
31
|
+
|
32
|
+
def create(resource)
|
33
|
+
process(
|
34
|
+
resource: resource,
|
35
|
+
for_topic: ->(topic) { sns.create(topic) },
|
36
|
+
for_queue: ->(queue) { sqs.create(queue) }
|
37
|
+
)
|
38
|
+
|
39
|
+
puts " #{resource.class.name.split('::').last} was created `#{resource.name}`"
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete(resource)
|
43
|
+
process(
|
44
|
+
resource: resource,
|
45
|
+
for_topic: ->(topic) { sns.delete(topic) },
|
46
|
+
for_queue: ->(queue) { sqs.delete(queue) }
|
47
|
+
)
|
48
|
+
puts " #{resource.class.name.split('::').last} was deleted `#{resource.name}`"
|
49
|
+
end
|
50
|
+
|
51
|
+
def exists?(resource)
|
52
|
+
process(
|
53
|
+
resource: resource,
|
54
|
+
for_topic: ->(topic) { sns.exists?(topic) },
|
55
|
+
for_queue: ->(queue) { sqs.exists?(queue) }
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def subscribe(topic:, endpoint:)
|
60
|
+
sns.subscribe topic: topic, endpoint: endpoint
|
61
|
+
puts " Subscription was created `#{topic.name} -> #{endpoint.name}`"
|
62
|
+
end
|
63
|
+
|
64
|
+
def unsubscribe(topic:, endpoint:)
|
65
|
+
sns.unsubscribe topic: topic, endpoint: endpoint
|
66
|
+
puts " Subscription was deleted `#{topic.name} -> #{endpoint.name}`"
|
67
|
+
end
|
68
|
+
|
69
|
+
def topics
|
70
|
+
sns.list_all
|
71
|
+
end
|
72
|
+
|
73
|
+
def queues
|
74
|
+
sqs.list_all
|
75
|
+
end
|
76
|
+
|
77
|
+
def subscriptions
|
78
|
+
sns.list_subscriptions
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def process(resource:, for_topic:, for_queue:)
|
84
|
+
case resource
|
85
|
+
when Topic then for_topic.call(resource)
|
86
|
+
when Queue then for_queue.call(resource)
|
87
|
+
else
|
88
|
+
raise ArgumentError, "Unknown resource class #{resource.class}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class << self
|
93
|
+
def migrate(dataset: CycloneLariat.versions_dataset, dir: DIR)
|
94
|
+
alert('No one migration exists') if !Dir.exist?(dir) || Dir.empty?(dir)
|
95
|
+
|
96
|
+
Dir.glob("#{dir}/*.rb") do |path|
|
97
|
+
filename = File.basename(path, '.rb')
|
98
|
+
version, title = filename.split('_', 2)
|
99
|
+
|
100
|
+
existed_migrations = dataset.all.map { |row| row[:version] }
|
101
|
+
unless existed_migrations.include? version.to_i
|
102
|
+
class_name = title.split('_').collect(&:capitalize).join
|
103
|
+
puts "Up - #{version} #{class_name} #{path}"
|
104
|
+
require_relative Pathname.new(Dir.pwd) + Pathname.new(path)
|
105
|
+
Object.const_get(class_name).new.up
|
106
|
+
dataset.insert(version: version)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def rollback(version = nil, dataset: CycloneLariat.versions_dataset, dir: DIR)
|
112
|
+
existed_migrations = dataset.all.map { |row| row[:version] }.sort
|
113
|
+
version ||= existed_migrations[-1]
|
114
|
+
migrations_to_downgrade = existed_migrations.select { |migration| migration >= version }
|
115
|
+
|
116
|
+
paths = []
|
117
|
+
migrations_to_downgrade.each do |migration|
|
118
|
+
path = Pathname.new(Dir.pwd) + Pathname.new(dir)
|
119
|
+
founded = Dir.glob("#{path}/#{migration}_*.rb")
|
120
|
+
raise "Could not found migration: `#{migration}` in #{path}" if founded.empty?
|
121
|
+
raise "Found lot of migration: `#{migration}` in #{path}" if founded.size > 1
|
122
|
+
|
123
|
+
paths += founded
|
124
|
+
end
|
125
|
+
|
126
|
+
paths.each do |path|
|
127
|
+
filename = File.basename(path, '.rb')
|
128
|
+
version, title = filename.split('_', 2)
|
129
|
+
class_name = title.split('_').collect(&:capitalize).join
|
130
|
+
puts "Down - #{version} #{class_name} #{path}"
|
131
|
+
require_relative Pathname.new(Dir.pwd) + Pathname.new(path)
|
132
|
+
Object.const_get(class_name).new.down
|
133
|
+
dataset.filter(version: version).delete
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def list_topics
|
138
|
+
rows = []
|
139
|
+
new.topics.each do |topic|
|
140
|
+
rows << [
|
141
|
+
topic.custom? ? 'custom' : 'standard',
|
142
|
+
topic.region,
|
143
|
+
topic.account_id,
|
144
|
+
topic.name,
|
145
|
+
topic.instance,
|
146
|
+
topic.kind,
|
147
|
+
topic.publisher,
|
148
|
+
topic.type,
|
149
|
+
topic.fifo
|
150
|
+
]
|
151
|
+
end
|
152
|
+
|
153
|
+
puts Terminal::Table.new rows: rows, headings: %w[valid region account_id name instance kind publisher type fifo]
|
154
|
+
end
|
155
|
+
|
156
|
+
def list_queues
|
157
|
+
rows = []
|
158
|
+
new.queues.each do |queue|
|
159
|
+
rows << [
|
160
|
+
queue.custom? ? 'custom' : 'standard',
|
161
|
+
queue.region,
|
162
|
+
queue.account_id,
|
163
|
+
queue.name,
|
164
|
+
queue.instance,
|
165
|
+
queue.kind,
|
166
|
+
queue.publisher,
|
167
|
+
queue.type,
|
168
|
+
queue.dest,
|
169
|
+
queue.fifo
|
170
|
+
]
|
171
|
+
end
|
172
|
+
|
173
|
+
puts Terminal::Table.new rows: rows, headings: %w[valid region account_id name instance kind publisher type destination fifo]
|
174
|
+
end
|
175
|
+
|
176
|
+
def list_subscriptions
|
177
|
+
rows = []
|
178
|
+
new.subscriptions.each do |subscription|
|
179
|
+
rows << [
|
180
|
+
subscription[:topic].name,
|
181
|
+
subscription[:endpoint].name,
|
182
|
+
subscription[:arn]
|
183
|
+
]
|
184
|
+
end
|
185
|
+
|
186
|
+
puts Terminal::Table.new rows: rows, headings: %w[topic endpoint subscription_arn]
|
187
|
+
end
|
188
|
+
|
189
|
+
def build_graph
|
190
|
+
subscriptions = new.subscriptions
|
191
|
+
resources_set = Set.new
|
192
|
+
|
193
|
+
subscriptions.each do |subscription|
|
194
|
+
resources_set << subscription[:topic]
|
195
|
+
resources_set << subscription[:endpoint]
|
196
|
+
end
|
197
|
+
|
198
|
+
puts 'digraph G {'
|
199
|
+
puts ' rankdir=LR;'
|
200
|
+
|
201
|
+
resources_set.each do |resource|
|
202
|
+
color = resource.custom? ? ', fillcolor=grey' : ', fillcolor=white'
|
203
|
+
style = resource.topic? ? "[shape=component style=filled#{color}]" : "[shape=record, style=\"rounded,filled\"#{color}]"
|
204
|
+
puts " \"#{resource.name}\" #{style};"
|
205
|
+
end
|
206
|
+
|
207
|
+
subscriptions.each do |subscription|
|
208
|
+
puts " \"#{subscription[:topic].name}\" -> \"#{subscription[:endpoint].name}\";"
|
209
|
+
end
|
210
|
+
puts '}'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|