3scale_toolbox 0.11.0 → 0.12.2
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/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
@@ -13,7 +13,14 @@ module ThreeScaleToolbox
|
|
13
13
|
end
|
14
14
|
|
15
15
|
existing_operations.each do |op|
|
16
|
-
|
16
|
+
method_attrs = methods_index.fetch(op.method['system_name'])
|
17
|
+
method = Entities::Method.new(
|
18
|
+
id: method_attrs.fetch('id'),
|
19
|
+
parent_id: hits_metric_id,
|
20
|
+
service: service
|
21
|
+
)
|
22
|
+
method.update(op.method)
|
23
|
+
op.set(:metric_id, method.id)
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
@@ -23,18 +30,18 @@ module ThreeScaleToolbox
|
|
23
30
|
@hits_metric_id ||= service.hits['id']
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
27
|
-
@
|
28
|
-
acc[method['system_name']] = method
|
33
|
+
def methods_index
|
34
|
+
@methods_index ||= service.methods(hits_metric_id).each_with_object({}) do |method, acc|
|
35
|
+
acc[method['system_name']] = method
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
32
39
|
def missing_operations
|
33
|
-
operations.reject { |op|
|
40
|
+
operations.reject { |op| methods_index.key? op.method['system_name'] }
|
34
41
|
end
|
35
42
|
|
36
43
|
def existing_operations
|
37
|
-
operations.select { |op|
|
44
|
+
operations.select { |op| methods_index.key? op.method['system_name'] }
|
38
45
|
end
|
39
46
|
end
|
40
47
|
end
|
@@ -6,6 +6,7 @@ module ThreeScaleToolbox
|
|
6
6
|
def method
|
7
7
|
{
|
8
8
|
'friendly_name' => friendly_name,
|
9
|
+
'description' => description,
|
9
10
|
'system_name' => system_name
|
10
11
|
}
|
11
12
|
end
|
@@ -21,6 +22,10 @@ module ThreeScaleToolbox
|
|
21
22
|
def operation_id
|
22
23
|
"#{operation[:verb]}#{operation[:path].gsub(/[^\w]/, '')}"
|
23
24
|
end
|
25
|
+
|
26
|
+
def description
|
27
|
+
String(operation[:description])
|
28
|
+
end
|
24
29
|
end
|
25
30
|
end
|
26
31
|
end
|
@@ -40,12 +40,9 @@ module ThreeScaleToolbox
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def add_api_backend_settings(settings)
|
43
|
-
return if
|
44
|
-
|
45
|
-
scheme = api_spec.schemes.first || 'https'
|
46
|
-
host = api_spec.host
|
43
|
+
return if private_base_url.nil?
|
47
44
|
|
48
|
-
settings[:api_backend] =
|
45
|
+
settings[:api_backend] = private_base_url
|
49
46
|
end
|
50
47
|
|
51
48
|
def add_security_proxy_settings(settings)
|
@@ -74,6 +71,16 @@ module ThreeScaleToolbox
|
|
74
71
|
raise ThreeScaleToolbox::Error, "Unexpected security in_f field #{in_f}"
|
75
72
|
end
|
76
73
|
end
|
74
|
+
|
75
|
+
def private_base_url
|
76
|
+
override_private_base_url || private_base_url_from_openapi
|
77
|
+
end
|
78
|
+
|
79
|
+
def private_base_url_from_openapi
|
80
|
+
return if api_spec.host.nil?
|
81
|
+
|
82
|
+
"#{api_spec.schemes.first || 'https'}://#{api_spec.host}"
|
83
|
+
end
|
77
84
|
end
|
78
85
|
end
|
79
86
|
end
|
@@ -33,18 +33,11 @@ module ThreeScaleToolbox
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def print_data
|
36
|
-
metrics.each do |metric|
|
36
|
+
service.metrics.each do |metric|
|
37
37
|
puts FIELDS_TO_SHOW.map { |field| metric.fetch(field, '(empty)') }.join("\t")
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def metrics
|
42
|
-
hits_id = service.hits['id']
|
43
|
-
ThreeScaleToolbox::Helper.array_difference(service.metrics, service.methods(hits_id)) do |metric, method|
|
44
|
-
ThreeScaleToolbox::Helper.compare_hashes(metric, method, %w[id])
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
41
|
def service
|
49
42
|
@service ||= find_service
|
50
43
|
end
|
@@ -22,7 +22,6 @@ module ThreeScaleToolbox
|
|
22
22
|
option nil, 'cost-per-month', 'Cost per month', argument: :required, transform: method(:Float)
|
23
23
|
option nil, 'setup-fee', 'Setup fee', argument: :required, transform: method(:Float)
|
24
24
|
option nil, 'trial-period-days', 'Trial period days', argument: :required, transform: method(:Integer)
|
25
|
-
option nil, 'end-user-required', 'End user required. true or false', argument: :required, transform: ThreeScaleToolbox::Helper::BooleanTransformer.new
|
26
25
|
param :remote
|
27
26
|
param :service_ref
|
28
27
|
param :plan_ref
|
@@ -38,7 +37,7 @@ module ThreeScaleToolbox
|
|
38
37
|
plan = Entities::ApplicationPlan.create(service: service,
|
39
38
|
plan_attrs: create_plan_attrs)
|
40
39
|
else
|
41
|
-
plan.update(
|
40
|
+
plan.update(new_plan_attrs) unless new_plan_attrs.empty?
|
42
41
|
end
|
43
42
|
|
44
43
|
plan.make_default if option_default
|
@@ -65,12 +64,15 @@ module ThreeScaleToolbox
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def create_plan_attrs
|
68
|
-
|
69
|
-
|
67
|
+
new_attrs = plan_basic_attrs.merge('name' => plan_ref) { |_key, oldval, _newval| oldval }
|
68
|
+
new_attrs.tap do |params|
|
69
|
+
params['system_name'] = plan_ref
|
70
|
+
params['state'] = 'published' if option_publish
|
71
|
+
end
|
70
72
|
end
|
71
73
|
|
72
|
-
def
|
73
|
-
plan_basic_attrs.tap do |params|
|
74
|
+
def new_plan_attrs
|
75
|
+
plan_basic_attrs.clone.tap do |params|
|
74
76
|
params['state'] = 'published' if option_publish
|
75
77
|
params['state'] = 'hidden' if option_hide
|
76
78
|
end
|
@@ -80,7 +82,6 @@ module ThreeScaleToolbox
|
|
80
82
|
{
|
81
83
|
'name' => options[:name],
|
82
84
|
'approval_required' => options[:'approval-required'],
|
83
|
-
'end_user_required' => options[:'end-user-required'],
|
84
85
|
'cost_per_month' => options[:'cost-per-month'],
|
85
86
|
'setup_fee' => options[:'setup-fee'],
|
86
87
|
'trial_period_days' => options[:'trial-period-days']
|
@@ -20,7 +20,6 @@ module ThreeScaleToolbox
|
|
20
20
|
option nil, 'cost-per-month', 'Cost per month', argument: :required, transform: method(:Float)
|
21
21
|
option nil, 'setup-fee', 'Setup fee', argument: :required, transform: method(:Float)
|
22
22
|
option nil, 'trial-period-days', 'Trial period days', argument: :required, transform: method(:Integer)
|
23
|
-
option nil, 'end-user-required', 'End user required. true or false', argument: :required, transform: ThreeScaleToolbox::Helper::BooleanTransformer.new
|
24
23
|
param :remote
|
25
24
|
param :service_ref
|
26
25
|
param :plan_name
|
@@ -56,7 +55,6 @@ module ThreeScaleToolbox
|
|
56
55
|
'name' => arguments[:plan_name],
|
57
56
|
'system_name' => options[:'system-name'],
|
58
57
|
'approval_required' => options[:'approval-required'],
|
59
|
-
'end_user_required' => options[:'end-user-required'],
|
60
58
|
'cost_per_month' => options[:'cost-per-month'],
|
61
59
|
'setup_fee' => options[:'setup-fee'],
|
62
60
|
'trial_period_days' => options[:'trial-period-days']
|
@@ -26,8 +26,6 @@ module ThreeScaleToolbox
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def filtered_limit_methods
|
29
|
-
# has to be filtered this way
|
30
|
-
# looking up in metrics list does not work. Metric list includes methods and metrics
|
31
29
|
result[:limits].select { |limit| limit.dig('metric', 'type') == 'method' }
|
32
30
|
end
|
33
31
|
|
@@ -40,7 +38,6 @@ module ThreeScaleToolbox
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def filtered_pricing_rule_methods
|
43
|
-
# looking up in metrics list does not work. Metric list includes methods and metrics
|
44
41
|
result[:pricingrules].select { |limit| limit.dig('metric', 'type') == 'method' }
|
45
42
|
end
|
46
43
|
end
|
@@ -26,7 +26,6 @@ module ThreeScaleToolbox
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def filtered_limit_metrics
|
29
|
-
# looking up in metrics list does not work. Metric list includes methods and metrics
|
30
29
|
result[:limits].select { |limit| limit.dig('metric', 'type') == 'metric' }
|
31
30
|
end
|
32
31
|
|
@@ -39,7 +38,6 @@ module ThreeScaleToolbox
|
|
39
38
|
end
|
40
39
|
|
41
40
|
def filtered_pricing_rule_metrics
|
42
|
-
# looking up in metrics list does not work. Metric list includes methods and metrics
|
43
41
|
result[:pricingrules].select { |limit| limit.dig('metric', 'type') == 'metric' }
|
44
42
|
end
|
45
43
|
end
|
@@ -9,7 +9,8 @@ module ThreeScaleToolbox
|
|
9
9
|
# add metric system_name out of metric_id
|
10
10
|
def call
|
11
11
|
result[:pricingrules] = plan.pricing_rules.map do |pr|
|
12
|
-
pr.
|
12
|
+
pr.merge('metric' => metric_info(pr, 'PricingRule'),
|
13
|
+
'cost_per_unit' => pr.fetch('cost_per_unit').to_f)
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -54,8 +54,6 @@ module ThreeScaleToolbox
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def metric_info(elem, elem_name)
|
57
|
-
# Methods are included in metrics.
|
58
|
-
# First methods must be checked, otherwise it could be considered as a false metric
|
59
57
|
if (method = find_method(elem.fetch('metric_id')))
|
60
58
|
{ 'type' => 'method', 'system_name' => method.fetch('system_name') }
|
61
59
|
elsif (metric = find_metric(elem.fetch('metric_id')))
|
@@ -9,10 +9,11 @@ module ThreeScaleToolbox
|
|
9
9
|
def call
|
10
10
|
plan_obj = Entities::ApplicationPlan.find(service: service, ref: plan_system_name)
|
11
11
|
if plan_obj.nil?
|
12
|
-
plan_obj = Entities::ApplicationPlan.create(service: service,
|
12
|
+
plan_obj = Entities::ApplicationPlan.create(service: service,
|
13
|
+
plan_attrs: create_plan_attrs)
|
13
14
|
puts "Application plan created: #{plan_obj.id}"
|
14
15
|
else
|
15
|
-
res = plan_obj.update(
|
16
|
+
res = plan_obj.update(update_plan_attrs)
|
16
17
|
if (errors = res['errors'])
|
17
18
|
raise ThreeScaleToolbox::Error, "Could not update application plan #{plan_system_name}. Errors: #{errors}"
|
18
19
|
end
|
@@ -23,9 +24,13 @@ module ThreeScaleToolbox
|
|
23
24
|
|
24
25
|
private
|
25
26
|
|
26
|
-
def
|
27
|
+
def create_plan_attrs
|
27
28
|
resource_plan.merge('system_name' => plan_system_name)
|
28
29
|
end
|
30
|
+
|
31
|
+
def update_plan_attrs
|
32
|
+
resource_plan.reject { |key, _| %w[system_name].include? key }
|
33
|
+
end
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
@@ -18,9 +18,6 @@ module ThreeScaleToolbox
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def missing_metrics
|
21
|
-
# service metrics list includes methods
|
22
|
-
# this array_difference method computes elements in resource_metrics not included in service_metrics
|
23
|
-
# So methods will not be in the "missing_metrics" list, as long as array diff semantics are kept.
|
24
21
|
ThreeScaleToolbox::Helper.array_difference(resource_metrics, service_metrics) do |a, b|
|
25
22
|
ThreeScaleToolbox::Helper.compare_hashes(a, b, ['system_name'])
|
26
23
|
end
|
@@ -21,15 +21,22 @@ module ThreeScaleToolbox
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def missing_pricing_rules
|
24
|
-
ThreeScaleToolbox::Helper.array_difference(resource_pr_processed,
|
24
|
+
ThreeScaleToolbox::Helper.array_difference(resource_pr_processed, remote_pr_processed) do |a, b|
|
25
25
|
ThreeScaleToolbox::Helper.compare_hashes(a, b, %w[metric_id cost_per_unit min max])
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def remote_pr_processed
|
30
|
+
plan.pricing_rules.map do |pr|
|
31
|
+
pr.merge('cost_per_unit' => pr.fetch('cost_per_unit').to_f)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
29
35
|
def resource_pr_processed
|
30
36
|
resource_pricing_rules.map do |pr|
|
31
37
|
metric = find_metric_by_system_name(pr.delete('metric_system_name'))
|
32
|
-
pr.merge('metric_id' => metric.fetch('id')
|
38
|
+
pr.merge('metric_id' => metric.fetch('id'),
|
39
|
+
'cost_per_unit' => pr.fetch('cost_per_unit').to_f)
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
@@ -81,6 +81,10 @@ module ThreeScaleToolbox
|
|
81
81
|
context[:service_methods] ||= service.methods(service_hits['id'])
|
82
82
|
end
|
83
83
|
|
84
|
+
def service_metrics_and_methods
|
85
|
+
service_metrics + service_methods
|
86
|
+
end
|
87
|
+
|
84
88
|
def invalidate_service_methods
|
85
89
|
context[:service_methods] = nil
|
86
90
|
end
|
@@ -99,7 +103,7 @@ module ThreeScaleToolbox
|
|
99
103
|
end
|
100
104
|
|
101
105
|
def find_metric_by_system_name(system_name)
|
102
|
-
|
106
|
+
service_metrics_and_methods.find { |metric| metric['system_name'] == system_name }
|
103
107
|
end
|
104
108
|
|
105
109
|
private
|
@@ -19,8 +19,12 @@ module ThreeScaleToolbox
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def run
|
22
|
-
|
23
|
-
|
22
|
+
if promotable?
|
23
|
+
latest_proxy_config_from.promote(to: to_env)
|
24
|
+
puts "Proxy Configuration version #{latest_proxy_config_from.version} promoted to '#{to_env}'"
|
25
|
+
else
|
26
|
+
warn "warning: Nothing to promote. Proxy Configuration version #{latest_proxy_config_from.version} already promoted to production"
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
@@ -29,16 +33,28 @@ module ThreeScaleToolbox
|
|
29
33
|
@remote ||= threescale_client(arguments[:remote])
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
@
|
36
|
+
def latest_proxy_config_from
|
37
|
+
@proxy_config_from ||= find_proxy_config_latest_from
|
38
|
+
end
|
39
|
+
|
40
|
+
def latest_proxy_config_to
|
41
|
+
@proxy_config_to ||= find_proxy_config_latest_to
|
34
42
|
end
|
35
43
|
|
36
|
-
def
|
44
|
+
def promotable?
|
45
|
+
return latest_proxy_config_to.nil? || latest_proxy_config_from.version != latest_proxy_config_to.version
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_proxy_config_latest_from
|
37
49
|
Entities::ProxyConfig.find_latest(service: service, environment: from_env).tap do |pc|
|
38
50
|
raise ThreeScaleToolbox::Error, "ProxyConfig #{from_env} in service #{service.id} does not exist" if pc.nil?
|
39
51
|
end
|
40
52
|
end
|
41
53
|
|
54
|
+
def find_proxy_config_latest_to
|
55
|
+
Entities::ProxyConfig.find_latest(service: service, environment: to_env)
|
56
|
+
end
|
57
|
+
|
42
58
|
def service_ref
|
43
59
|
arguments[:service_ref]
|
44
60
|
end
|
@@ -20,15 +20,55 @@ module ThreeScaleToolbox
|
|
20
20
|
find_by_text(ref, remote)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
# ref can be
|
24
|
+
# * Email of the account user.
|
25
|
+
# * Username of the account user.
|
26
|
+
# * ID of the account user.
|
27
|
+
# * [Master API] Provider key of the account
|
28
|
+
# * [Master API] Service token of the account service.
|
29
|
+
#
|
30
|
+
# email, username or user_id fields search with AND logic. Therefore separate requests.
|
31
|
+
# buyer_provider_key, buyer_service_token fields search with OR logic. Same request.
|
32
|
+
def find_by_text(ref, remote)
|
33
|
+
account = find_by_email(remote, ref)
|
34
|
+
return account unless account.nil?
|
35
|
+
|
36
|
+
account = find_by_username(remote, ref)
|
37
|
+
return account unless account.nil?
|
38
|
+
|
39
|
+
account = find_by_user_id(remote, ref)
|
40
|
+
return account unless account.nil?
|
41
|
+
|
42
|
+
account = find_by_provider_or_service_token(remote, ref)
|
43
|
+
return account unless account.nil?
|
44
|
+
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_by_email(remote, email)
|
49
|
+
generic_find(remote, email: email)
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_by_username(remote, username)
|
53
|
+
generic_find(remote, username: username)
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_by_user_id(remote, user_id)
|
57
|
+
generic_find(remote, user_id: user_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_by_provider_or_service_token(remote, text)
|
61
|
+
generic_find(remote, buyer_provider_key: text, buyer_service_token: text)
|
62
|
+
end
|
63
|
+
|
64
|
+
def generic_find(remote, criteria)
|
65
|
+
account = remote.find_account(criteria)
|
26
66
|
if (errors = account['errors'])
|
27
67
|
raise ThreeScaleToolbox::ThreeScaleApiError.new(
|
28
68
|
'Account find returned errors', errors
|
29
69
|
)
|
30
70
|
end
|
31
|
-
new(id: account['id'], remote:
|
71
|
+
new(id: account['id'], remote: remote, attrs: account)
|
32
72
|
rescue ThreeScale::API::HttpClient::NotFoundError
|
33
73
|
nil
|
34
74
|
end
|