cyclone_lariat 0.3.10 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|