Skip to content

Commit

Permalink
Merge branch 'master' into fix-auth-repo
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusbv authored Jan 14, 2025
2 parents 3e31167 + 9444e3f commit f80bd2d
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 40 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ RSpec/MultipleExpectations:
Metrics/ClassLength:
Exclude:
- lib/rmt/downloader.rb
Max: 250

Naming/FileName:
Exclude:
Expand Down
2 changes: 1 addition & 1 deletion app/models/product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def self.recommended_extensions(root_product_ids)
joins(:product_extensions_associations).where(products_extensions: { recommended: true, root_product_id: root_product_ids })
end

def create_service!
def find_or_create_service!
service = Service.find_by(product_id: id)
return service if service

Expand Down
8 changes: 0 additions & 8 deletions app/models/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ class Repository < ApplicationRecord
validates :local_path, presence: true
validates :friendly_id, presence: true

before_destroy :ensure_destroy_possible

class << self

def remove_suse_repos_without_tokens!
Expand Down Expand Up @@ -70,10 +68,4 @@ def custom?
scc_id.nil?
end

private

def ensure_destroy_possible
throw(:abort) unless custom?
end

end
2 changes: 1 addition & 1 deletion app/services/repository_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class RepositoryService
class RepositoryNotFound < RuntimeError
end

def create_repository!(product, url, attributes, custom: false)
def update_or_create_repository!(product, url, attributes, custom: false)
repository = if custom
Repository.find_or_initialize_by(external_url: url)
else
Expand Down
2 changes: 0 additions & 2 deletions engines/scc_proxy/lib/scc_proxy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ def scc_upgrade(auth, product, system_login, mode, logger)
end
end

# rubocop:disable Metrics/ClassLength
class Engine < ::Rails::Engine
isolate_namespace SccProxy
config.generators.api_only = true
Expand Down Expand Up @@ -523,6 +522,5 @@ def get_system(systems)
end
end
end
# rubocop:enable Metrics/ClassLength
end
# rubocop:enable Metrics/ModuleLength
2 changes: 1 addition & 1 deletion lib/rmt/cli/repos_custom.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def add(url, name)
raise RMT::CLI::Error.new(_("Couldn't add custom repository."))
end

repository_service.create_repository!(nil, url, {
repository_service.update_or_create_repository!(nil, url, {
name: name.strip,
mirroring_enabled: true,
autorefresh: true,
Expand Down
36 changes: 33 additions & 3 deletions lib/rmt/scc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,32 @@ def sync
data.each { |item| create_product(item) }
data.each { |item| migration_paths(item) }

update_repositories(scc_api_client.list_repositories)
# Update repositories with details (eg. access token) from API
repositories_data = scc_api_client.list_repositories
update_repositories(repositories_data)

Repository.remove_suse_repos_without_tokens!
remove_obsolete_repositories(repositories_data)

update_subscriptions(scc_api_client.list_subscriptions)
end

def remove_obsolete_repositories(repos_data)
@logger.info _('Removing obsolete repositories')
return if repos_data.empty?

scc_repo_ids = repos_data.pluck(:id)


# Find repositories in RMT that no longer exist in SCC
# Only consider repositories that have a non-null scc_id
repos_to_remove = Repository.only_scc.where.not(scc_id: scc_repo_ids)
if repos_to_remove.any?
repos_to_remove.destroy_all
@logger.debug("Successfully removed #{repos_to_remove.count} obsolete repositories")
end
end

def export(path)
credentials_set? || (raise CredentialsError, 'SCC credentials not set.')

Expand Down Expand Up @@ -185,10 +204,21 @@ def create_product(item, root_product_id = nil, base_product = nil, recommended
end

def create_service(item, product)
product.create_service!
service = product.find_or_create_service!

item[:repositories].each do |repo_item|
repository_service.create_repository!(product, repo_item[:url], repo_item)
repository_service.update_or_create_repository!(product, repo_item[:url], repo_item)
end

# detect repositories removed from the product in SCC
removed_repos = service.repositories.only_scc.where.not(scc_id: item[:repositories].pluck(:id))
disassociate_repositories(service, removed_repos) if removed_repos.present?

end

def disassociate_repositories(service, repos)
service.repositories.delete(repos)
@logger.debug("Removed repositories #{repos.pluck(:scc_id)} from '#{service.product.friendly_name}'")
end

def migration_paths(item)
Expand Down
1 change: 1 addition & 0 deletions package/obs/rmt-server.changes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Mon Dec 23 14:07:00 UTC 2024 - Luís Caparroz <[email protected]>
* rmt-server-pubcloud:
* Update Micro check due to Micro 6.0 and 6.1 identifier to keep bsc#1230419 in place
* Update Zypper path allowing check to handle paid extensions (i.e. LTSS) (bsc#1230157)
* Remove obsolete repositories and associations from rmt during SCC sync (bsc#1232808)

-------------------------------------------------------------------
Mon Dec 23 08:03:56 UTC 2024 - Parag Jain <[email protected]>
Expand Down
2 changes: 1 addition & 1 deletion spec/factories/products.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@

trait :with_service do
after :create do |product, _evaluator|
product.create_service!
product.find_or_create_service!
end
end

Expand Down
7 changes: 7 additions & 0 deletions spec/factories/services.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,10 @@
end
end
end

FactoryBot.define do
factory :repositories_services_association do
association :repository
association :service
end
end
118 changes: 116 additions & 2 deletions spec/lib/rmt/scc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@

describe '#remove_suse_repos_without_tokens' do
let(:api_double) { double }
let!(:suse_repo_with_token) { FactoryBot.create(:repository, :with_products, auth_token: 'auth_token') }
let!(:suse_repo_with_token) { FactoryBot.create(:repository, :with_products, auth_token: 'auth_token', scc_id: 200000) }
let!(:suse_repo_without_token) do
FactoryBot.create(
:repository,
Expand All @@ -262,7 +262,8 @@
:with_products,
auth_token: nil,
external_url: 'https://installer-updates.suse.com/repos/not/updates',
installer_updates: true
installer_updates: true,
scc_id: 200001
)
end
let!(:custom_repo) do
Expand Down Expand Up @@ -314,6 +315,119 @@ def scc
end
end

describe '#remove_obsolete_repositories' do
let(:api_double) { instance_double 'SUSE::Connect::Api' }
let(:logger) { instance_double('RMT::Logger').as_null_object }
let!(:suse_repo_one) { create(:repository, :with_products, scc_id: 1) }
let!(:suse_repo_two) { create(:repository, :with_products, scc_id: 2) }
let!(:custom_repo) { create(:repository, :with_products, scc_id: nil) }

before do
allow(Settings).to receive(:scc).and_return OpenStruct.new(username: 'foo', password: 'bar')
allow(RMT::Logger).to receive(:new).and_return(logger)
end

context 'when repos_data is empty' do
it 'returns early and does not remove any repositories' do
expect(Repository).not_to receive(:only_scc)
described_class.new.remove_obsolete_repositories([])
expect(Repository.count).to eq(3)
end
end

context 'when repos_data contains all existing SCC repositories' do
let(:repos_data) do
[
{ id: suse_repo_one.scc_id },
{ id: suse_repo_two.scc_id }
]
end

it 'does not remove any repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.not_to change(Repository, :count)
end
end

context 'when repos_data is missing some existing SCC repositories' do
let(:repos_data) do
[
{ id: suse_repo_one.scc_id }
]
end

it 'removes only the obsolete SCC repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.to change(Repository, :count).by(-1)

expect(Repository.find_by(id: suse_repo_one.id)).to be_present
expect(Repository.find_by(id: suse_repo_two.id)).to be_nil
expect(Repository.find_by(id: custom_repo.id)).to be_present
end
end

context 'when repos_data does not contain any existing SCC repository IDs' do
let(:repos_data) do
[
{ id: 999 }
]
end

it 'removes all SCC repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.to change(Repository, :count).by(-2)

expect(Repository.find_by(id: suse_repo_one.id)).to be_nil
expect(Repository.find_by(id: suse_repo_two.id)).to be_nil
expect(Repository.find_by(id: custom_repo.id)).to be_present
end
end
end


describe '#disassociate_repositories' do
let(:logger) { instance_double('RMT::Logger').as_null_object }
let(:product) { create(:product) }
let(:service) { create(:service, product: product) }

before do
allow(RMT::Logger).to receive(:new).and_return(logger)
end

context 'when existing_repo_ids is empty' do
it 'does not remove any associations' do
expect { described_class.new.send(:disassociate_repositories, service, []) }.not_to change(RepositoriesServicesAssociation, :count)
end
end

context 'when existing_repo_ids contains repository IDs' do
let!(:repo_one) { create(:repository, :with_products, scc_id: 101) }
let!(:repo_two) { create(:repository, :with_products, scc_id: 102) }
let!(:repo_three) { create(:repository, :with_products, scc_id: 103) }
let(:existing_repo_ids) { [repo_one.scc_id, repo_two.scc_id] }

before do
# Associate repositories with the product through services
[repo_one, repo_two, repo_three].each do |repo|
create(:repositories_services_association,
repository: repo,
service: service)
end
end

it 'removes repository associations for the specified repo IDs' do
expect do
described_class.new.send(:disassociate_repositories, service, [repo_one, repo_two])
end.to change(RepositoriesServicesAssociation, :count).by(-2)
end

it 'only removes associations for specified repositories' do
described_class.new.send(:disassociate_repositories, service, [repo_one, repo_two])

expect(product.repositories).not_to include(repo_one)
expect(product.repositories).not_to include(repo_two)
expect(product.repositories).to include(repo_three)
end
end
end

describe '#export' do
let(:path) { '/tmp/usb' }

Expand Down
8 changes: 4 additions & 4 deletions spec/models/product_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,13 @@
end
end

describe '#create_service!' do
describe '#find_or_create_service!' do
context 'when service already exists' do
let!(:product) { create :product }
let!(:service) { create :service, product_id: product.id }

it 'returns the existing service' do
expect(product.create_service!).to eq(service)
expect(product.find_or_create_service!).to eq(service)
end
end

Expand All @@ -234,15 +234,15 @@
let!(:other_service) { create :service, id: product.id, product_id: other_product.id }

it 'creates a service with a random ID' do
expect(product.create_service!.id).not_to eq(other_service.id)
expect(product.find_or_create_service!.id).not_to eq(other_service.id)
end
end

context 'when the matching service ID is free' do
let!(:product) { create :product }

it 'creates a service with a matching ID' do
expect(product.create_service!.id).to eq(product.id)
expect(product.find_or_create_service!.id).to eq(product.id)
end
end
end
Expand Down
8 changes: 0 additions & 8 deletions spec/models/repository_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,6 @@
end

describe '#destroy' do
context 'when it is an official repository' do
subject { repository.destroy }

let!(:repository) { create :repository }

it { is_expected.to be_falsey }
end

context 'when it is a custom repository' do
subject { repository.destroy }

Expand Down
Loading

0 comments on commit f80bd2d

Please sign in to comment.