diff --git a/engines/instance_verification/lib/instance_verification/providers/example.rb b/engines/instance_verification/lib/instance_verification/providers/example.rb
index b773d7855..393236e4b 100644
--- a/engines/instance_verification/lib/instance_verification/providers/example.rb
+++ b/engines/instance_verification/lib/instance_verification/providers/example.rb
@@ -27,10 +27,6 @@ def validate_instance_data(_instance_data)
end
def parse_instance_data
- if @instance_data.include? ''
- return { 'instance_data' => 'parsed_instance_data' }
- end
-
if @instance_data.include?('SUSE')
if @instance_data.include?('SAP')
return { 'billingProducts' => nil, 'marketplaceProductCodes' => ['6789_SUSE_SAP'] }
@@ -49,4 +45,14 @@ def payg_billing_code?(iid, identifier)
return true if (identifier.casecmp('sles').zero? && instance_billing_info[:billing_product] == SLES_PRODUCT_IDENTIFIER)
return true if (identifier.casecmp('sles_sap').zero? && SLES4SAP_PRODUCT_IDENTIFIER.include?(instance_billing_info[:marketplace_code]))
end
+
+ def instance_identifier
+ 'foo'
+ end
+
+ def allowed_extension?
+ # method to check if a product (extension) meet the criteria
+ # to be acivated on SCC or not, i.e. LTSS in Azure Basic VM
+ true
+ 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 9ccbcb1c2..6b7afad35 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
@@ -38,7 +38,7 @@
it 'class instance verification provider' do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original.at_least(:once)
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
@@ -71,13 +71,18 @@
end
context 'when verification provider returns false' do
+ let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') }
+
before do
stub_request(:post, scc_activate_url)
.to_return(
status: 200,
body: { error: 'Unexpected instance verification error has occurred' }.to_json,
headers: {}
- )
+ )
+ allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double)
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
+ allow(plugin_double).to receive(:instance_valid?).and_return(false)
post url, params: payload, headers: headers
end
@@ -113,7 +118,7 @@
it 'class instance verification provider' do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original.at_least(:once)
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
@@ -141,8 +146,9 @@
context 'when verification provider returns false' do
before do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double)
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once)
expect(plugin_double).to receive(:instance_valid?).and_return(false)
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
post url, params: payload, headers: headers
end
@@ -155,8 +161,9 @@
context 'when verification provider raises an unhandled exception' do
before do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double)
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once)
expect(plugin_double).to receive(:instance_valid?).and_raise('Custom plugin error')
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
post url, params: payload, headers: headers
end
@@ -171,9 +178,9 @@
before do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double)
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once)
expect(plugin_double).to receive(:instance_valid?).and_raise(InstanceVerification::Exception, 'Custom plugin error')
-
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
post url, params: payload, headers: headers
end
@@ -227,9 +234,9 @@
end
before do
- allow(InstanceVerification::Providers::Example).to receive(:new)
- .with(nil, nil, nil, instance_data).and_return(plugin_double)
+ 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)
FactoryBot.create(:subscription, product_classes: product_classes)
stub_request(:post, scc_activate_url)
@@ -339,9 +346,10 @@
end
before do
- allow(InstanceVerification::Providers::Example).to receive(:new)
- .with(nil, nil, nil, instance_data).and_return(plugin_double)
+ allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double)
+ allow(plugin_double).to receive(:instance_identifier).and_return('foo')
allow(plugin_double).to receive(:parse_instance_data).and_return({ InstanceId: 'foo' })
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
allow(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, product.id)
FactoryBot.create(:subscription, product_classes: product_classes)
@@ -380,8 +388,9 @@
before do
allow(InstanceVerification::Providers::Example).to receive(:new)
- .with(nil, nil, nil, instance_data).and_return(plugin_double)
+ .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(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, product.id)
FactoryBot.create(:subscription, product_classes: product_classes)
@@ -397,7 +406,7 @@
.to_return(status: 201, body: scc_response_body, headers: {})
expect(InstanceVerification).not_to receive(:update_cache).with('127.0.0.1', system.login, product.id)
-
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
post url, params: payload_no_token, headers: headers
end
@@ -409,12 +418,16 @@
end
context 'when the system is hybrid' do
+ before do
+ allow_any_instance_of(InstanceVerification::Providers::Example).to receive(:allowed_extension?).and_return(true)
+ end
+
context "when system doesn't have hw_info" do
let(:system) { FactoryBot.create(:system, :hybrid) }
it 'class instance verification provider' do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, nil).and_call_original
+ .and_call_original.at_least(:once)
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
@@ -442,7 +455,8 @@
context 'when verification provider returns false' do
before do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double)
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once)
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
expect(plugin_double).to receive(:instance_valid?).and_return(false)
post url, params: payload, headers: headers
end
@@ -456,7 +470,8 @@
context 'when verification provider raises an unhandled exception' do
before do
expect(InstanceVerification::Providers::Example).to receive(:new)
- .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double)
+ .with(be_a(ActiveSupport::Logger), be_a(ActionDispatch::Request), payload, instance_data).and_return(plugin_double).at_least(:once)
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
expect(plugin_double).to receive(:instance_valid?).and_raise('Custom plugin error')
post url, params: payload, headers: headers
end
@@ -514,8 +529,9 @@
before do
allow(InstanceVerification::Providers::Example).to receive(:new)
- .with(nil, nil, nil, instance_data).and_return(plugin_double)
+ .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)
FactoryBot.create(:subscription, product_classes: product_classes)
stub_request(:post, scc_activate_url)
diff --git a/engines/scc_proxy/lib/scc_proxy/engine.rb b/engines/scc_proxy/lib/scc_proxy/engine.rb
index e684dc910..47e6557e8 100644
--- a/engines/scc_proxy/lib/scc_proxy/engine.rb
+++ b/engines/scc_proxy/lib/scc_proxy/engine.rb
@@ -25,12 +25,6 @@
Net::HTTPRetriableError
].freeze
-INSTANCE_ID_KEYS = {
- amazon: 'instanceId',
- google: 'instance_id',
- microsoft: 'vmId'
-}.freeze
-
# rubocop:disable Metrics/ModuleLength
module SccProxy
class << self
@@ -43,7 +37,12 @@ class << self
# rubocop:disable ThreadSafety/InstanceVariableInClassMethod
def headers(auth, params)
@instance_id = if params && params.class != String
- get_instance_id(params)
+ InstanceVerification.provider.new(
+ nil,
+ nil,
+ nil,
+ params['instance_data']
+ ).instance_identifier
else
# if it is not JSON, it is the system_token already
# announce system has metadata
@@ -61,18 +60,6 @@ def headers(auth, params)
end
# rubocop:enable ThreadSafety/InstanceVariableInClassMethod
- def get_instance_id(params)
- verification_provider = InstanceVerification.provider.new(
- nil,
- nil,
- nil,
- params['instance_data']
- )
- instance_id_key = INSTANCE_ID_KEYS[params['hwinfo']['cloud_provider'].downcase.to_sym]
- iid = verification_provider.parse_instance_data
- iid[instance_id_key]
- end
-
def prepare_scc_announce_request(uri_path, auth, params)
scc_request = Net::HTTP::Post.new(uri_path, headers(auth, params))
@@ -307,6 +294,7 @@ 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
@@ -372,6 +360,12 @@ def has_no_regcode?(auth_header)
protected
def scc_activate_product
+ product_hash = @product.attributes.symbolize_keys.slice(:identifier, :version, :arch)
+ unless InstanceVerification.provider.new(logger, request, product_hash, @system.instance_data).allowed_extension?
+ error = ActionController::TranslatedError.new(N_('Product not supported for this instance'))
+ error.status = :forbidden
+ raise error
+ end
mode = find_mode
unless mode.nil?
# if system is byos or hybrid and there is a token
@@ -540,5 +534,6 @@ def get_system(systems)
end
end
end
+ # rubocop:enable Metrics/ClassLength
end
# rubocop:enable Metrics/ModuleLength
diff --git a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb
index 0ff8417f3..f023a15b9 100644
--- a/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb
+++ b/engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb
@@ -354,7 +354,7 @@
end
let(:product) do
FactoryBot.create(
- :product, :product_sles, :extension, :with_mirrored_repositories, :with_mirrored_extensions,
+ :product, :product_sles_ltss, :extension, :with_mirrored_repositories, :with_mirrored_extensions,
base_products: [system_payg.products.first]
)
end
@@ -415,7 +415,120 @@
allow(File).to receive(:directory?)
allow(FileUtils).to receive(:mkdir_p)
allow(FileUtils).to receive(:touch)
+ allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double)
+ allow(plugin_double).to receive(:allowed_extension?).and_return(true)
+ allow(InstanceVerification).to receive(:write_cache_file).twice.with(
+ Rails.application.config.repo_cache_dir, "127.0.0.1-#{system_payg.login}-#{product.id}"
+ )
+ allow(InstanceVerification).to receive(:write_cache_file).twice.with(
+ Rails.application.config.registry_cache_dir, "127.0.0.1-#{system_payg.login}"
+ )
+ allow(plugin_double).to receive(:instance_valid?).and_return(true)
+ end
+
+ context 'when LTSS not allowed' do
+ before do
+ allow(plugin_double).to receive(:allowed_extension?).and_return(false)
+ end
+
+ it 'raises an error' do
+ stub_request(:post, scc_register_system_url)
+ .to_return(status: 403, body: { ok: 'OK' }.to_json, headers: {})
+
+ post url, params: payload, headers: headers
+ data = JSON.parse(response.body)
+ expect(data['error']).to include('Product not supported for this instance')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when system has hw info' do
+ let(:instance_data) { '{"instanceId": "dummy_instance_data"}' }
+ let(:new_system_token) { 'BBBBBBBB-BBBB-4BBB-9BBB-BBBBBBBBBBBB' }
+ let(:serialized_service_json) do
+ V3::ServiceSerializer.new(
+ product.service,
+ base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
+ ).to_json
+ end
+
+ let(:serialized_service_sap_json) do
+ V3::ServiceSerializer.new(
+ product_sap.service,
+ base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
+ ).to_json
+ end
+
+ context 'when system is connected to SCC' do
+ let(:system_payg) do
+ FactoryBot.create(:system, :payg, :with_system_information, :with_activated_base_product, instance_data: instance_data,
+ system_token: new_system_token)
+ end
+ let(:product) do
+ FactoryBot.create(
+ :product, :product_sles_ltss, :extension, :with_mirrored_repositories, :with_mirrored_extensions,
+ base_products: [system_payg.products.first]
+ )
+ end
+ let(:subscription_response) do
+ {
+ id: 4206714,
+ regcode: 'bar',
+ name: 'SUSE Employee subscription for SUSE Linux Enterprise Server for SAP Applications',
+ type: 'internal',
+ status: 'ACTIVE',
+ starts_at: '2019-03-20T09:48:52.658Z',
+ expires_at: '2024-03-20T09:48:52.658Z',
+ system_limit: '100',
+ systems_count: '156',
+ virtual_count: nil,
+ product_classes: [
+ 'AiO',
+ '7261',
+ 'SLE-HAE-X86',
+ '7261-BETA',
+ 'SLE-HAE-X86-BETA',
+ 'AiO-BETA',
+ '7261-ALPHA',
+ 'SLE-HAE-X86-ALPHA',
+ 'AiO-ALPHA'
+ ],
+ product_ids: [
+ 1959,
+ 1421
+ ],
+ skus: [],
+ systems: [
+ {
+ id: 3021957,
+ login: 'SCC_foo',
+ password: '5ee7273ac6ac4d7f',
+ last_seen_at: '2019-03-20T14:01:05.424Z'
+ }
+ ]
+ }
+ end
+
+ before do
+ allow(plugin_double).to(
+ receive(:instance_valid?)
+ .and_raise(InstanceVerification::Exception, 'Custom plugin error')
+ )
+ end
+ context 'with a valid registration code' do
+ before do
+ stub_request(:post, scc_activate_url)
+ .to_return(
+ status: 201,
+ body: { id: 'bar' }.to_json,
+ headers: {}
+ )
+ allow(File).to receive(:directory?)
+ allow(FileUtils).to receive(:mkdir_p)
+ allow(FileUtils).to receive(:touch)
allow(InstanceVerification).to receive(:write_cache_file).twice.with(
Rails.application.config.repo_cache_dir, "127.0.0.1-#{system_payg.login}-#{product.id}"
)
diff --git a/spec/factories/products.rb b/spec/factories/products.rb
index 30532e1fc..e11965e7a 100644
--- a/spec/factories/products.rb
+++ b/spec/factories/products.rb
@@ -57,6 +57,23 @@
friendly_version { '15 SP3' }
end
+ trait :product_sles_ltss do
+ identifier { 'SLES-LTSS' }
+ name { 'SUSE Linux Enterprise Server LTSS' }
+ description { 'SUSE Linux Enterprise offers a comprehensive suite of products...' }
+ shortname { 'SLES15-SP3-LTSS' }
+ former_identifier { 'SLES_LTSS' }
+ product_type { 'extension' }
+ product_class { 'LTSS' }
+ release_type { nil }
+ release_stage { 'released' }
+ version { '15.3' }
+ arch { 'x86_64' }
+ free { false }
+ cpe { 'cpe:/o:suse:sles:15:sp3' }
+ friendly_version { '15 SP3' }
+ end
+
trait :product_sles_sap do
identifier { 'SLES_SAP' }
name { 'SUSE Linux Enterprise Server' }