Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 4 additions & 27 deletions engines/data_export/lib/data_export/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,16 @@ module DataExport
class Engine < ::Rails::Engine
isolate_namespace DataExport
config.after_initialize do
# replaces RMT registration for SCC registration
Api::Connect::V3::Subscriptions::SystemsController.class_eval do
after_action :export_rmt_data, only: %i[announce_system], if: -> { DataExport.handler.presence && response.successful? && !@system.byos? }

def export_rmt_data
# no need to check if system is nil
# as the response is successful
data_export_handler = DataExport.handler.new(
@system,
request,
params,
logger
)
data_export_handler.export_rmt_data
logger.info "System #{@system.login} info updated by data export handler after announcing the system"
rescue StandardError => e
logger.error('Unexpected data export error has occurred:')
logger.error(e.message)
logger.error("System login: #{@system.login}, IP: #{request.remote_ip}")
logger.error('Backtrace:')
logger.error(e.backtrace)
end
end

Api::Connect::V3::Systems::SystemsController.class_eval do
# if registered_at and last_seen_at are the same, it is a registration
after_action :export_rmt_data, only: %i[update], if: lambda {
DataExport.handler.presence && response.successful? && !@system.byos? &&
@system.products.present?
@system.products.present? && @system.registered_at != @system.last_seen_at
Copy link
Collaborator Author

@jesusbv jesusbv Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means that if a user runs heartbeat command right after registration, we would not write anything to the file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attributes registered_at and last_seen_at are not initialized with the same value. Both get set independently with Time.zone.now in different places of the code.

https://github.com/SUSE/rmt/blob/master/app/models/system.rb#L25 vs
https://github.com/SUSE/rmt/blob/master/app/controllers/application_controller.rb#L26

You might want to set registered_at directly from the last_seen_at value to guarantee they match.

Copy link
Collaborator Author

@jesusbv jesusbv Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the check to be under 10 seconds difference between the two values for a registration

}

def export_rmt_data
@system.products.pluck(:name).each do |prod_name|
params[:dw_product_name] = prod_name
@system.activations.each do |activation|
params[:dw_product_name] = activation.service.product.product_string
send_data
end
rescue StandardError => e
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
subject(:update_action) { put url, params: payload, headers: headers }

context 'when update success' do
before { allow(DataExport::Handlers::Example).to receive(:new).and_return(plugin_double) }
before do
system.update(last_seen_at: system.registered_at + 1.day)
allow(DataExport::Handlers::Example).to receive(:new).and_return(plugin_double)
end

context 'when data export success' do
before { allow(plugin_double).to receive(:export_rmt_data) }
Expand Down
28 changes: 1 addition & 27 deletions engines/zypper_auth/lib/zypper_auth/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,33 +93,7 @@ def path_allowed?(headers)

return true if @system.byos?

instance_verified = InstanceVerification.verify_instance(request, logger, @system)
DataExport.handler.new(@system, request, params, logger).export_rmt_data if DataExport.handler.presence && instance_verified
instance_verified
rescue InstanceVerification::Exception => e
# if we are here that means the instance data in the database is not right
# but the instance data coming from the hypervisor in the client is OK
logger.error("Could not parse the instance data: #{e.message}")
decoded_instance_data = Base64.decode64(request.headers['X-Instance-Data'].to_s)
cache_params = {}
if @system.pubcloud_reg_code.present?
cache_params = { token: Base64.decode64(@system.pubcloud_reg_code.split(',')[0]), instance_data: decoded_instance_data }
end
cache_key = InstanceVerification.build_cache_entry(
request.remote_ip,
@system.login,
cache_params,
@system.proxy_byos_mode,
@system.products.find_by(product_type: 'base')
)
logger.info("Removing entry #{cache_key} from the cache, if present")
InstanceVerification.remove_entry_from_cache(cache_key, @system.proxy_byos_mode)
instance_verified
rescue StandardError => e
logger.error("Unexpected data export error has occurred: #{e.message}")
logger.error('Data not exported')
logger.error("System login: #{@system.login}, IP: #{request.remote_ip}")
instance_verified
InstanceVerification.verify_instance(request, logger, @system)
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,71 +89,6 @@
end
end

context 'system with instance_data headers instance data is invalid in the DB' do
context 'InstanceVerification error' do
let(:headers) { auth_header.merge({ 'X-Original-URI': requested_uri, 'X-Instance-Data': Base64.strict_encode64('test') }) }
let(:data_export_double) { instance_double('DataExport::Handlers::Example') }
let(:wrong_iid) { '<repoformat>plugin:susecloud</repoformat>\n' }


before do
allow(InstanceVerification).to receive(:reg_code_in_cache?).and_return(nil)
Rails.cache.clear
expect_any_instance_of(InstanceVerification::Providers::Example).to receive(:instance_valid?).and_return(true)
allow(DataExport::Handlers::Example).to receive(:new).and_return(data_export_double)
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
expect(data_export_double).to receive(:export_rmt_data).and_raise(InstanceVerification::Exception, "Malformed instance data #{wrong_iid}")
allow(Rails.logger).to receive(:error)
allow(Rails.logger).to receive(:info)
expect(Rails.logger).to receive(:error).with(
'Could not parse the instance data: Malformed instance data <repoformat>plugin:susecloud</repoformat>\n'
)
expect(Rails.logger).to receive(:info)
get '/api/auth/check', headers: headers
end

it do
is_expected.to have_http_status(200)
end
end

context 'StandardError' do
let(:system_byos) { FactoryBot.create(:system, :byos_reg_code, :with_activated_product) }
let(:headers) { auth_header.merge({ 'X-Original-URI': requested_uri, 'X-Instance-Data': Base64.strict_encode64('test') }) }
let(:data_export_double) { instance_double('DataExport::Handlers::Example') }
let(:wrong_iid) { '<repoformat>plugin:susecloud</repoformat>\n' }


before do
allow(InstanceVerification).to receive(:reg_code_in_cache?).and_return(nil)
Rails.cache.clear
expect_any_instance_of(InstanceVerification::Providers::Example).to receive(:instance_valid?).and_return(true)
allow(DataExport::Handlers::Example).to receive(:new).and_return(data_export_double)
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
expect(data_export_double).to receive(:export_rmt_data).and_raise(
StandardError, 'API BORKED'
)
allow(Rails.logger).to receive(:error)
expect(Rails.logger).to receive(:error).with(
'Unexpected data export error has occurred: API BORKED'
)
expect(Rails.logger).to receive(:error).with('Data not exported')
expect(Rails.logger).to receive(:error).with(
"System login: #{system.login}, IP: 127.0.0.1"
)
get '/api/auth/check', headers: headers
end

it do
is_expected.to have_http_status(200)
end
end
end

context 'when system is BYOS proxy' do
let(:local_path) { system_byos.activations.first.product.repositories.first.local_path }
let(:paid_local_path) do
Expand Down Expand Up @@ -399,7 +334,6 @@
allow(File).to receive(:directory?)
allow(Dir).to receive(:mkdir)
allow(FileUtils).to receive(:touch)
expect(data_export_double).to receive(:export_rmt_data)
get '/api/auth/check', headers: headers
end

Expand Down Expand Up @@ -645,7 +579,6 @@
before do
allow(InstanceVerification).to receive(:verify_instance).and_return(true)
allow(DataExport::Handlers::Example).to receive(:new).and_return(data_export_double)
expect(data_export_double).to receive(:export_rmt_data)
get '/api/auth/check', headers: headers
end

Expand Down