Skip to content

Commit

Permalink
Merge branch 'master' into depfu/update/group/rails-6.1.7.9
Browse files Browse the repository at this point in the history
  • Loading branch information
digitaltom authored Dec 17, 2024
2 parents 3b5c2e0 + c386c36 commit 8cab670
Show file tree
Hide file tree
Showing 29 changed files with 556 additions and 82 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/lint-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ jobs:
- name: Run core tests
run: |
bundle exec rake test:core
- name: Run core tests with sqlite
run: |
sed -i 's/adapter: mysql2/adapter: sqlite3/' config/rmt.yml
bundle exec rake test:core
- name: Run PubCloud engines tests
run: |
bundle exec rake test:engines
Expand Down
10 changes: 10 additions & 0 deletions app/controllers/api/connect/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ def authenticate_with_token
end
end

def system_token_header
headers[SYSTEM_TOKEN_HEADER] = @system.system_token
end

def refresh_system_token
if system_tokens_enabled?
@system.update(system_token: SecureRandom.uuid)
system_token_header
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@ class Api::Connect::V3::Systems::ProductsController < Api::Connect::BaseControll
before_action :check_product_service_and_repositories, only: %i[show activate]
before_action :load_subscription, only: %i[activate upgrade]
before_action :check_base_product_dependencies, only: %i[activate upgrade show]
after_action :refresh_system_token, only: %i[activate upgrade], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) }

def activate
create_product_activation
render_service
end

def show
if @system.products.include? @product
if @product.identifier.casecmp?('sles')
# if system has SLE Micro
# it should access to SLES products
sle_micro = @system.products.any? { |p| p.identifier.downcase.include?('sle-micro') }
sle_micro_same_arch = @system.products.pluck(:arch).include?(@product.arch) if sle_micro
end
if @system.products.include?(@product) || sle_micro_same_arch
respond_with(
@product,
serializer: ::V3::ProductSerializer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Api::Connect::V3::Systems::SystemsController < Api::Connect::BaseController

before_action :authenticate_system
after_action :refresh_system_token, only: [:update], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) }

def update
if params[:online_at].present?
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class Api::Connect::V4::Systems::ProductsController < Api::Connect::V3::Systems::ProductsController

after_action :refresh_system_token, only: %i[activate upgrade synchronize destroy], if: -> { request.headers.key?(SYSTEM_TOKEN_HEADER) }
def destroy
if @product.base?
raise ActionController::TranslatedError.new(N_('The product "%s" is a base product and cannot be deactivated'), @product.name)
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ def authenticate_system(skip_on_duplicated: false)
update_user_agent

# If SYSTEM_TOKEN_HEADER is present, RMT assumes the client uses a SUSEConnect version
# that supports this feature. In this case, refresh the token and include it in the response.
# that supports this feature.
if system_tokens_enabled? && request.headers.key?(SYSTEM_TOKEN_HEADER)
@system.update(last_seen_at: Time.zone.now, system_token: SecureRandom.uuid)
headers[SYSTEM_TOKEN_HEADER] = @system.system_token
@system.update(last_seen_at: Time.zone.now)
system_token_header
# only update last_seen_at each 3 minutes,
# so that a system that calls SCC every second doesn't write + lock the database row
elsif !@system.last_seen_at || @system.last_seen_at < 3.minutes.ago
Expand Down
5 changes: 3 additions & 2 deletions app/models/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ class Repository < ApplicationRecord
class << self

def remove_suse_repos_without_tokens!
where(auth_token: nil).where('external_url LIKE ?', 'https://updates.suse.com%').delete_all
where(auth_token: nil).where("external_url LIKE '%.suse.com%'").where(installer_updates: 0).where.not(scc_id: nil).delete_all
end

# Mangles remote repo URL to make a nicer local path, see specs for examples
def make_local_path(url)
uri = URI(url)
path = uri.path.to_s
path.gsub!(%r{^/repo}, '') if (uri.hostname == 'updates.suse.com')
# drop '/repo' from SLE11 paths, to avoid double /repo/repo in local storage path.
path.gsub!(%r{^/repo/\$RCE/}, '/$RCE/')
(path == '') ? '/' : path
end

Expand Down
2 changes: 1 addition & 1 deletion config/rmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ database_test:
database: rmt_test

scc:
host: https://scc.suse.com/connect
host: <%= ENV.fetch('SCC_HOST'){ 'https://scc.suse.com/connect' } %>
username: <%= ENV['SCC_USERNAME'] %>
password: <%= ENV['SCC_PASSWORD'] %>
sync_systems: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def check
# belongs to a PAYG or BYOS instance
verification_provider = InstanceVerification.provider.new(
logger,
nil,
request,
nil,
params[:metadata]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ def validate_instance_data(_instance_data)
end

def parse_instance_data
if @instance_data.include? '<instance_data/>'
return { 'instance_data' => 'parsed_instance_data' }
end

if @instance_data.include?('SUSE')
if @instance_data.include?('SAP')
return { 'billingProducts' => nil, 'marketplaceProductCodes' => ['6789_SUSE_SAP'] }
Expand All @@ -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) meets the criteria
# to be activated on SCC or not, i.e. LTSS in Azure Basic VM
true
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
33 changes: 14 additions & 19 deletions engines/scc_proxy/lib/scc_proxy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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))

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -540,5 +534,6 @@ def get_system(systems)
end
end
end
# rubocop:enable Metrics/ClassLength
end
# rubocop:enable Metrics/ModuleLength
Loading

0 comments on commit 8cab670

Please sign in to comment.