3scale_toolbox 0.11.0 → 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/3scale_toolbox.gemspec +42 -0
- data/LICENSE +201 -0
- data/NOTICE +15 -0
- data/README.md +8 -0
- data/lib/3scale_toolbox.rb +1 -0
- data/lib/3scale_toolbox/commands/application_command/apply_command.rb +21 -6
- data/lib/3scale_toolbox/commands/application_command/create_command.rb +3 -1
- data/lib/3scale_toolbox/commands/copy_command/copy_service.rb +5 -0
- data/lib/3scale_toolbox/commands/import_command/openapi.rb +5 -3
- data/lib/3scale_toolbox/commands/import_command/openapi/create_activedocs_step.rb +10 -2
- data/lib/3scale_toolbox/commands/import_command/openapi/create_method_step.rb +13 -6
- data/lib/3scale_toolbox/commands/import_command/openapi/method.rb +5 -0
- data/lib/3scale_toolbox/commands/import_command/openapi/step.rb +4 -0
- data/lib/3scale_toolbox/commands/import_command/openapi/threescale_api_spec.rb +2 -1
- data/lib/3scale_toolbox/commands/import_command/openapi/update_service_proxy_step.rb +12 -5
- data/lib/3scale_toolbox/commands/metrics_command/list_command.rb +1 -8
- data/lib/3scale_toolbox/commands/plans_command/apply_command.rb +8 -7
- data/lib/3scale_toolbox/commands/plans_command/create_command.rb +0 -2
- data/lib/3scale_toolbox/commands/plans_command/export/read_plan_methods_step.rb +0 -3
- data/lib/3scale_toolbox/commands/plans_command/export/read_plan_metrics_step.rb +0 -2
- data/lib/3scale_toolbox/commands/plans_command/export/read_plan_pricing_rules_step.rb +2 -1
- data/lib/3scale_toolbox/commands/plans_command/export/step.rb +0 -2
- data/lib/3scale_toolbox/commands/plans_command/import/create_or_update_app_plan_step.rb +8 -3
- data/lib/3scale_toolbox/commands/plans_command/import/import_plan_metrics_step.rb +0 -3
- data/lib/3scale_toolbox/commands/plans_command/import/import_plan_pricing_rules_step.rb +9 -2
- data/lib/3scale_toolbox/commands/plans_command/import/step.rb +5 -1
- data/lib/3scale_toolbox/commands/proxy_config_command/promote_command.rb +21 -5
- data/lib/3scale_toolbox/entities/account.rb +44 -4
- data/lib/3scale_toolbox/entities/activedocs.rb +1 -1
- data/lib/3scale_toolbox/entities/application.rb +21 -13
- data/lib/3scale_toolbox/entities/application_plan.rb +13 -12
- data/lib/3scale_toolbox/entities/base_entity.rb +1 -1
- data/lib/3scale_toolbox/entities/method.rb +1 -1
- data/lib/3scale_toolbox/entities/metric.rb +1 -1
- data/lib/3scale_toolbox/entities/service.rb +30 -15
- data/lib/3scale_toolbox/remotes.rb +1 -1
- data/lib/3scale_toolbox/resource_reader.rb +5 -2
- data/lib/3scale_toolbox/swagger/swagger.rb +5 -3
- data/lib/3scale_toolbox/tasks/copy_activedocs_task.rb +27 -9
- data/lib/3scale_toolbox/tasks/copy_limits_task.rb +4 -1
- data/lib/3scale_toolbox/tasks/copy_mapping_rules_task.rb +4 -1
- data/lib/3scale_toolbox/tasks/copy_methods_task.rb +20 -16
- data/lib/3scale_toolbox/tasks/copy_metrics_task.rb +14 -14
- data/lib/3scale_toolbox/tasks/copy_pricingrules_task.rb +4 -1
- data/lib/3scale_toolbox/tasks/copy_task.rb +40 -0
- data/lib/3scale_toolbox/version.rb +1 -1
- data/licenses.xml +303 -0
- metadata +8 -4
@@ -16,37 +16,37 @@ module ThreeScaleToolbox
|
|
16
16
|
# * User_key (API key)
|
17
17
|
# * App_id (from app_id/app_key pair)
|
18
18
|
# * Client ID (for OAuth and OpenID Connect authentication modes)
|
19
|
-
def find(remote:, ref:)
|
20
|
-
app = find_by_user_key(remote, ref)
|
19
|
+
def find(remote:, service_id: nil, ref:)
|
20
|
+
app = find_by_user_key(remote, service_id, ref)
|
21
21
|
return app unless app.nil?
|
22
22
|
|
23
|
-
app = find_by_app_id(remote, ref)
|
23
|
+
app = find_by_app_id(remote, service_id, ref)
|
24
24
|
return app unless app.nil?
|
25
25
|
|
26
|
-
app = find_by_id(remote, ref)
|
26
|
+
app = find_by_id(remote, service_id, ref)
|
27
27
|
return app unless app.nil?
|
28
28
|
|
29
29
|
nil
|
30
30
|
end
|
31
31
|
|
32
|
-
def find_by_id(remote, id)
|
33
|
-
generic_find(remote, :id, id)
|
32
|
+
def find_by_id(remote, service_id, id)
|
33
|
+
generic_find(remote, service_id, :id, id)
|
34
34
|
end
|
35
35
|
|
36
|
-
def find_by_user_key(remote, user_key)
|
37
|
-
generic_find(remote, :user_key, user_key)
|
36
|
+
def find_by_user_key(remote, service_id, user_key)
|
37
|
+
generic_find(remote, service_id, :user_key, user_key)
|
38
38
|
end
|
39
39
|
|
40
|
-
def find_by_app_id(remote, app_id)
|
41
|
-
generic_find(remote, :application_id, app_id)
|
40
|
+
def find_by_app_id(remote, service_id, app_id)
|
41
|
+
generic_find(remote, service_id, :application_id, app_id)
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
def generic_find(remote, type, ref)
|
46
|
+
def generic_find(remote, service_id, type, ref)
|
47
47
|
# find_application criteria only accepts one parameter.
|
48
48
|
# Otherwise unexpected behavior
|
49
|
-
attrs = remote.find_application(type => ref)
|
49
|
+
attrs = remote.find_application(service_id: service_id, type => ref)
|
50
50
|
if (errors = attrs['errors'])
|
51
51
|
raise ThreeScaleToolbox::ThreeScaleApiError.new('Application find error', errors)
|
52
52
|
end
|
@@ -60,7 +60,7 @@ module ThreeScaleToolbox
|
|
60
60
|
attr_reader :id, :remote
|
61
61
|
|
62
62
|
def initialize(id:, remote:, attrs: nil)
|
63
|
-
@id = id
|
63
|
+
@id = id.to_i
|
64
64
|
@remote = remote
|
65
65
|
@attrs = attrs
|
66
66
|
end
|
@@ -81,6 +81,8 @@ module ThreeScaleToolbox
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def resume
|
84
|
+
return attrs if live?
|
85
|
+
|
84
86
|
new_attrs = remote.resume_application(account_id, id)
|
85
87
|
if (errors = new_attrs['errors'])
|
86
88
|
raise ThreeScaleToolbox::ThreeScaleApiError.new('Application has not been resumed', errors)
|
@@ -92,6 +94,8 @@ module ThreeScaleToolbox
|
|
92
94
|
end
|
93
95
|
|
94
96
|
def suspend
|
97
|
+
return attrs unless live?
|
98
|
+
|
95
99
|
new_attrs = remote.suspend_application(account_id, id)
|
96
100
|
if (errors = new_attrs['errors'])
|
97
101
|
raise ThreeScaleToolbox::ThreeScaleApiError.new('Application has not been suspended', errors)
|
@@ -106,6 +110,10 @@ module ThreeScaleToolbox
|
|
106
110
|
remote.delete_application account_id, id
|
107
111
|
end
|
108
112
|
|
113
|
+
def live?
|
114
|
+
attrs.fetch('state') == 'live'
|
115
|
+
end
|
116
|
+
|
109
117
|
private
|
110
118
|
|
111
119
|
def account_id
|
@@ -39,7 +39,7 @@ module ThreeScaleToolbox
|
|
39
39
|
attr_reader :id, :service, :remote
|
40
40
|
|
41
41
|
def initialize(id:, service:, attrs: nil)
|
42
|
-
@id = id
|
42
|
+
@id = id.to_i
|
43
43
|
@service = service
|
44
44
|
@remote = service.remote
|
45
45
|
@attrs = attrs
|
@@ -50,6 +50,8 @@ module ThreeScaleToolbox
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def update(plan_attrs)
|
53
|
+
return attrs if update_plan_attrs(plan_attrs).empty?
|
54
|
+
|
53
55
|
new_attrs = remote.update_application_plan(service.id, id,
|
54
56
|
update_plan_attrs(plan_attrs))
|
55
57
|
if (errors = new_attrs['errors'])
|
@@ -170,6 +172,10 @@ module ThreeScaleToolbox
|
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
175
|
+
def published?
|
176
|
+
attrs.fetch('state') == 'published'
|
177
|
+
end
|
178
|
+
|
173
179
|
private
|
174
180
|
|
175
181
|
def read_plan_attrs
|
@@ -181,17 +187,12 @@ module ThreeScaleToolbox
|
|
181
187
|
plan_attrs
|
182
188
|
end
|
183
189
|
|
184
|
-
def update_plan_attrs(
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
# plans are created by default in hidden state
|
191
|
-
# If published is required, 'state_event' attr has to be added
|
192
|
-
state = new_plan_attrs.delete('state')
|
193
|
-
new_plan_attrs['state_event'] = 'publish' if state == 'published'
|
194
|
-
new_plan_attrs['state_event'] = 'hide' if state == 'hidden'
|
190
|
+
def update_plan_attrs(update_attrs)
|
191
|
+
new_attrs = update_attrs.reject { |key, _| %w[id links system_name].include? key }
|
192
|
+
new_attrs.tap do |params|
|
193
|
+
state = params.delete('state')
|
194
|
+
params['state_event'] = 'publish' if state == 'published' && !published?
|
195
|
+
params['state_event'] = 'hide' if state == 'hidden' && published?
|
195
196
|
end
|
196
197
|
end
|
197
198
|
|
@@ -66,7 +66,7 @@ module ThreeScaleToolbox
|
|
66
66
|
attr_reader :id, :remote
|
67
67
|
|
68
68
|
def initialize(id:, remote:, attrs: nil)
|
69
|
-
@id = id
|
69
|
+
@id = id.to_i
|
70
70
|
@remote = remote
|
71
71
|
@attrs = attrs
|
72
72
|
end
|
@@ -95,21 +95,18 @@ module ThreeScaleToolbox
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def metrics
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
# cache result to reuse
|
99
|
+
metric_and_method_list = metrics_and_methods
|
100
|
+
hits_metric_obj = hits_metric(metric_and_method_list)
|
101
|
+
hits_id = hits_metric_obj.fetch('id')
|
102
102
|
|
103
|
-
|
103
|
+
ThreeScaleToolbox::Helper.array_difference(metric_and_method_list, methods(hits_id)) do |metric, method|
|
104
|
+
ThreeScaleToolbox::Helper.compare_hashes(metric, method, %w[id])
|
105
|
+
end
|
104
106
|
end
|
105
107
|
|
106
108
|
def hits
|
107
|
-
hits_metric
|
108
|
-
metric['system_name'] == 'hits'
|
109
|
-
end
|
110
|
-
raise ThreeScaleToolbox::Error, 'missing hits metric' if hits_metric.nil?
|
111
|
-
|
112
|
-
hits_metric
|
109
|
+
hits_metric(metrics_and_methods)
|
113
110
|
end
|
114
111
|
|
115
112
|
def methods(parent_metric_id)
|
@@ -121,6 +118,15 @@ module ThreeScaleToolbox
|
|
121
118
|
service_methods
|
122
119
|
end
|
123
120
|
|
121
|
+
def metrics_and_methods
|
122
|
+
m_m = remote.list_metrics id
|
123
|
+
if m_m.respond_to?(:has_key?) && (errors = m_m['errors'])
|
124
|
+
raise ThreeScaleToolbox::ThreeScaleApiError.new('Service metrics not read', errors)
|
125
|
+
end
|
126
|
+
|
127
|
+
m_m
|
128
|
+
end
|
129
|
+
|
124
130
|
def plans
|
125
131
|
service_plans = remote.list_service_application_plans id
|
126
132
|
if service_plans.respond_to?(:has_key?) && (errors = service_plans['errors'])
|
@@ -174,9 +180,7 @@ module ThreeScaleToolbox
|
|
174
180
|
end
|
175
181
|
|
176
182
|
tenant_activedocs.select do |activedoc|
|
177
|
-
|
178
|
-
# activedocs endpoints return service_id as integers
|
179
|
-
activedoc['service_id'] == id.to_i
|
183
|
+
activedoc['service_id'] == id
|
180
184
|
end
|
181
185
|
end
|
182
186
|
|
@@ -245,8 +249,19 @@ module ThreeScaleToolbox
|
|
245
249
|
end
|
246
250
|
end
|
247
251
|
|
252
|
+
def ==(other)
|
253
|
+
remote.http_client.endpoint == other.remote.http_client.endpoint && id == other.id
|
254
|
+
end
|
255
|
+
|
248
256
|
private
|
249
257
|
|
258
|
+
def hits_metric(metric_list)
|
259
|
+
hits_metric = metric_list.find { |metric| metric['system_name'] == 'hits' }
|
260
|
+
raise ThreeScaleToolbox::Error, 'missing hits metric' if hits_metric.nil?
|
261
|
+
|
262
|
+
hits_metric
|
263
|
+
end
|
264
|
+
|
250
265
|
def service_attrs
|
251
266
|
svc = remote.show_service id
|
252
267
|
if (errors = svc['errors'])
|
@@ -27,8 +27,11 @@ module ThreeScaleToolbox
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Detect format from file extension
|
30
|
-
def read_file(
|
31
|
-
File.
|
30
|
+
def read_file(filename)
|
31
|
+
raise ThreeScaleToolbox::Error, "File not found: #{filename} " unless File.file?(filename)
|
32
|
+
raise ThreeScaleToolbox::Error, "File not readable: #{filename} " unless File.readable?(filename)
|
33
|
+
|
34
|
+
File.read(filename)
|
32
35
|
end
|
33
36
|
|
34
37
|
def read_stdin(_resource)
|
@@ -23,12 +23,13 @@ module ThreeScaleToolbox
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class Operation
|
26
|
-
attr_reader :verb, :operation_id, :path
|
26
|
+
attr_reader :verb, :operation_id, :path, :description
|
27
27
|
|
28
|
-
def initialize(verb:, operation_id:, path:)
|
28
|
+
def initialize(verb:, operation_id:, path:, description:)
|
29
29
|
@verb = verb
|
30
30
|
@operation_id = operation_id
|
31
31
|
@path = path
|
32
|
+
@description = description
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
@@ -83,7 +84,8 @@ module ThreeScaleToolbox
|
|
83
84
|
path_obj.flat_map do |method, operation|
|
84
85
|
next unless %w[get head post put patch delete trace options].include? method
|
85
86
|
|
86
|
-
Operation.new(verb: method, path: path,
|
87
|
+
Operation.new(verb: method, path: path, description: operation['description'],
|
88
|
+
operation_id: operation['operationId'])
|
87
89
|
end.compact
|
88
90
|
end
|
89
91
|
end
|
@@ -6,17 +6,35 @@ module ThreeScaleToolbox
|
|
6
6
|
def call
|
7
7
|
puts 'copying all service ActiveDocs'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
source.activedocs.each(&method(:apply_target_activedoc))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def apply_target_activedoc(attrs)
|
15
|
+
activedocs = Entities::ActiveDocs.find_by_system_name(remote: target.remote,
|
16
|
+
system_name: attrs['system_name'])
|
17
|
+
if activedocs.nil?
|
18
|
+
Entities::ActiveDocs.create(remote: target.remote, attrs: create_attrs(attrs))
|
19
|
+
elsif activedocs.attrs.fetch('service_id') == target.id
|
20
|
+
activedocs.update(update_attrs(attrs))
|
21
|
+
else
|
22
|
+
# activedocs with same system_name exists, but now owned by target service
|
23
|
+
new_attrs = create_attrs(attrs)
|
24
|
+
new_attrs['system_name'] = "#{attrs['system_name']}#{target.id}"
|
25
|
+
Entities::ActiveDocs.create(remote: target.remote, attrs: new_attrs)
|
15
26
|
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_attrs(old_attrs)
|
30
|
+
create_attrs(old_attrs)
|
31
|
+
end
|
16
32
|
|
17
|
-
|
18
|
-
|
19
|
-
|
33
|
+
def create_attrs(old_attrs)
|
34
|
+
# keep same system_name
|
35
|
+
new_attrs = old_attrs.reject { |key, _| %w[id created_at updated_at].include? key }
|
36
|
+
new_attrs.tap do |attrs|
|
37
|
+
attrs['service_id'] = target.id
|
20
38
|
end
|
21
39
|
end
|
22
40
|
end
|
@@ -5,7 +5,6 @@ module ThreeScaleToolbox
|
|
5
5
|
include Helper
|
6
6
|
|
7
7
|
def call
|
8
|
-
metrics_map = metrics_mapping(source.metrics, target.metrics)
|
9
8
|
plan_mapping = application_plan_mapping(source.plans, target.plans)
|
10
9
|
plan_mapping.each do |plan_id, target_plan|
|
11
10
|
source_plan = ThreeScaleToolbox::Entities::ApplicationPlan.new(id: plan_id, service: source)
|
@@ -22,6 +21,10 @@ module ThreeScaleToolbox
|
|
22
21
|
|
23
22
|
private
|
24
23
|
|
24
|
+
def metrics_map
|
25
|
+
@metrics_map ||= metrics_mapping(source_metrics_and_methods, target_metrics_and_methods)
|
26
|
+
end
|
27
|
+
|
25
28
|
def missing_limits(source_limits, target_limits, metrics_map)
|
26
29
|
ThreeScaleToolbox::Helper.array_difference(source_limits, target_limits) do |limit, target|
|
27
30
|
ThreeScaleToolbox::Helper.compare_hashes(limit, target, ['period']) &&
|
@@ -5,7 +5,6 @@ module ThreeScaleToolbox
|
|
5
5
|
include Helper
|
6
6
|
|
7
7
|
def call
|
8
|
-
metrics_map = metrics_mapping(source.metrics, target.metrics)
|
9
8
|
missing_rules = missing_mapping_rules(source.mapping_rules,
|
10
9
|
target.mapping_rules, metrics_map)
|
11
10
|
missing_rules.each do |mapping_rule|
|
@@ -18,6 +17,10 @@ module ThreeScaleToolbox
|
|
18
17
|
|
19
18
|
private
|
20
19
|
|
20
|
+
def metrics_map
|
21
|
+
@metrics_map ||= metrics_mapping(source_metrics_and_methods, target_metrics_and_methods)
|
22
|
+
end
|
23
|
+
|
21
24
|
def missing_mapping_rules(source_rules, target_rules, metrics_map)
|
22
25
|
ThreeScaleToolbox::Helper.array_difference(source_rules, target_rules) do |source_rule, target_rule|
|
23
26
|
ThreeScaleToolbox::Helper.compare_hashes(source_rule, target_rule, %w[pattern http_method delta]) &&
|
@@ -4,26 +4,30 @@ module ThreeScaleToolbox
|
|
4
4
|
include CopyTask
|
5
5
|
|
6
6
|
def call
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
puts "target service hits metric #{target_hits_id} has #{target_methods.size} methods"
|
13
|
-
missing = missing_methods(source_methods, target_methods).each do |method|
|
14
|
-
Entities::Method.create(
|
15
|
-
service: target,
|
16
|
-
parent_id: target_hits_id,
|
17
|
-
attrs: ThreeScaleToolbox::Helper.filter_params(%w[friendly_name system_name], method)
|
18
|
-
)
|
19
|
-
end
|
20
|
-
puts "created #{missing.size} missing methods on target service"
|
7
|
+
puts "original service hits metric #{source_hits.fetch('id')} has #{source_methods.size} methods"
|
8
|
+
puts "target service hits metric #{target_hits.fetch('id')} has #{target_methods.size} methods"
|
9
|
+
missing_methods.each(&method(:create_method))
|
10
|
+
puts "created #{missing_methods.size} missing methods on target service"
|
11
|
+
invalidate_target_methods if missing_methods.size.positive?
|
21
12
|
end
|
22
13
|
|
23
14
|
private
|
24
15
|
|
25
|
-
def
|
26
|
-
|
16
|
+
def create_method(method)
|
17
|
+
Entities::Method.create(
|
18
|
+
service: target,
|
19
|
+
parent_id: target_hits.fetch('id'),
|
20
|
+
attrs: ThreeScaleToolbox::Helper.filter_params(%w[friendly_name system_name], method)
|
21
|
+
)
|
22
|
+
rescue ThreeScaleToolbox::ThreeScaleApiError => e
|
23
|
+
raise e unless ThreeScaleToolbox::Helper.system_name_already_taken_error?(e.apierrors)
|
24
|
+
|
25
|
+
warn "[WARN] method #{method.fetch('system_name')} not created. " \
|
26
|
+
'Metric with the same system_name exists.'
|
27
|
+
end
|
28
|
+
|
29
|
+
def missing_methods
|
30
|
+
@missing_methods ||= ThreeScaleToolbox::Helper.array_difference(source_methods, target_methods) do |method, target|
|
27
31
|
ThreeScaleToolbox::Helper.compare_hashes(method, target, ['system_name'])
|
28
32
|
end
|
29
33
|
end
|