foreman_scc_manager 1.6.1 → 1.6.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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scc_accounts_controller.rb +17 -11
  3. data/app/lib/actions/scc_manager/subscribe_product.rb +1 -0
  4. data/app/lib/actions/scc_manager/sync.rb +1 -0
  5. data/app/lib/actions/scc_manager/sync_plan_account_repositories.rb +38 -0
  6. data/app/lib/actions/scc_manager/sync_repositories.rb +3 -2
  7. data/app/lib/scc_manager.rb +1 -0
  8. data/app/models/concerns/recurring_logic_extensions.rb +9 -0
  9. data/app/models/scc_account.rb +123 -1
  10. data/app/models/scc_account_sync_plan_task_group.rb +7 -0
  11. data/app/models/scc_product.rb +1 -0
  12. data/app/views/scc_account_sync_plan_task_groups/_scc_account_sync_plan_task_groups.html.erb +4 -0
  13. data/app/views/scc_accounts/_form.html.erb +4 -0
  14. data/config/routes.rb +1 -0
  15. data/db/migrate/20190417202427_add_recurring_sync.foreman_scc_manager.rb +26 -0
  16. data/lib/foreman_scc_manager/engine.rb +4 -0
  17. data/lib/foreman_scc_manager/version.rb +1 -1
  18. data/lib/tasks/rubocop.rake +32 -0
  19. data/lib/tasks/test.rake +26 -0
  20. data/test/features/data_products_page1.json +10468 -0
  21. data/test/features/data_products_page2.json +11277 -0
  22. data/test/features/data_subscriptions.json +88 -0
  23. data/test/features/sync_test.rb +141 -0
  24. data/test/fixtures/models/scc_accounts.yml +24 -0
  25. data/test/fixtures/models/scc_products.yml +21 -0
  26. data/test/models/scc_account_test.rb +74 -0
  27. data/test/models/scc_product_test.rb +32 -0
  28. data/test/support/fixtures_support.rb +12 -0
  29. data/test/test_plugin_helper.rb +54 -0
  30. metadata +43 -5
  31. data/lib/tasks/foreman_scc_manager_tasks.rake +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6322d1af0ee5027a7cdbdf56bf3b9e837dbd55e3f3a6bb1550ec3f9de9d08390
4
- data.tar.gz: 1ec9da3d0aa4e905906c0640f80eebf6c7b635565264ddcf455f9f2ee8912b4d
3
+ metadata.gz: 3107d456ab7e1c5f822a4cbd7bd7ab1892d9f44fbcceb8bd60ec0ffb0746a685
4
+ data.tar.gz: 4d048099707ca69af205df6ffa0dc31b178e96fcd4a817f4ec4106e6927b255d
5
5
  SHA512:
6
- metadata.gz: 3c52d141ba0f4f743fc24cf60f21a6fc2273f28025c87a571ead35981d97f525daaf6ac6c7d75baab784281ac1a44ffb0507b65d2f6c732239a945eb921cdae0
7
- data.tar.gz: ffd154f4d1d7783bfb339d1048958a76f23ea077560188d9a33919b41a7f4818dd554cea643ce7e686e3d23ae6ca0e5aea0473405c973bb40f27f1acd1e2f6c6
6
+ metadata.gz: ba3d694f7bdf5978877b7304b6d71a2a035bf58122ac7e1969914d4cd8b6a55adabd174965b10092b32986ec31d31f9e585f0d6a6ebf8045edae20305223538c
7
+ data.tar.gz: 998d9f9d79624bb1f42e69c8ad546d6dd1c309c373a9a5db11cf849da266ecf0e83d54b77a1e260476b40169d1183c600cafcef1bf99fb8854fc61a3594e783d
@@ -18,11 +18,10 @@ class SccAccountsController < ApplicationController
18
18
  # POST /scc_accounts
19
19
  def create
20
20
  @scc_account = SccAccount.new(scc_account_params)
21
- if @scc_account.save
22
- process_success
23
- else
24
- process_error
25
- end
21
+ @scc_account.save_with_logic!
22
+ process_success
23
+ rescue ActiveRecord::RecordInvalid
24
+ process_error
26
25
  end
27
26
 
28
27
  # GET /scc_accounts/1/edit
@@ -43,11 +42,10 @@ class SccAccountsController < ApplicationController
43
42
 
44
43
  # PATCH/PUT /scc_accounts/1
45
44
  def update
46
- if @scc_account.update(scc_account_params)
47
- process_success
48
- else
49
- process_error
50
- end
45
+ @scc_account.update_attributes_with_logic!(scc_account_params)
46
+ process_success
47
+ rescue ActiveRecord::RecordInvalid
48
+ process_error
51
49
  end
52
50
 
53
51
  # DELETE /scc_accounts/1
@@ -103,7 +101,15 @@ class SccAccountsController < ApplicationController
103
101
  # Only allow a trusted parameter "white list" through.
104
102
  def scc_account_params
105
103
  params[:scc_account].delete(:password) if params[:scc_account][:password].blank?
106
- params.require(:scc_account).permit(:name, :login, :password, :base_url, :organization_id)
104
+ params.require(:scc_account).permit(
105
+ :name,
106
+ :login,
107
+ :password,
108
+ :base_url,
109
+ :interval,
110
+ :sync_date,
111
+ :organization_id
112
+ )
107
113
  end
108
114
 
109
115
  def scc_bulk_subscribe_params
@@ -3,6 +3,7 @@ module Actions
3
3
  class SubscribeProduct < Actions::EntryAction
4
4
  def plan(scc_product)
5
5
  raise _('Product already subscribed!') if scc_product.product
6
+
6
7
  ::Foreman::Logging.logger('foreman_scc_manager')
7
8
  .info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
8
9
  sequence do
@@ -15,6 +15,7 @@ module Actions
15
15
  def finalize
16
16
  scc_account = SccAccount.find(input[:scc_account][:id])
17
17
  raise 'Updating failed' unless input[:repo_status] == 'SUCCESS' && input[:prod_status] == 'SUCCESS'
18
+
18
19
  scc_account.update! synced: Time.current
19
20
  end
20
21
 
@@ -0,0 +1,38 @@
1
+ module Actions
2
+ module SccManager
3
+ class SyncPlanAccountRepositories < Actions::EntryAction
4
+ include Actions::RecurringAction
5
+ def plan(scc_account)
6
+ add_missing_task_group(scc_account)
7
+ action_subject(scc_account)
8
+
9
+ User.as_anonymous_admin do
10
+ plan_action(::Actions::SccManager::SyncRepositories, scc_account)
11
+ plan_self(:sync_plan_name => scc_account.name)
12
+ end
13
+ end
14
+
15
+ def add_missing_task_group(sync_plan)
16
+ if sync_plan.task_group.nil?
17
+ sync_plan.task_group = ::SccAccountSyncPlanTaskGroup.create!
18
+ sync_plan.save!
19
+ end
20
+ task.add_missing_task_groups(sync_plan.task_group)
21
+ end
22
+
23
+ def rescue_strategy
24
+ # Dynflow::Action::Rescue::Skip
25
+ # REMOVEME
26
+ Dynflow::Action::Rescue::Fail
27
+ end
28
+
29
+ def humanized_name
30
+ if input.try(:[], :sync_plan_name)
31
+ _('Update SUSE repositories %s') % (input[:sync_plan_name] || _('Unknown'))
32
+ else
33
+ _('Update SUSE repositories')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -9,12 +9,13 @@ module Actions
9
9
  end
10
10
 
11
11
  def run
12
- output[:status] = 'SUCCESS'
12
+ output[:status] = 'IN PROGRESS'
13
13
  begin
14
14
  output[:data] = ::SccManager.get_scc_data(input[:base_url],
15
15
  '/connect/organizations/repositories',
16
16
  input[:login],
17
17
  input[:password])
18
+ output[:status] = 'SUCCESS'
18
19
  rescue StandardError
19
20
  output[:status] = 'FAILURE'
20
21
  end
@@ -37,7 +38,7 @@ module Actions
37
38
  end
38
39
 
39
40
  def humanized_output
40
- output.dup.update(data: 'Trimmed')
41
+ output.dup.update(data: "Trimmed (got #{output[:data]&.length} repositories")
41
42
  end
42
43
  end
43
44
  end
@@ -21,6 +21,7 @@ module SccManager
21
21
  loop do
22
22
  response = RestClient.get url, auth_header
23
23
  raise 'Connection to SUSE costomer center failed.' unless response.code == 200
24
+
24
25
  links = (response.headers[:link] || '').split(', ').map do |link|
25
26
  href, rel = /<(.*?)>; rel="(\w+)"/.match(link).captures
26
27
  [rel.to_sym, href]
@@ -0,0 +1,9 @@
1
+ module Concerns
2
+ module RecurringLogicExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_one :scc_account, :inverse_of => :foreman_tasks_recurring_logic, :class_name => 'SccAccount'
7
+ end
8
+ end
9
+ end
@@ -4,12 +4,20 @@ class SccAccount < ApplicationRecord
4
4
  include ForemanTasks::Concerns::ActionSubject
5
5
  encrypts :password
6
6
 
7
+ NEVER = 'never'.freeze
8
+ DAILY = 'daily'.freeze
9
+ WEEKLY = 'weekly'.freeze
10
+ MONTHLY = 'monthly'.freeze
11
+ TYPES = [NEVER, DAILY, WEEKLY, MONTHLY].freeze
12
+
7
13
  self.include_root_in_json = false
8
14
 
9
15
  belongs_to :organization
10
16
  belongs_to :sync_task, class_name: 'ForemanTasks::Task'
11
17
  has_many :scc_products, dependent: :destroy
12
18
  has_many :scc_repositories, dependent: :destroy
19
+ belongs_to :foreman_tasks_recurring_logic, :inverse_of => :scc_account, :class_name => 'ForemanTasks::RecurringLogic', :dependent => :destroy
20
+ belongs_to :task_group, :class_name => 'SccAccountSyncPlanTaskGroup', :inverse_of => :scc_account
13
21
 
14
22
  validates_lengths_from_database
15
23
  validates :name, presence: true
@@ -17,11 +25,30 @@ class SccAccount < ApplicationRecord
17
25
  validates :login, presence: true
18
26
  validates :password, presence: true
19
27
  validates :base_url, presence: true
28
+ validates :interval, :inclusion => { :in => TYPES }, :allow_blank => false
29
+ validate :sync_date_is_valid_datetime
30
+
31
+ after_initialize :init
32
+ before_destroy :cancel_recurring_logic
20
33
 
21
34
  default_scope -> { order(:login) }
22
35
 
23
36
  scoped_search on: :login, complete_value: true
24
37
 
38
+ def init
39
+ # set default values
40
+ self.sync_date ||= Time.new if self.new_record?
41
+ end
42
+
43
+ def sync_date_is_valid_datetime
44
+ errors.add(:sync_date, 'must be a valid datetime') if interval != NEVER &&
45
+ sync_date.present? &&
46
+ !sync_date.respond_to?(:min) &&
47
+ !sync_date.respond_to?(:hour) &&
48
+ !sync_date.respond_to?(:wday) &&
49
+ !sync_date.respond_to?(:day)
50
+ end
51
+
25
52
  def to_s
26
53
  name
27
54
  end
@@ -40,8 +67,103 @@ class SccAccount < ApplicationRecord
40
67
  end
41
68
  end
42
69
 
70
+ def use_recurring_logic?
71
+ self.interval != NEVER
72
+ end
73
+
74
+ def save_with_logic!
75
+ self.task_group ||= SccAccountSyncPlanTaskGroup.create!
76
+
77
+ associate_recurring_logic if self.valid?
78
+
79
+ self.save!
80
+ start_recurring_logic if self.use_recurring_logic?
81
+
82
+ true
83
+ end
84
+
85
+ def update_attributes_with_logic!(params)
86
+ transaction do
87
+ self.update_attributes!(params)
88
+ if rec_logic_changed?
89
+ old_rec_logic = self.foreman_tasks_recurring_logic
90
+ associate_recurring_logic
91
+ self.save!
92
+ old_rec_logic&.cancel
93
+ # Can/Should we do that???
94
+ old_rec_logic&.destroy
95
+ start_recurring_logic
96
+ end
97
+ toggle_enabled if enabled_toggle?
98
+ end
99
+ true
100
+ end
101
+
102
+ def add_recurring_logic(sync_date, interval)
103
+ sd = sync_date
104
+
105
+ raise _('Interval cannot be nil') if interval.nil?
106
+
107
+ cron = case interval.downcase
108
+ when DAILY then "#{sd.min} #{sd.hour} * * *"
109
+ when WEEKLY then "#{sd.min} #{sd.hour} * * #{sd.wday}"
110
+ when MONTHLY then "#{sd.min} #{sd.hour} #{sd.day} * *"
111
+ else
112
+ raise _('Interval not set correctly')
113
+ end
114
+
115
+ recurring_logic = ForemanTasks::RecurringLogic.new_from_cronline(cron)
116
+
117
+ raise _('Cron expression is not valid!') unless recurring_logic.valid_cronline?
118
+
119
+ recurring_logic.save!
120
+ recurring_logic
121
+ end
122
+
123
+ def associate_recurring_logic
124
+ if self.use_recurring_logic?
125
+ self.foreman_tasks_recurring_logic = add_recurring_logic(self.sync_date, self.interval)
126
+ else
127
+ self.foreman_tasks_recurring_logic = nil
128
+ end
129
+ end
130
+
131
+ def toggle_enabled
132
+ self.foreman_tasks_recurring_logic&.enabled = self.enabled
133
+ end
134
+
135
+ def start_recurring_logic
136
+ # rubocop:disable Style/GuardClause
137
+ if self.use_recurring_logic?
138
+ User.as_anonymous_admin do
139
+ if self.sync_date.to_time < Time.now
140
+ self.foreman_tasks_recurring_logic.start(::Actions::SccManager::SyncPlanAccountRepositories, self)
141
+ else
142
+ self.foreman_tasks_recurring_logic.start_after(::Actions::SccManager::SyncPlanAccountRepositories, self.sync_date, self)
143
+ end
144
+ end
145
+ end
146
+ # rubocop:enable Style/GuardClause
147
+ end
148
+
149
+ def cancel_recurring_logic
150
+ self.foreman_tasks_recurring_logic&.cancel
151
+ end
152
+
153
+ def rec_logic_changed?
154
+ saved_change_to_attribute?(:sync_date) || saved_change_to_attribute?(:interval)
155
+ end
156
+
157
+ def enabled_toggle?
158
+ saved_change_to_attribute?(:enabled)
159
+ end
160
+
161
+ def get_scc_data(rel_url)
162
+ SccManager.get_scc_data(base_url, rel_url, login, password)
163
+ end
164
+
43
165
  def test_connection
44
- SccManager.get_scc_data(base_url, '/connect/organizations/subscriptions', login, password)
166
+ get_scc_data('/connect/organizations/subscriptions')
45
167
  true
46
168
  rescue StandardError
47
169
  false
@@ -0,0 +1,7 @@
1
+ class SccAccountSyncPlanTaskGroup < ::ForemanTasks::TaskGroup
2
+ has_one :scc_account, :foreign_key => :task_group_id, :dependent => :nullify, :inverse_of => :task_group, :class_name => 'SccAccount'
3
+
4
+ def resource_name
5
+ N_('SUSE Subscription')
6
+ end
7
+ end
@@ -26,6 +26,7 @@ class SccProduct < ApplicationRecord
26
26
 
27
27
  def subscribe
28
28
  raise 'Product already subscribed!' if product
29
+
29
30
  new_product = Katello::Product.new
30
31
  new_product.name = uniq_name
31
32
  new_product.description = description
@@ -0,0 +1,4 @@
1
+ <%= _("SUSE Subscription: ") %>
2
+
3
+ <%= link_to(task_groups.first.scc_account.name, "/scc_accounts/#{task_groups.first.scc_account.id}/edit") %>
4
+
@@ -13,6 +13,10 @@
13
13
  <%= text_f f, :login, :help_block => _("Use your 'Organization credentials' obtained from the SUSE Customer Center.") %>
14
14
  <%= password_f f, :password %>
15
15
  <%= text_f f, :base_url, label: _('Base URL') %>
16
+ <%= selectable_f f, :interval, SccAccount::TYPES, label: _('Interval') %>
17
+ <%= field f, :sync_date, label: _('Sync Date') do
18
+ f.datetime_field :sync_date, placeholder: Time.now
19
+ end %>
16
20
  <div class='clearfix'>
17
21
  <div class='form-group'>
18
22
  <div class='col-md-2'></div>
@@ -2,6 +2,7 @@ Rails.application.routes.draw do
2
2
  resources :scc_accounts do
3
3
  collection do
4
4
  put 'test_connection'
5
+ get 'auto_complete_search'
5
6
  end
6
7
  member do
7
8
  put 'sync'
@@ -0,0 +1,26 @@
1
+ class AddRecurringSync < ActiveRecord::Migration[5.2]
2
+ class FakeSccAccount < ApplicationRecord
3
+ self.table_name = 'scc_accounts'
4
+ end
5
+
6
+ def up
7
+ add_column :scc_accounts, :foreman_tasks_recurring_logic_id, :integer
8
+ add_column :scc_accounts, :interval, :string, default: 'never'
9
+ add_column :scc_accounts, :sync_date, :datetime
10
+ add_foreign_key :scc_accounts, :foreman_tasks_recurring_logics, :name => 'scc_accounts_foreman_tasks_recurring_logic_fk', :column => 'foreman_tasks_recurring_logic_id'
11
+ add_column :scc_accounts, :task_group_id, :integer, index: true
12
+ add_foreign_key :scc_accounts, :foreman_tasks_task_groups, column: :task_group_id
13
+ FakeSccAccount.all.each do |scca|
14
+ scca.task_group_id ||= SccAccountSyncPlanTaskGroup.create!.id
15
+ scca.save!
16
+ end
17
+ end
18
+
19
+ def down
20
+ remove_column :scc_accounts, :foreman_tasks_recurring_logic_id
21
+ remove_column :scc_accounts, :interval
22
+ remove_column :scc_accounts, :sync_date
23
+ remove_column :scc_accounts, :task_group_id
24
+ ForemanTasks::TaskGroup.where(:type => 'SccAccountSyncPlanTaskGroup').delete_all
25
+ end
26
+ end
@@ -9,6 +9,10 @@ module ForemanSccManager
9
9
  config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
10
10
  config.autoload_paths += Dir["#{config.root}/app/overrides"]
11
11
 
12
+ config.to_prepare do
13
+ ForemanTasks::RecurringLogic.send :include, Concerns::RecurringLogicExtensions
14
+ end
15
+
12
16
  # Add any db migrations
13
17
  initializer 'foreman_scc_manager.load_app_instance_data' do |app|
14
18
  ForemanSccManager::Engine.paths['db/migrate'].existent.each do |path|
@@ -1,3 +1,3 @@
1
1
  module ForemanSccManager
2
- VERSION = '1.6.1'.freeze
2
+ VERSION = '1.6.2'.freeze
3
3
  end
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'rubocop/rake_task'
3
+
4
+ test_patterns = [
5
+ "#{ForemanSccManager::Engine.root}/*.gemspec",
6
+ "#{ForemanSccManager::Engine.root}/*.rb",
7
+ "#{ForemanSccManager::Engine.root}/app/**/*.rb",
8
+ "#{ForemanSccManager::Engine.root}/config/**/*.rb",
9
+ "#{ForemanSccManager::Engine.root}/db/**/*.rb",
10
+ "#{ForemanSccManager::Engine.root}/lib/**/*.rake",
11
+ "#{ForemanSccManager::Engine.root}/lib/**/*.rb",
12
+ "#{ForemanSccManager::Engine.root}/locale/**/*.rb",
13
+ "#{ForemanSccManager::Engine.root}/test/**/*.rb"
14
+ ]
15
+
16
+ namespace :foreman_scc_manager do
17
+ desc 'Runs Rubocop style checker'
18
+ RuboCop::RakeTask.new(:rubocop) do |task|
19
+ task.patterns = test_patterns
20
+ end
21
+
22
+ desc 'Runs Rubocop style checker with xml output for Jenkins'
23
+ RuboCop::RakeTask.new('rubocop:jenkins') do |task|
24
+ task.patterns = test_patterns
25
+ task.requires = ['rubocop/formatter/checkstyle_formatter']
26
+ task.formatters = ['RuboCop::Formatter::CheckstyleFormatter']
27
+ task.options = ['--no-color', '--out', 'rubocop.xml']
28
+ end
29
+ end
30
+ rescue LoadError
31
+ puts 'Rubocop not loaded.'
32
+ end
@@ -0,0 +1,26 @@
1
+ require 'rake/testtask'
2
+
3
+ # Tests
4
+ namespace :test do
5
+ desc 'Test ForemanSccManager'
6
+ Rake::TestTask.new(:foreman_scc_manager) do |t|
7
+ test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
8
+ t.libs << ['test', test_dir]
9
+ t.pattern = "#{test_dir}/**/*_test.rb"
10
+ t.verbose = true
11
+ t.warning = false
12
+ end
13
+ end
14
+
15
+ namespace :jenkins do
16
+ desc 'Test ForemanSccManager with XML output for jenkins'
17
+ task 'foreman_scc_manager' do
18
+ Rake::Task['jenkins:setup:minitest'].invoke
19
+ Rake::Task['rake:test:foreman_scc_manager'].invoke
20
+ end
21
+ end
22
+
23
+ Rake::Task[:test].enhance ['test:foreman_scc_manager']
24
+
25
+ load 'tasks/jenkins.rake'
26
+ Rake::Task['jenkins:unit'].enhance ['test:foreman_scc_manager', 'foreman_scc_manager:rubocop'] if Rake::Task.task_defined?(:'jenkins:unit')