diff --git a/engines/instance_verification/lib/instance_verification/engine.rb b/engines/instance_verification/lib/instance_verification/engine.rb index 45438e3f0..546fce6b9 100644 --- a/engines/instance_verification/lib/instance_verification/engine.rb +++ b/engines/instance_verification/lib/instance_verification/engine.rb @@ -53,6 +53,35 @@ def find_product product end + def find_subscription(base_product, logger, request) + # this method is needed because + # https://bugzilla.suse.com/show_bug.cgi?id=1236816 + # https://bugzilla.suse.com/show_bug.cgi?id=1236836 + product_hash = { + identifier: base_product.identifier, + version: base_product.version, + arch: base_product.arch, + release_type: base_product.release_type + } + add_on_product_class = InstanceVerification.provider.new( + logger, + request, + product_hash, + @system.instance_data + ).add_on + # add_on_product_class, if present, is the real product class + # i.e. in the case of SUMA, it would be SUMA product class + # not the SUMA base product's product class (Micro) + product_class = add_on_product_class.presence || base_product.product_class + # it returns the first subscription that matches + # even if there are more subscriptions that match + Subscription.joins(:product_classes).find_by( + subscription_product_classes: { + product_class: product_class + } + ) + end + def verify_product_activation product = find_product @@ -83,12 +112,7 @@ def verify_payg_extension_activation!(product) return if product.free? base_product = @system.products.find_by(product_type: :base) - subscription = Subscription.joins(:product_classes).find_by( - subscription_product_classes: { - product_class: base_product.product_class - } - ) - + subscription = find_subscription(base_product, logger, request) # This error would occur only if there's a problem with subscription setup on SCC side raise InstanceVerification::Exception, "Can't find a subscription for base product #{base_product.product_string}" unless subscription @@ -122,7 +146,8 @@ def verify_base_product_upgrade activated_bases = @system.products.where(product_type: 'base') activated_bases.each do |base_product| - return true if (base_product.identifier == upgrade_product.identifier) + base_product_subscription = find_subscription(base_product, logger, request) + return true if base_product_subscription && base_product_subscription.products.include?(upgrade_product) end raise ActionController::TranslatedError.new('Migration target not allowed on this instance type') diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb index e4379c39b..b83aab501 100644 --- a/engines/instance_verification/lib/instance_verification/providers/example.rb +++ b/engines/instance_verification/lib/instance_verification/providers/example.rb @@ -55,4 +55,10 @@ def allowed_extension? # to be activated on SCC or not, i.e. LTSS in Azure Basic VM true end + + def add_on + # method to check if a system has an add on product + # based on the system metadata + # and if so, it returns its real product class + end end diff --git a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb index 7256bf256..6ae99686c 100644 --- a/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb +++ b/engines/instance_verification/spec/requests/api/connect/v3/systems/products_controller_spec.rb @@ -237,6 +237,7 @@ allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) allow(plugin_double).to receive(:allowed_extension?).and_return(true) + allow(plugin_double).to receive(:add_on).and_return(nil) FactoryBot.create(:subscription, product_classes: product_classes) stub_request(:post, scc_activate_url) @@ -532,6 +533,7 @@ .and_return(plugin_double) allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' }) allow(plugin_double).to receive(:allowed_extension?).and_return(true) + allow(plugin_double).to receive(:add_on).and_return(nil) FactoryBot.create(:subscription, product_classes: product_classes) stub_request(:post, scc_activate_url) @@ -598,18 +600,24 @@ 'User-Agent' => 'Ruby' } end + let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') } context 'when SCC upgrade success' do - before do - stub_request(:put, scc_systems_products_url) - .with({ headers: scc_headers, body: payload.merge({ byos_mode: 'byos' }) }) - .and_return(status: 201, body: '', headers: {}) - request - end + let(:fake_subscription) { instance_double(Subscription, id: 1, products: [new_product]) } context "when migration target base product doesn't have an activated successor/predecessor" do let(:new_product) { FactoryBot.create(:product, :with_mirrored_repositories) } + before do + allow(InstanceVerification::Providers::Example).to receive(:new) + .and_return(plugin_double) + allow(plugin_double).to receive(:add_on).and_return('foo') + stub_request(:put, scc_systems_products_url) + .with({ headers: scc_headers, body: payload.merge({ byos_mode: 'byos' }) }) + .and_return(status: 201, body: '', headers: {}) + request + end + it 'HTTP response code is 422' do expect(response).to have_http_status(422) end @@ -628,6 +636,17 @@ ) end + before do + allow(InstanceVerification::Providers::Example).to receive(:new) + .and_return(plugin_double) + allow(plugin_double).to receive(:add_on).and_return('foo') + allow_any_instance_of(described_class).to receive(:find_subscription).and_return(fake_subscription) + stub_request(:put, scc_systems_products_url) + .with({ headers: scc_headers, body: payload.merge({ byos_mode: 'byos' }) }) + .and_return(status: 201, body: '', headers: {}) + request + end + it 'HTTP response code is 201' do expect(response).to have_http_status(201) end @@ -648,12 +667,13 @@ body: 'Migration target not allowed on this instance type', headers: {} ) - request end context "when migration target base product doesn't have an activated successor/predecessor" do let(:new_product) { FactoryBot.create(:product, :with_mirrored_repositories) } + before { request } + it 'HTTP response code is 422' do expect(response).to have_http_status(422) end @@ -671,8 +691,15 @@ version: '999', predecessors: [ old_product ] ) end + let(:fake_subscription) { instance_double(Subscription, id: 1, products: [new_product]) } + + before do + allow_any_instance_of(described_class).to receive(:find_subscription).and_return(fake_subscription) + request + end it 'HTTP response code is 422' do + # problem here expect(response).to have_http_status(422) end @@ -695,11 +722,11 @@ } end - before { request } - context "when migration target base product doesn't have an activated successor/predecessor" do let(:new_product) { FactoryBot.create(:product, :with_mirrored_repositories) } + before { request } + it 'HTTP response code is 422' do expect(response).to have_http_status(422) end @@ -718,6 +745,8 @@ ) end + before { request } + it 'HTTP response code is 422' do expect(response).to have_http_status(422) end @@ -735,6 +764,13 @@ version: '999', predecessors: [ old_product ] ) end + let(:fake_subscription) { instance_double(Subscription, id: 1, products: [new_product]) } + + before do + allow_any_instance_of(described_class).to receive(:find_subscription).and_return(fake_subscription) + + request + end it 'HTTP response code is 201' do expect(response).to have_http_status(201)