3scale_toolbox 0.19.2 → 0.19.3

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/3scale_toolbox/commands/import_command/openapi/update_policies_step.rb +23 -10
  3. data/lib/3scale_toolbox/commands/plans_command/export_command.rb +52 -29
  4. data/lib/3scale_toolbox/commands/plans_command/import/import_backend_metrics_step.rb +37 -0
  5. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_limits_step.rb +11 -2
  6. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_metrics_step.rb +2 -2
  7. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_pricing_rules_step.rb +12 -1
  8. data/lib/3scale_toolbox/commands/plans_command/import/step.rb +23 -8
  9. data/lib/3scale_toolbox/commands/plans_command/import/validate_plan_step.rb +126 -0
  10. data/lib/3scale_toolbox/commands/plans_command/import_command.rb +5 -1
  11. data/lib/3scale_toolbox/crds/limit_dump.rb +1 -1
  12. data/lib/3scale_toolbox/crds/pricing_rule_dump.rb +1 -1
  13. data/lib/3scale_toolbox/entities/application_plan.rb +64 -0
  14. data/lib/3scale_toolbox/entities/backend.rb +4 -0
  15. data/lib/3scale_toolbox/entities/backend_method.rb +16 -0
  16. data/lib/3scale_toolbox/entities/backend_metric.rb +16 -0
  17. data/lib/3scale_toolbox/entities/limit.rb +52 -7
  18. data/lib/3scale_toolbox/entities/method.rb +11 -0
  19. data/lib/3scale_toolbox/entities/metric.rb +12 -0
  20. data/lib/3scale_toolbox/entities/pricing_rule.rb +52 -7
  21. data/lib/3scale_toolbox/entities/service.rb +4 -0
  22. data/lib/3scale_toolbox/remote_cache.rb +42 -1
  23. data/lib/3scale_toolbox/version.rb +1 -1
  24. data/licenses.xml +4 -4
  25. metadata +4 -10
  26. data/lib/3scale_toolbox/commands/plans_command/export/read_app_plan_step.rb +0 -16
  27. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_features_step.rb +0 -16
  28. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_limits_step.rb +0 -19
  29. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_methods_step.rb +0 -47
  30. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_metrics_step.rb +0 -47
  31. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_pricing_rules_step.rb +0 -19
  32. data/lib/3scale_toolbox/commands/plans_command/export/step.rb +0 -85
  33. data/lib/3scale_toolbox/commands/plans_command/export/write_artifacts_file_step.rb +0 -84
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dee95ebde6b993418261f63857e80e18c8dd94bcfea9b92c6fa505cbbfdade99
4
- data.tar.gz: ff8c3c97adb47ad141b2af12f8d4481330f9f25ce8819ecb5162666c6eedc521
3
+ metadata.gz: d2a44bdf128bf6f8d4d0a592a4eee49c82c34415017e03366ff2bcc241fe18c0
4
+ data.tar.gz: 0e94df4747331e9092ae0c961709cfcc334a553eb54209378941b8239307eceb
5
5
  SHA512:
6
- metadata.gz: 41473b4f397a15743224e1848aecdd21abdf8a0246833522c2a3aadf6ed5c5cc58970e4761bb61801afa2e32b4326a33d15bf71db3f926c06a7620f7daa5e8b1
7
- data.tar.gz: 6d1396f584b308ba1f978f02981605023d346c2ff39d806e1e3b265b7d16233f72beb4f7fc896e99a6d62d5b765878d5e9c71ee4eeb444db91101decc0a16bae
6
+ metadata.gz: 8dd7a6efc6567598d87e4ebbc18c486eba1ea9e6766ca6c0241f78e73a4287408d9e18ac838788e81a073c8f3a8fd93d299fac4ea9f21a42571e3cff68f2b0bb
7
+ data.tar.gz: c4ed75a0b46414606208a5fb6e1374e72d5fe06fbb5a237b3793bc2471d20667c489acace51cdf93d4971bfe59b42dc2919631b90074a8af72bac1668c663d01
@@ -15,7 +15,7 @@ module ThreeScaleToolbox
15
15
  # do not update in-place, otherwise changes will not be detected
16
16
  policies_settings = source_policies_settings.dup
17
17
 
18
- add_anonymous_access_policy(policies_settings)
18
+ reconcile_anonymous_access_policy(policies_settings)
19
19
  add_rh_sso_keycloak_role_check_policy(policies_settings)
20
20
  add_url_rewritting_policy(policies_settings)
21
21
 
@@ -31,15 +31,28 @@ module ThreeScaleToolbox
31
31
 
32
32
  private
33
33
 
34
- def add_anonymous_access_policy(policies)
35
- # only on 'open api' security req
36
- return unless api_spec.security.nil?
37
-
38
- return if policies.any? { |policy| policy['name'] == 'default_credentials' }
39
-
40
- # Anonymous policy should be before apicast policy
41
- # hence, adding as a first element
42
- policies.insert(0, anonymous_policy)
34
+ def reconcile_anonymous_access_policy(policies)
35
+ idx = policies.find_index { |p| p['name'] == 'default_credentials' }
36
+
37
+ if api_spec.security.nil?
38
+ # only on 'open api' security req
39
+ # Update anonymous policy if exists
40
+ #
41
+ if idx.nil?
42
+ # Anonymous policy should be before apicast policy
43
+ # hence, adding as a first element
44
+ policies.insert(0, anonymous_policy)
45
+ else
46
+ # only update if different
47
+ if policies[idx].dig('configuration', 'user_key') != anonymous_policy.dig(:configuration, :user_key)
48
+ policies[idx] = anonymous_policy
49
+ end
50
+ end
51
+ else
52
+ unless idx.nil?
53
+ policies.slice!(idx)
54
+ end
55
+ end
43
56
  end
44
57
 
45
58
  def anonymous_policy
@@ -1,12 +1,3 @@
1
- require '3scale_toolbox/commands/plans_command/export/step'
2
- require '3scale_toolbox/commands/plans_command/export/read_app_plan_step'
3
- require '3scale_toolbox/commands/plans_command/export/read_plan_features_step'
4
- require '3scale_toolbox/commands/plans_command/export/read_plan_limits_step'
5
- require '3scale_toolbox/commands/plans_command/export/read_plan_pricing_rules_step'
6
- require '3scale_toolbox/commands/plans_command/export/read_plan_methods_step'
7
- require '3scale_toolbox/commands/plans_command/export/read_plan_metrics_step'
8
- require '3scale_toolbox/commands/plans_command/export/write_artifacts_file_step'
9
-
10
1
  module ThreeScaleToolbox
11
2
  module Commands
12
3
  module PlansCommand
@@ -31,32 +22,64 @@ module ThreeScaleToolbox
31
22
  end
32
23
 
33
24
  def run
34
- tasks = []
35
- tasks << ReadAppPlanStep.new(context)
36
- tasks << ReadPlanLimitsStep.new(context)
37
- tasks << ReadPlanPricingRulesStep.new(context)
38
- tasks << ReadPlanFeaturesStep.new(context)
39
- tasks << ReadPlanMethods.new(context)
40
- tasks << ReadPlanMetrics.new(context)
41
- tasks << WriteArtifactsStep.new(context)
42
-
43
- # run tasks
44
- tasks.each(&:call)
25
+ select_output do |output|
26
+ plan_object = application_plan.to_hash.merge(
27
+ 'created_at' => Time.now.utc.iso8601,
28
+ 'toolbox_version' => ThreeScaleToolbox::VERSION
29
+ )
30
+ output.write(plan_object.to_yaml)
31
+ end
45
32
  end
46
33
 
47
34
  private
48
35
 
49
- def context
50
- @context ||= create_context
36
+ def remote
37
+ @remote ||= threescale_client(arguments[:remote])
38
+ end
39
+
40
+ def select_output
41
+ ios = if file
42
+ File.open(file, 'w')
43
+ else
44
+ $stdout
45
+ end
46
+ begin
47
+ yield(ios)
48
+ ensure
49
+ ios.close
50
+ end
51
+ end
52
+
53
+ def application_plan
54
+ @application_plan ||= find_application_plan
55
+ end
56
+
57
+ def find_application_plan
58
+ Entities::ApplicationPlan.find(service: product, ref: plan_system_name).tap do |p|
59
+ raise ThreeScaleToolbox::Error, "Application plan #{plan_system_name} does not exist" if p.nil?
60
+ end
61
+ end
62
+
63
+ def product
64
+ @product ||= find_product
65
+ end
66
+
67
+ def product_ref
68
+ arguments[:service_system_name]
69
+ end
70
+
71
+ def plan_system_name
72
+ arguments[:plan_system_name]
73
+ end
74
+
75
+ def find_product
76
+ Entities::Service.find(remote: remote, ref: product_ref).tap do |prd|
77
+ raise ThreeScaleToolbox::Error, "Product #{product_ref} does not exist" if prd.nil?
78
+ end
51
79
  end
52
80
 
53
- def create_context
54
- {
55
- file: options[:file],
56
- threescale_client: threescale_client(arguments[:remote]),
57
- service_system_name: arguments[:service_system_name],
58
- plan_system_name: arguments[:plan_system_name],
59
- }
81
+ def file
82
+ options[:file]
60
83
  end
61
84
  end
62
85
  end
@@ -0,0 +1,37 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Import
5
+ class ImportBackendMetricsStep
6
+ include Step
7
+ ##
8
+ # Writes Plan metrics and methods
9
+ def call
10
+ resource_backend_metrics.each(&method(:create_metric))
11
+ resource_backend_methods.each(&method(:create_method))
12
+ end
13
+
14
+ private
15
+
16
+ def create_metric(metric_attrs)
17
+ backend = find_backend(metric_attrs.fetch('backend_system_name'))
18
+
19
+ unless backend.metrics.any? { |m| m.system_name == metric_attrs.fetch('system_name') }
20
+ Entities::BackendMetric.create(backend: backend, attrs: metric_attrs)
21
+ puts "Created backend metric: #{metric_attrs.fetch('system_name')}; backend: #{backend.system_name}"
22
+ end
23
+ end
24
+
25
+ def create_method(method_attrs)
26
+ backend = find_backend(method_attrs.fetch('backend_system_name'))
27
+
28
+ unless backend.methods.any? { |m| m.system_name == method_attrs.fetch('system_name') }
29
+ Entities::BackendMethod.create(backend: backend, attrs: method_attrs)
30
+ puts "Created backend method: #{method_attrs.fetch('system_name')}; backend: #{backend.system_name}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,7 +2,7 @@ module ThreeScaleToolbox
2
2
  module Commands
3
3
  module PlansCommand
4
4
  module Import
5
- class ImportMetricLimitsStep
5
+ class ImportLimitsStep
6
6
  include Step
7
7
  ##
8
8
  # Writes Plan limits
@@ -26,9 +26,18 @@ module ThreeScaleToolbox
26
26
 
27
27
  def resource_limits_processed
28
28
  resource_limits.map do |limit|
29
- metric = find_metric_by_system_name(limit.delete('metric_system_name'))
29
+ metric_system_name = limit.delete('metric_system_name')
30
+ backend_system_name = limit.delete('metric_backend_system_name')
31
+ metric_owner = if backend_system_name.nil?
32
+ service
33
+ else
34
+ find_backend(backend_system_name)
35
+ end
36
+ metric = metric_owner.find_metric_or_method(metric_system_name)
30
37
  # this ImportMetricLimitsStep step is assuming all metrics/methods have been created
31
38
  # in previous step, so finding metric should always succeed.
39
+ raise ThreeScaleToolbox::Error, "metric [#{metric_system_name}, #{backend_system_name}] not found" if metric.nil?
40
+
32
41
  limit.merge('metric_id' => metric.id)
33
42
  end
34
43
  end
@@ -14,13 +14,13 @@ module ThreeScaleToolbox
14
14
  private
15
15
 
16
16
  def missing_metrics
17
- ThreeScaleToolbox::Helper.array_difference(resource_metrics, service.metrics) do |a, b|
17
+ ThreeScaleToolbox::Helper.array_difference(resource_product_metrics, service.metrics) do |a, b|
18
18
  a['system_name'] == b.system_name
19
19
  end
20
20
  end
21
21
 
22
22
  def missing_methods
23
- ThreeScaleToolbox::Helper.array_difference(resource_methods, service.methods) do |a, b|
23
+ ThreeScaleToolbox::Helper.array_difference(resource_product_methods, service.methods) do |a, b|
24
24
  a['system_name'] == b.system_name
25
25
  end
26
26
  end
@@ -26,7 +26,18 @@ module ThreeScaleToolbox
26
26
 
27
27
  def resource_pr_processed
28
28
  resource_pricing_rules.map do |pr|
29
- metric = find_metric_by_system_name(pr.delete('metric_system_name'))
29
+ metric_system_name = pr.delete('metric_system_name')
30
+ backend_system_name = pr.delete('metric_backend_system_name')
31
+ metric_owner = if backend_system_name.nil?
32
+ service
33
+ else
34
+ find_backend(backend_system_name)
35
+ end
36
+ metric = metric_owner.find_metric_or_method(metric_system_name)
37
+ # this ImportMetricLimitsStep step is assuming all metrics/methods have been created
38
+ # in previous step, so finding metric should always succeed.
39
+ raise ThreeScaleToolbox::Error, "metric [#{metric_system_name}, #{backend_system_name}] not found" if metric.nil?
40
+
30
41
  pr.merge('metric_id' => metric.id,
31
42
  'cost_per_unit' => pr.fetch('cost_per_unit').to_f)
32
43
  end
@@ -53,6 +53,22 @@ module ThreeScaleToolbox
53
53
  artifacts_resource['methods'] || []
54
54
  end
55
55
 
56
+ def resource_product_metrics
57
+ resource_metrics.reject{ |m| m.has_key? 'backend_system_name' }
58
+ end
59
+
60
+ def resource_product_methods
61
+ resource_methods.reject{ |mth| mth.has_key? 'backend_system_name' }
62
+ end
63
+
64
+ def resource_backend_metrics
65
+ resource_metrics.select{ |m| m.has_key? 'backend_system_name' }
66
+ end
67
+
68
+ def resource_backend_methods
69
+ resource_methods.select{ |mth| mth.has_key? 'backend_system_name' }
70
+ end
71
+
56
72
  def resource_limits
57
73
  artifacts_resource['limits'] || []
58
74
  end
@@ -65,10 +81,6 @@ module ThreeScaleToolbox
65
81
  artifacts_resource['plan_features'] || []
66
82
  end
67
83
 
68
- def service_metrics_and_methods
69
- service.metrics + service.methods
70
- end
71
-
72
84
  def service_features
73
85
  context[:service_features] ||= service.features
74
86
  end
@@ -82,10 +94,6 @@ module ThreeScaleToolbox
82
94
  service_features.find { |feature| feature['system_name'] == system_name }
83
95
  end
84
96
 
85
- def find_metric_by_system_name(system_name)
86
- service_metrics_and_methods.find { |metric| metric.system_name == system_name }
87
- end
88
-
89
97
  private
90
98
 
91
99
  def find_service
@@ -100,6 +108,13 @@ module ThreeScaleToolbox
100
108
  raise ThreeScaleToolbox::Error, "Application plan #{plan_system_name} does not exist" if p.nil?
101
109
  end
102
110
  end
111
+
112
+ def find_backend(backend_system_name)
113
+ Entities::Backend.find_by_system_name(remote: threescale_client,
114
+ system_name: backend_system_name).tap do |backend|
115
+ raise ThreeScaleToolbox::Error, "Backend #{backend_system_name} does not exist" if backend.nil?
116
+ end
117
+ end
103
118
  end
104
119
  end
105
120
  end
@@ -0,0 +1,126 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Import
5
+ class ValidatePlanStep
6
+ include Step
7
+ ##
8
+ # Creates if it does not exist, updates otherwise
9
+ def call
10
+ validate_product_metric_method_uniqueness!
11
+
12
+ validate_backend_metric_method_uniqueness!
13
+
14
+ validate_product_backend_usage_references!
15
+
16
+ validate_limit_backend_references!
17
+
18
+ validate_limit_product_references!
19
+
20
+ validate_pricingrule_backend_references!
21
+
22
+ validate_pricingrule_product_references!
23
+ end
24
+
25
+ private
26
+
27
+ def validate_product_metric_method_uniqueness!
28
+ system_name_list = (resource_product_metrics + resource_product_methods).map do |m|
29
+ m.fetch('system_name')
30
+ end
31
+ if system_name_list.length != system_name_list.uniq.length
32
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
33
+ "Product metrics and method system names must be unique."
34
+ end
35
+ end
36
+
37
+ def validate_backend_metric_method_uniqueness!
38
+ metric_list = resource_backend_metrics + resource_backend_methods
39
+ backend_list = metric_list.map { |m| m.fetch('backend_system_name') }.uniq
40
+ backend_list.each do |backend_system_name|
41
+ backend_metric_list = metric_list.select do |m|
42
+ m.fetch('backend_system_name') == backend_system_name
43
+ end.map { |m| m.fetch('system_name') }
44
+
45
+ if backend_metric_list.length != backend_metric_list.uniq.length
46
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
47
+ "Backend #{backend_system_name} contains metrics and method system names that are not unique"
48
+ end
49
+ end
50
+ end
51
+
52
+ def validate_product_backend_usage_references!
53
+ metric_list = resource_backend_metrics + resource_backend_methods
54
+ backend_list = metric_list.map { |m| m.fetch('backend_system_name') }.uniq
55
+ backend_usages_list = service.backend_usage_list.map(&:backend).map(&:system_name)
56
+
57
+ backend_list.each do |backend_system_name|
58
+ unless backend_usages_list.include?(backend_system_name)
59
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
60
+ "Backend usage reference to backend #{backend_system_name} has not been found"
61
+ end
62
+ end
63
+ end
64
+
65
+ def validate_limit_backend_references!
66
+ metric_list = resource_backend_metrics + resource_backend_methods
67
+ limits_with_backend_ref = resource_limits.select{ |limit| limit.has_key? 'metric_backend_system_name'}
68
+ limits_with_backend_ref.each do |limit|
69
+ none = metric_list.none? do |m|
70
+ m.fetch('system_name') == limit.fetch('metric_system_name') &&
71
+ m.fetch('backend_system_name') == limit.fetch('metric_backend_system_name')
72
+ end
73
+
74
+ if none
75
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
76
+ "Limit with backend metric [#{limit.fetch('metric_system_name')}, #{limit.fetch('metric_backend_system_name')}] " \
77
+ "has not been found in metric or method list"
78
+ end
79
+ end
80
+ end
81
+
82
+ def validate_limit_product_references!
83
+ metric_list = resource_product_metrics + resource_product_methods
84
+ limits = resource_limits.reject { |limit| limit.has_key? 'metric_backend_system_name'}
85
+ limits.each do |limit|
86
+ if metric_list.none? { |m| m.fetch('system_name') == limit.fetch('metric_system_name') }
87
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
88
+ "Limit with product metric [#{limit.fetch('metric_system_name')}] " \
89
+ "has not been found in metric or method list"
90
+ end
91
+ end
92
+ end
93
+
94
+ def validate_pricingrule_backend_references!
95
+ metric_list = resource_backend_metrics + resource_backend_methods
96
+ pr_with_backend_ref = resource_pricing_rules.select{ |pr| pr.has_key? 'metric_backend_system_name'}
97
+ pr_with_backend_ref.each do |pr|
98
+ none = metric_list.none? do |m|
99
+ m.fetch('system_name') == pr.fetch('metric_system_name') &&
100
+ m.fetch('backend_system_name') == pr.fetch('metric_backend_system_name')
101
+ end
102
+
103
+ if none
104
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
105
+ "PricingRule with backend metric [#{pr.fetch('metric_system_name')}, #{pr.fetch('metric_backend_system_name')}] " \
106
+ "has not been found in metric or method list"
107
+ end
108
+ end
109
+ end
110
+
111
+ def validate_pricingrule_product_references!
112
+ metric_list = resource_product_metrics + resource_product_methods
113
+ prs = resource_pricing_rules.reject { |pr| pr.has_key? 'metric_backend_system_name'}
114
+ prs.each do |pr|
115
+ if metric_list.none? { |m| m.fetch('system_name') == pr.fetch('metric_system_name') }
116
+ raise ThreeScaleToolbox::Error, "Invalid content. " \
117
+ "PricingRule with product metric [#{pr.fetch('metric_system_name')}] " \
118
+ "has not been found in metric or method list"
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,9 +1,11 @@
1
1
  require '3scale_toolbox/commands/plans_command/import/step'
2
+ require '3scale_toolbox/commands/plans_command/import/validate_plan_step'
2
3
  require '3scale_toolbox/commands/plans_command/import/create_or_update_app_plan_step'
3
4
  require '3scale_toolbox/commands/plans_command/import/import_plan_features_step'
4
5
  require '3scale_toolbox/commands/plans_command/import/import_plan_metrics_step'
5
6
  require '3scale_toolbox/commands/plans_command/import/import_plan_limits_step'
6
7
  require '3scale_toolbox/commands/plans_command/import/import_plan_pricing_rules_step'
8
+ require '3scale_toolbox/commands/plans_command/import/import_backend_metrics_step'
7
9
 
8
10
  module ThreeScaleToolbox
9
11
  module Commands
@@ -31,9 +33,11 @@ module ThreeScaleToolbox
31
33
 
32
34
  def run
33
35
  tasks = []
36
+ tasks << ValidatePlanStep.new(context)
34
37
  tasks << CreateOrUpdateAppPlanStep.new(context)
35
38
  tasks << ImportMetricsStep.new(context)
36
- tasks << ImportMetricLimitsStep.new(context)
39
+ tasks << ImportBackendMetricsStep.new(context)
40
+ tasks << ImportLimitsStep.new(context)
37
41
  tasks << ImportPricingRulesStep.new(context)
38
42
  tasks << ImportPlanFeaturesStep.new(context)
39
43
 
@@ -18,7 +18,7 @@ module ThreeScaleToolbox
18
18
  { 'systemName' => method.system_name }
19
19
  elsif (metric = plan.service.metrics.find { |m| m.id == metric_id })
20
20
  { 'systemName' => metric.system_name }
21
- elsif (backend = backend_from_metric)
21
+ elsif (backend = backend_from_metric_link)
22
22
  if (backend_metric = backend.metrics.find { |m| m.id == metric_id })
23
23
  { 'systemName' => backend_metric.system_name, 'backend' => backend.system_name }
24
24
  elsif (backend_method = backend.methods.find { |m| m.id == metric_id })
@@ -19,7 +19,7 @@ module ThreeScaleToolbox
19
19
  { 'systemName' => method.system_name }
20
20
  elsif (metric = plan.service.metrics.find { |m| m.id == metric_id })
21
21
  { 'systemName' => metric.system_name }
22
- elsif (backend = backend_from_metric)
22
+ elsif (backend = backend_from_metric_link)
23
23
  if (backend_metric = backend.metrics.find { |m| m.id == metric_id })
24
24
  { 'systemName' => backend_metric.system_name, 'backend' => backend.system_name }
25
25
  elsif (backend_method = backend.methods.find { |m| m.id == metric_id })
@@ -3,6 +3,9 @@ module ThreeScaleToolbox
3
3
  class ApplicationPlan
4
4
  include CRD::ApplicationPlanSerializer
5
5
 
6
+ APP_PLANS_BLACKLIST = %w[id links default custom created_at updated_at].freeze
7
+ PLAN_FEATURE_BLACKLIST = %w[id links created_at updated_at].freeze
8
+
6
9
  class << self
7
10
  def create(service:, plan_attrs:)
8
11
  plan = service.remote.create_application_plan service.id, create_plan_attrs(plan_attrs)
@@ -209,8 +212,69 @@ module ThreeScaleToolbox
209
212
  attrs.fetch('cost_per_month', 0.0)
210
213
  end
211
214
 
215
+ def to_hash
216
+ {
217
+ 'plan' => attrs.reject { |key, _| APP_PLANS_BLACKLIST.include? key },
218
+ 'limits' => limits.map(&:to_hash),
219
+ 'pricingrules' => pricing_rules.map(&:to_hash),
220
+ 'plan_features' => features.map do |feature|
221
+ feature.reject { |key, _| PLAN_FEATURE_BLACKLIST.include? key }
222
+ end,
223
+ 'metrics' => uniq_metrics_to_hash,
224
+ 'methods' => uniq_methods_to_hash,
225
+ }
226
+ end
227
+
212
228
  private
213
229
 
230
+ def uniq_metrics_to_hash
231
+ limit_metrics = limits.flat_map do |limit|
232
+ # one of them (or both) could be nil
233
+ [
234
+ limit.product_metric, limit.backend_metric
235
+ ]
236
+ end.compact
237
+
238
+ pr_metrics = pricing_rules.flat_map do |pr|
239
+ # one of them (or both) could be nil
240
+ [
241
+ pr.product_metric, pr.backend_metric
242
+ ]
243
+ end.compact
244
+
245
+ # multiple limits can reference the same metric
246
+ # multiple pricing rules can reference the same metric
247
+ uniq_metrics = limit_metrics.concat(pr_metrics).each_with_object({}) do |metric, acc|
248
+ acc[metric.enriched_key] = metric
249
+ end.values
250
+
251
+ uniq_metrics.map { |metric| metric.to_hash }
252
+ end
253
+
254
+ def uniq_methods_to_hash
255
+ limit_methods = limits.flat_map do |limit|
256
+ # one of them (or both) could be nil
257
+ [
258
+ limit.product_method, limit.backend_method
259
+ ]
260
+ end.compact
261
+
262
+ pr_methods = pricing_rules.flat_map do |pr|
263
+ # one of them (or both) could be nil
264
+ [
265
+ pr.product_method, pr.backend_method
266
+ ]
267
+ end.compact
268
+
269
+ # multiple limits can reference the same method
270
+ # multiple pricing rules can reference the same method
271
+ uniq_methods = limit_methods.concat(pr_methods).each_with_object({}) do |method, acc|
272
+ acc[method.enriched_key] = method
273
+ end.values
274
+
275
+ uniq_methods.map { |method| method.to_hash }
276
+ end
277
+
214
278
  def read_plan_attrs
215
279
  raise ThreeScaleToolbox::InvalidIdError if id.zero?
216
280
 
@@ -161,6 +161,10 @@ module ThreeScaleToolbox
161
161
  remote.http_client.endpoint == other.remote.http_client.endpoint && id == other.id
162
162
  end
163
163
 
164
+ def find_metric_or_method(system_name)
165
+ (metrics + methods).find { |m| m.system_name == system_name }
166
+ end
167
+
164
168
  private
165
169
 
166
170
  def metrics_and_methods
@@ -6,6 +6,8 @@ module ThreeScaleToolbox
6
6
  VALID_PARAMS = %w[friendly_name system_name description].freeze
7
7
  public_constant :VALID_PARAMS
8
8
 
9
+ METHOD_BLACKLIST = %w[id links created_at updated_at parent_id].freeze
10
+
9
11
  class << self
10
12
  def create(backend:, attrs:)
11
13
  method = backend.remote.create_backend_method(backend.id, backend.hits.id,
@@ -71,6 +73,20 @@ module ThreeScaleToolbox
71
73
  remote.delete_backend_method backend.id, hits_id, id
72
74
  end
73
75
 
76
+ # enriched_key returns a metric key that will be unique for all
77
+ # metrics/methods from products and backends
78
+ def enriched_key
79
+ "backend.#{backend.id}.#{id}"
80
+ end
81
+
82
+ def to_hash
83
+ extra_attrs = {
84
+ 'backend_system_name' => backend.system_name
85
+ }
86
+
87
+ attrs.merge(extra_attrs).reject { |key, _| METHOD_BLACKLIST.include? key }
88
+ end
89
+
74
90
  private
75
91
 
76
92
  def hits_id
@@ -6,6 +6,8 @@ module ThreeScaleToolbox
6
6
  VALID_PARAMS = %w[friendly_name system_name unit description].freeze
7
7
  public_constant :VALID_PARAMS
8
8
 
9
+ METRIC_BLACKLIST = %w[id links created_at updated_at].freeze
10
+
9
11
  class << self
10
12
  def create(backend:, attrs:)
11
13
  metric = backend.remote.create_backend_metric(backend.id,
@@ -74,6 +76,20 @@ module ThreeScaleToolbox
74
76
  remote.delete_backend_metric backend.id, id
75
77
  end
76
78
 
79
+ # enriched_key returns a metric key that will be unique for all
80
+ # metrics from products and backends
81
+ def enriched_key
82
+ "backend.#{backend.id}.#{id}"
83
+ end
84
+
85
+ def to_hash
86
+ extra_attrs = {
87
+ 'backend_system_name' => backend.system_name
88
+ }
89
+
90
+ attrs.merge(extra_attrs).reject { |key, _| METRIC_BLACKLIST.include? key }
91
+ end
92
+
77
93
  private
78
94
 
79
95
  def process_attrs(metric_attrs)