3scale_toolbox 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -1
  3. data/lib/3scale_toolbox/cli/error_handler.rb +0 -2
  4. data/lib/3scale_toolbox/commands/3scale_command.rb +0 -4
  5. data/lib/3scale_toolbox/commands/copy_command/copy_service.rb +5 -4
  6. data/lib/3scale_toolbox/commands/copy_command.rb +0 -2
  7. data/lib/3scale_toolbox/commands/help_command.rb +0 -3
  8. data/lib/3scale_toolbox/commands/import_command/import_csv.rb +0 -6
  9. data/lib/3scale_toolbox/commands/import_command/openapi/create_activedocs_step.rb +39 -2
  10. data/lib/3scale_toolbox/commands/import_command/openapi/create_method_step.rb +1 -1
  11. data/lib/3scale_toolbox/commands/import_command/openapi/create_service_step.rb +5 -16
  12. data/lib/3scale_toolbox/commands/import_command/openapi/mapping_rule.rb +11 -1
  13. data/lib/3scale_toolbox/commands/import_command/openapi/step.rb +4 -3
  14. data/lib/3scale_toolbox/commands/import_command/openapi/threescale_api_spec.rb +13 -2
  15. data/lib/3scale_toolbox/commands/import_command/openapi/update_policies_step.rb +63 -14
  16. data/lib/3scale_toolbox/commands/import_command/openapi/update_service_proxy_step.rb +6 -3
  17. data/lib/3scale_toolbox/commands/import_command/openapi.rb +11 -5
  18. data/lib/3scale_toolbox/commands/import_command.rb +0 -2
  19. data/lib/3scale_toolbox/commands/plans_command/apply_command.rb +136 -0
  20. data/lib/3scale_toolbox/commands/plans_command/create_command.rb +100 -0
  21. data/lib/3scale_toolbox/commands/plans_command/delete_command.rb +66 -0
  22. data/lib/3scale_toolbox/commands/plans_command/export/read_app_plan_step.rb +16 -0
  23. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_features_step.rb +16 -0
  24. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_limits_step.rb +19 -0
  25. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_methods_step.rb +50 -0
  26. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_metrics_step.rb +49 -0
  27. data/lib/3scale_toolbox/commands/plans_command/export/read_plan_pricing_rules_step.rb +19 -0
  28. data/lib/3scale_toolbox/commands/plans_command/export/step.rb +95 -0
  29. data/lib/3scale_toolbox/commands/plans_command/export/write_artifacts_file_step.rb +84 -0
  30. data/lib/3scale_toolbox/commands/plans_command/export_command.rb +65 -0
  31. data/lib/3scale_toolbox/commands/plans_command/import/create_or_update_app_plan_step.rb +33 -0
  32. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_features_step.rb +45 -0
  33. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_limits_step.rb +41 -0
  34. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_metrics_step.rb +57 -0
  35. data/lib/3scale_toolbox/commands/plans_command/import/import_plan_pricing_rules_step.rb +39 -0
  36. data/lib/3scale_toolbox/commands/plans_command/import/step.rb +129 -0
  37. data/lib/3scale_toolbox/commands/plans_command/import_command.rb +62 -0
  38. data/lib/3scale_toolbox/commands/plans_command/list_command.rb +63 -0
  39. data/lib/3scale_toolbox/commands/plans_command/show_command.rb +81 -0
  40. data/lib/3scale_toolbox/commands/plans_command.rb +34 -0
  41. data/lib/3scale_toolbox/commands/remote_command.rb +0 -3
  42. data/lib/3scale_toolbox/commands/update_command/update_service.rb +5 -4
  43. data/lib/3scale_toolbox/commands/update_command.rb +0 -2
  44. data/lib/3scale_toolbox/commands.rb +3 -1
  45. data/lib/3scale_toolbox/entities/application_plan.rb +150 -0
  46. data/lib/3scale_toolbox/entities/service.rb +25 -12
  47. data/lib/3scale_toolbox/entities.rb +1 -0
  48. data/lib/3scale_toolbox/helper.rb +41 -0
  49. data/lib/3scale_toolbox/resource_reader.rb +42 -0
  50. data/lib/3scale_toolbox/tasks/copy_app_plans_task.rb +1 -1
  51. data/lib/3scale_toolbox/tasks/copy_limits_task.rb +8 -11
  52. data/lib/3scale_toolbox/tasks/copy_pricingrules_task.rb +5 -3
  53. data/lib/3scale_toolbox/version.rb +1 -1
  54. data/lib/3scale_toolbox.rb +10 -0
  55. metadata +28 -5
  56. data/lib/3scale_toolbox/commands/import_command/openapi/resource_reader.rb +0 -51
@@ -0,0 +1,100 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Create
5
+ class CreateSubcommand < Cri::CommandRunner
6
+ include ThreeScaleToolbox::Command
7
+
8
+ def self.command
9
+ Cri::Command.define do
10
+ name 'create'
11
+ usage 'create [opts] <remote> <service> <plan_name>'
12
+ summary 'create application plan'
13
+ description 'Create application plan'
14
+
15
+ option :t, 'system-name', 'Application plan system name', argument: :required
16
+ flag nil, :default, 'Make default application plan'
17
+ flag nil, :disabled, 'Disables all methods and metrics in this application plan'
18
+ flag :p, :publish, 'Publish application plan'
19
+ option nil, 'approval-required', 'Applications require approval. true or false', argument: :required, transform: ThreeScaleToolbox::Helper::BooleanTransformer.new
20
+ option nil, 'cost-per-month', 'Cost per month', argument: :required, transform: method(:Integer)
21
+ option nil, 'setup-fee', 'Setup fee', argument: :required, transform: method(:Integer)
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
+ param :remote
25
+ param :service_ref
26
+ param :plan_name
27
+
28
+ runner CreateSubcommand
29
+ end
30
+ end
31
+
32
+ def run
33
+ plan = create_application_plan
34
+ plan.make_default if option_default
35
+ plan.disable if option_disabled
36
+ puts "Created application plan id: #{plan.id}. Default: #{option_default}; Disabled: #{option_disabled}"
37
+ end
38
+
39
+ private
40
+
41
+ def create_application_plan
42
+ ThreeScaleToolbox::Entities::ApplicationPlan.create(
43
+ service: service,
44
+ plan_attrs: plan_attrs
45
+ )
46
+ end
47
+
48
+ def plan_attrs
49
+ plan_basic_attrs.tap do |params|
50
+ params['state'] = 'published' if option_publish
51
+ end
52
+ end
53
+
54
+ def plan_basic_attrs
55
+ {
56
+ 'name' => arguments[:plan_name],
57
+ 'system_name' => options[:'system-name'],
58
+ 'approval_required' => options[:'approval-required'],
59
+ 'end_user_required' => options[:'end-user-required'],
60
+ 'cost_per_month' => options[:'cost-per-month'],
61
+ 'setup_fee' => options[:'setup-fee'],
62
+ 'trial_period_days' => options[:'trial-period-days']
63
+ }.compact
64
+ end
65
+
66
+ def option_default
67
+ !options[:default].nil?
68
+ end
69
+
70
+ def option_disabled
71
+ !options[:disabled].nil?
72
+ end
73
+
74
+ def option_publish
75
+ !options[:publish].nil?
76
+ end
77
+
78
+ def service
79
+ @service ||= find_service
80
+ end
81
+
82
+ def find_service
83
+ Entities::Service.find(remote: remote,
84
+ ref: service_ref).tap do |svc|
85
+ raise ThreeScaleToolbox::Error, "Service #{service_ref} does not exist" if svc.nil?
86
+ end
87
+ end
88
+
89
+ def remote
90
+ @remote ||= threescale_client(arguments[:remote])
91
+ end
92
+
93
+ def service_ref
94
+ arguments[:service_ref]
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,66 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Delete
5
+ class DeleteSubcommand < Cri::CommandRunner
6
+ include ThreeScaleToolbox::Command
7
+
8
+ def self.command
9
+ Cri::Command.define do
10
+ name 'delete'
11
+ usage 'delete [opts] <remote> <service> <plan>'
12
+ summary 'delete application plan'
13
+ description 'Delete application plan'
14
+
15
+ param :remote
16
+ param :service_ref
17
+ param :plan_ref
18
+
19
+ runner DeleteSubcommand
20
+ end
21
+ end
22
+
23
+ def run
24
+ plan.delete
25
+ puts "Application plan id: #{plan.id} deleted"
26
+ end
27
+
28
+ private
29
+
30
+ def service
31
+ @service ||= find_service
32
+ end
33
+
34
+ def plan
35
+ @plan ||= find_plan
36
+ end
37
+
38
+ def find_service
39
+ Entities::Service.find(remote: remote,
40
+ ref: service_ref).tap do |svc|
41
+ raise ThreeScaleToolbox::Error, "Service #{service_ref} does not exist" if svc.nil?
42
+ end
43
+ end
44
+
45
+ def find_plan
46
+ Entities::ApplicationPlan.find(service: service, ref: plan_ref).tap do |p|
47
+ raise ThreeScaleToolbox::Error, "Application plan #{plan_ref} does not exist" if p.nil?
48
+ end
49
+ end
50
+
51
+ def remote
52
+ @remote ||= threescale_client(arguments[:remote])
53
+ end
54
+
55
+ def service_ref
56
+ arguments[:service_ref]
57
+ end
58
+
59
+ def plan_ref
60
+ arguments[:plan_ref]
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadAppPlanStep
6
+ include Step
7
+ ##
8
+ # Reads Application plan
9
+ def call
10
+ result[:plan] = plan.show
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadPlanFeaturesStep
6
+ include Step
7
+ ##
8
+ # Reads Application Plan features
9
+ def call
10
+ result[:plan_features] = plan.features
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadPlanLimitsStep
6
+ include Step
7
+ ##
8
+ # Reads Application Plan limits
9
+ # add metric system_name out of metric_id
10
+ def call
11
+ result[:limits] = plan.limits.map do |limit|
12
+ limit.tap { |l| l['metric'] = metric_info(l, 'Limit') }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadPlanMethods
6
+ include Step
7
+ ##
8
+ # Compute unique list of methods from limits and pricingrules
9
+ def call
10
+ methods = [
11
+ limit_methods,
12
+ pricingrule_methods
13
+ ]
14
+ result[:plan_methods] = methods.each_with_object({}) { |elem, acc| acc.merge!(elem) }
15
+ end
16
+
17
+ private
18
+
19
+ def limit_methods
20
+ # multiple limits can reference the same method
21
+ filtered_limit_methods.each_with_object({}) do |elem, acc|
22
+ # find_method should not return nil.
23
+ # It is assumed that metric_id refers to existing element from previous steps
24
+ acc[elem['metric_id']] = find_method(elem['metric_id'])
25
+ end
26
+ end
27
+
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
+ result[:limits].select { |limit| limit.dig('metric', 'type') == 'method' }
32
+ end
33
+
34
+ def pricingrule_methods
35
+ filtered_pricing_rule_methods.each_with_object({}) do |elem, acc|
36
+ # find_method should not return nil.
37
+ # It is assumed that metric_id refers to existing element from previous steps
38
+ acc[elem['metric_id']] = find_method(elem['metric_id'])
39
+ end
40
+ end
41
+
42
+ def filtered_pricing_rule_methods
43
+ # looking up in metrics list does not work. Metric list includes methods and metrics
44
+ result[:pricingrules].select { |limit| limit.dig('metric', 'type') == 'method' }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,49 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadPlanMetrics
6
+ include Step
7
+ ##
8
+ # Compute unique list of metrics limits and pricingrules
9
+ def call
10
+ all_metrics = [
11
+ limit_metrics,
12
+ pricingrule_metrics
13
+ ]
14
+ result[:plan_metrics] = all_metrics.each_with_object({}) { |elem, acc| acc.merge!(elem) }
15
+ end
16
+
17
+ private
18
+
19
+ def limit_metrics
20
+ # multiple limits can reference the same metric
21
+ filtered_limit_metrics.each_with_object({}) do |elem, acc|
22
+ # find_metric should not return nil.
23
+ # It is assumed that metric_id refers to existing element from previous steps
24
+ acc[elem['metric_id']] = find_metric(elem['metric_id'])
25
+ end
26
+ end
27
+
28
+ def filtered_limit_metrics
29
+ # looking up in metrics list does not work. Metric list includes methods and metrics
30
+ result[:limits].select { |limit| limit.dig('metric', 'type') == 'metric' }
31
+ end
32
+
33
+ def pricingrule_metrics
34
+ filtered_pricing_rule_metrics.each_with_object({}) do |elem, acc|
35
+ # find_metric should not return nil.
36
+ # It is assumed that metric_id refers to existing element from previous steps
37
+ acc[elem['metric_id']] = find_metric(elem['metric_id'])
38
+ end
39
+ end
40
+
41
+ def filtered_pricing_rule_metrics
42
+ # looking up in metrics list does not work. Metric list includes methods and metrics
43
+ result[:pricingrules].select { |limit| limit.dig('metric', 'type') == 'metric' }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class ReadPlanPricingRulesStep
6
+ include Step
7
+ ##
8
+ # Reads Application Plan pricing rules
9
+ # add metric system_name out of metric_id
10
+ def call
11
+ result[:pricingrules] = plan.pricing_rules.map do |pr|
12
+ pr.tap { |e| e['metric'] = metric_info(e, 'PricingRule') }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,95 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ APP_PLANS_BLACKLIST = %w[id links default custom created_at updated_at].freeze
6
+ LIMITS_BLACKLIST = %w[id metric_id links created_at updated_at].freeze
7
+ PRICINGRULES_BLACKLIST = %w[id metric_id links created_at updated_at].freeze
8
+ PLAN_FEATURE_BLACKLIST = %w[id links created_at updated_at].freeze
9
+ METRIC_BLACKLIST = %w[id links created_at updated_at].freeze
10
+
11
+ module Step
12
+ attr_reader :context
13
+
14
+ def initialize(context)
15
+ @context = context
16
+ end
17
+
18
+ def service
19
+ context[:service] ||= find_service
20
+ end
21
+
22
+ def file
23
+ context[:file]
24
+ end
25
+
26
+ def threescale_client
27
+ context[:threescale_client]
28
+ end
29
+
30
+ # can be id or system_name
31
+ def service_system_name
32
+ context[:service_system_name]
33
+ end
34
+
35
+ # can be id or system_name
36
+ def plan_system_name
37
+ context[:plan_system_name]
38
+ end
39
+
40
+ def result
41
+ context[:result] ||= {}
42
+ end
43
+
44
+ def plan
45
+ context[:plan] ||= find_plan
46
+ end
47
+
48
+ def service_metrics
49
+ context[:service_metrics] ||= service.metrics
50
+ end
51
+
52
+ def service_methods
53
+ context[:service_methods] ||= service.methods
54
+ end
55
+
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
+ if (method = find_method(elem.fetch('metric_id')))
60
+ { 'type' => 'method', 'system_name' => method.fetch('system_name') }
61
+ elsif (metric = find_metric(elem.fetch('metric_id')))
62
+ { 'type' => 'metric', 'system_name' => metric.fetch('system_name') }
63
+ else
64
+ raise ThreeScaleToolbox::Error, "Unexpected error. #{elem_name} #{elem['id']} " \
65
+ "referencing to metric id #{elem.fetch('metric_id')} which has not been found"
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def find_service
72
+ Entities::Service.find(remote: threescale_client,
73
+ ref: service_system_name).tap do |svc|
74
+ raise ThreeScaleToolbox::Error, "Service #{service_system_name} does not exist" if svc.nil?
75
+ end
76
+ end
77
+
78
+ def find_plan
79
+ Entities::ApplicationPlan.find(service: service, ref: plan_system_name).tap do |p|
80
+ raise ThreeScaleToolbox::Error, "Application plan #{plan_system_name} does not exist" if p.nil?
81
+ end
82
+ end
83
+
84
+ def find_metric(id)
85
+ service_metrics.find { |metric| metric['id'] == id }
86
+ end
87
+
88
+ def find_method(id)
89
+ service_methods.find { |method| method['id'] == id }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,84 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Export
5
+ class WriteArtifactsStep
6
+ include Step
7
+ ##
8
+ # Serialization of Application Plan objects
9
+ def call
10
+ select_output do |output|
11
+ output.write(serialized_object.to_yaml)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def select_output
18
+ ios = if file
19
+ File.open(file, 'w')
20
+ else
21
+ $stdout
22
+ end
23
+ begin
24
+ yield(ios)
25
+ ensure
26
+ ios.close
27
+ end
28
+ end
29
+
30
+ def serialized_object
31
+ {
32
+ 'plan' => serialized_plan,
33
+ 'limits' => serialized_limits,
34
+ 'pricingrules' => serialized_pricing_rules,
35
+ 'plan_features' => serialized_plan_features,
36
+ 'metrics' => serialized_metrics,
37
+ 'methods' => serialized_methods,
38
+ 'created_at' => Time.now.utc.iso8601,
39
+ 'toolbox_version' => ThreeScaleToolbox::VERSION
40
+ }
41
+ end
42
+
43
+ def serialized_plan
44
+ result[:plan].reject { |key, _| APP_PLANS_BLACKLIST.include? key }
45
+ end
46
+
47
+ def serialized_limits
48
+ result[:limits].map do |limit|
49
+ metric = limit.delete('metric')
50
+ limit['metric_system_name'] = metric['system_name']
51
+ limit.reject { |key, _| LIMITS_BLACKLIST.include? key }
52
+ end
53
+ end
54
+
55
+ def serialized_pricing_rules
56
+ result[:pricingrules].map do |pr|
57
+ metric = pr.delete('metric')
58
+ pr['metric_system_name'] = metric['system_name']
59
+ pr.reject { |key, _| PRICINGRULES_BLACKLIST.include? key }
60
+ end
61
+ end
62
+
63
+ def serialized_plan_features
64
+ result[:plan_features].map do |pr|
65
+ pr.reject { |key, _| PLAN_FEATURE_BLACKLIST.include? key }
66
+ end
67
+ end
68
+
69
+ def serialized_metrics
70
+ result[:plan_metrics].values.map do |metric|
71
+ metric.reject { |key, _| METRIC_BLACKLIST.include? key }
72
+ end
73
+ end
74
+
75
+ def serialized_methods
76
+ result[:plan_methods].values.map do |method|
77
+ method.reject { |key, _| METRIC_BLACKLIST.include? key }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,65 @@
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
+ module ThreeScaleToolbox
11
+ module Commands
12
+ module PlansCommand
13
+ module Export
14
+ class ExportSubcommand < Cri::CommandRunner
15
+ include ThreeScaleToolbox::Command
16
+
17
+ def self.command
18
+ Cri::Command.define do
19
+ name 'export'
20
+ usage 'export [opts] <remote> <service_system_name> <plan_system_name>'
21
+ summary 'export application plan'
22
+ description 'Export application plan, limits, pricing rules and features'
23
+
24
+ option :f, :file, 'Write to file instead of stdout', argument: :required
25
+ param :remote
26
+ param :service_system_name
27
+ param :plan_system_name
28
+
29
+ runner ExportSubcommand
30
+ end
31
+ end
32
+
33
+ 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)
45
+ end
46
+
47
+ private
48
+
49
+ def context
50
+ @context ||= create_context
51
+ end
52
+
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
+ }
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,33 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Import
5
+ class CreateOrUpdateAppPlanStep
6
+ include Step
7
+ ##
8
+ # Creates if it does not exist, updates otherwise
9
+ def call
10
+ plan_obj = Entities::ApplicationPlan.find(service: service, ref: plan_system_name)
11
+ if plan_obj.nil?
12
+ plan_obj = Entities::ApplicationPlan.create(service: service, plan_attrs: plan_attrs)
13
+ puts "Application plan created: #{plan_obj.id}"
14
+ else
15
+ res = plan_obj.update(plan_attrs)
16
+ if (errors = res['errors'])
17
+ raise ThreeScaleToolbox::Error, "Could not update application plan #{plan_system_name}. Errors: #{errors}"
18
+ end
19
+
20
+ puts "Application plan updated: #{plan_obj.id}"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def plan_attrs
27
+ resource_plan.merge('system_name' => plan_system_name)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ module ThreeScaleToolbox
2
+ module Commands
3
+ module PlansCommand
4
+ module Import
5
+ class ImportPlanFeaturesStep
6
+ include Step
7
+ ##
8
+ # Writes Plan features
9
+ def call
10
+ missing_features.each do |feature|
11
+ create_plan_feature(feature)
12
+ puts "Created plan feature: #{feature}"
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def missing_features
19
+ ThreeScaleToolbox::Helper.array_difference(resource_features, plan.features) do |a, b|
20
+ ThreeScaleToolbox::Helper.compare_hashes(a, b, ['system_name'])
21
+ end
22
+ end
23
+
24
+ def create_plan_feature(feature_attrs)
25
+ feature = find_feature_by_system_name(feature_attrs['system_name']) || create_service_feature(feature_attrs)
26
+
27
+ plan.create_feature(feature['id']).tap do |resp|
28
+ if (errors = resp['errors'])
29
+ raise ThreeScaleToolbox::Error, "Plan feature has not been created. #{errors}"
30
+ end
31
+ end
32
+ end
33
+
34
+ def create_service_feature(feature_attrs)
35
+ service.create_feature(feature_attrs).tap do |resp|
36
+ if (errors = resp['errors'])
37
+ raise ThreeScaleToolbox::Error, "Service feature has not been created. #{errors}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end