Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate the upgrate call to SCC #1220

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -551,65 +551,176 @@
describe '#upgrade' do
subject { response }

let(:system) { FactoryBot.create(:system) }
let(:instance_data) { 'dummy_instance_data' }
let(:request) { put url, headers: headers, params: payload }
let!(:old_product) { FactoryBot.create(:product, :with_mirrored_repositories, :activated, system: system) }
let(:payload) do
{
identifier: new_product.identifier,
version: new_product.version,
arch: new_product.arch
}
end

before { request }
context 'when system is byos' do
let(:system) { FactoryBot.create(:system, :byos, :with_system_information, instance_data: instance_data) }
let!(:old_product) { FactoryBot.create(:product, :with_mirrored_repositories, :activated, system: system) }
let(:payload) do
{
identifier: new_product.identifier,
version: new_product.version,
arch: new_product.arch
}
end
let(:scc_systems_products_url) { 'https://scc.suse.com/connect/systems/products' }
let(:scc_headers) do
{
'Accept' => 'application/json,application/vnd.scc.suse.com.v4+json',
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'Authorization' => headers['HTTP_AUTHORIZATION'],
'Content-Type' => 'application/json',
'User-Agent' => 'Ruby'
}
end

context 'when SCC upgrade success' do
before do
# pp headers
stub_request(:put, scc_systems_products_url)
.with({ headers: scc_headers, body: payload.merge({ byos_mode: 'byos' }) })
.and_return(status: 200, body: '', 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) }

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
end
end

context 'when migration target base product has the same identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories, identifier: old_product.identifier,
version: '999', predecessors: [ old_product ]
)
end

context "when migration target base product doesn't have an activated successor/predecessor" do
let(:new_product) { FactoryBot.create(:product, :with_mirrored_repositories) }
it 'HTTP response code is 201' do
expect(response).to have_http_status(201)
end

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
it "doesn't render an error" do
data = JSON.parse(response.body)
expect(data).not_to have_key('error')
end
end
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
context 'when SCC upgrade fails' do
before do
stub_request(:put, scc_systems_products_url)
.with({ headers: scc_headers, body: payload.merge({ byos_mode: 'byos' }) })
.and_return(
status: 401,
body: { error: 'error_message' }.to_json,
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) }

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
end
end

context 'when migration target base product has the same identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories, identifier: old_product.identifier,
version: '999', predecessors: [ old_product ]
)
end

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data).to have_key('error')
end
end
end
end

context 'when migration target base product has a different identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories,
identifier: old_product.identifier + '-foo', predecessors: [ old_product ]
)
context 'when system is payg' do
let(:system) { FactoryBot.create(:system, :payg, :with_system_information, instance_data: instance_data) }
let!(:old_product) { FactoryBot.create(:product, :with_mirrored_repositories, :activated, system: system) }
let(:payload) do
{
identifier: new_product.identifier,
version: new_product.version,
arch: new_product.arch
}
end

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end
before { request }

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
end
end
context "when migration target base product doesn't have an activated successor/predecessor" do
let(:new_product) { FactoryBot.create(:product, :with_mirrored_repositories) }

context 'when migration target base product has the same identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories, identifier: old_product.identifier,
version: '999', predecessors: [ old_product ]
)
it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
end
end

it 'HTTP response code is 201' do
expect(response).to have_http_status(201)
context 'when migration target base product has a different identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories,
identifier: old_product.identifier + '-foo', predecessors: [ old_product ]
)
end

it 'HTTP response code is 422' do
expect(response).to have_http_status(422)
end

it 'renders an error' do
data = JSON.parse(response.body)
expect(data['error']).to eq('Migration target not allowed on this instance type')
end
end

it "doesn't render an error" do
data = JSON.parse(response.body)
expect(data).not_to have_key('error')
context 'when migration target base product has the same identifier' do
let(:new_product) do
FactoryBot.create(
:product, :with_mirrored_repositories, identifier: old_product.identifier,
version: '999', predecessors: [ old_product ]
)
end

it 'HTTP response code is 201' do
expect(response).to have_http_status(201)
end

it "doesn't render an error" do
data = JSON.parse(response.body)
expect(data).not_to have_key('error')
end
end
end
end
Expand Down
67 changes: 55 additions & 12 deletions engines/scc_proxy/lib/scc_proxy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'net/http'

ANNOUNCE_URL = 'https://scc.suse.com/connect/subscriptions/systems'.freeze
ACTIVATE_PRODUCT_URL = 'https://scc.suse.com/connect/systems/products'.freeze
SYSTEM_PRODUCTS_URL = 'https://scc.suse.com/connect/systems/products'.freeze
SYSTEMS_ACTIVATIONS_URL = 'https://scc.suse.com/connect/systems/activations'.freeze
DEREGISTER_SYSTEM_URL = 'https://scc.suse.com/connect/systems'.freeze
DEREGISTER_PRODUCT_URL = 'https://scc.suse.com/connect/systems/products'.freeze
Expand Down Expand Up @@ -117,6 +117,17 @@ def prepare_scc_request(uri_path, product, auth, params, mode)
scc_request
end

def prepare_scc_update_request(uri_path, product, auth, mode)
jesusbv marked this conversation as resolved.
Show resolved Hide resolved
jesusbv marked this conversation as resolved.
Show resolved Hide resolved
scc_request = Net::HTTP::Put.new(uri_path, headers(auth, nil))
scc_request.body = {
identifier: product.identifier,
version: product.version,
arch: product.arch,
byos_mode: mode
}.to_json
scc_request
end

def announce_system_scc(auth, params)
uri = URI.parse(ANNOUNCE_URL)
http = Net::HTTP.new(uri.host, uri.port)
Expand All @@ -129,7 +140,7 @@ def announce_system_scc(auth, params)
end

def scc_activate_product(product, auth, params, mode)
uri = URI.parse(ACTIVATE_PRODUCT_URL)
uri = URI.parse(SYSTEM_PRODUCTS_URL)
rjschwei marked this conversation as resolved.
Show resolved Hide resolved
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
scc_request = prepare_scc_request(uri.path, product, auth, params, mode)
Expand Down Expand Up @@ -254,6 +265,20 @@ def scc_check_subscription_expiration(headers, login, system_token, logger, mode

SccProxy.activations_fail_state(scc_systems_activations, headers, product)
end

def scc_upgrade(auth, product, system_login, mode, logger)
uri = URI.parse(SYSTEM_PRODUCTS_URL)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
scc_request = prepare_scc_update_request(uri.path, product, auth, mode)
response = http.request(scc_request)
unless response.code_type == Net::HTTPOK
digitaltom marked this conversation as resolved.
Show resolved Hide resolved
logger.info "Could not upgrade the system (#{system_login}), error: #{response.message} #{response.code}"
response.message = SccProxy.parse_error(response.message) if response.message.include? 'json'
raise ActionController::TranslatedError.new(response.body)
end
response
end
end

# rubocop:disable Metrics/ClassLength
Expand Down Expand Up @@ -316,12 +341,12 @@ def has_no_regcode?(auth_header)

Api::Connect::V3::Systems::ProductsController.class_eval do
before_action :scc_activate_product, only: %i[activate]
before_action :scc_upgrade, only: %i[upgrade], if: -> { @system.byos? }

protected

# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/AbcSize
def scc_activate_product
logger.info "Activating product #{@product.product_string} to SCC"
auth = nil
Expand All @@ -337,12 +362,13 @@ def scc_activate_product
if @system.payg? && base_prod.present?
raise 'Incompatible extension product' unless @product.arch == base_prod.arch && @product.version == base_prod.version

params['hostname'] = @system.hostname
params['proxy_byos_mode'] = mode
params['scc_login'] = @system.login
params['scc_password'] = @system.password
params['hwinfo'] = JSON.parse(@system.system_information)
params['instance_data'] = @system.instance_data
update_params_system_info mode
# params['hostname'] = @system.hostname
jesusbv marked this conversation as resolved.
Show resolved Hide resolved
# params['proxy_byos_mode'] = mode
# params['scc_login'] = @system.login
# params['scc_password'] = @system.password
# params['hwinfo'] = JSON.parse(@system.system_information)
# params['instance_data'] = @system.instance_data
announce_auth = "Token token=#{params[:token]}"

response = SccProxy.announce_system_scc(announce_auth, params)
Expand Down Expand Up @@ -375,6 +401,8 @@ def scc_activate_product
end
logger.info 'No token provided' if params[:token].blank?
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

def deregister_hybrid(auth)
response = SccProxy.deregister_system_scc(auth, @system.system_token)
Expand All @@ -386,10 +414,25 @@ def deregister_hybrid(auth)
end
logger.info 'System successfully deregistered from SCC'
end

def scc_upgrade
logger.info "Upgrading system to product #{@product.product_string} to SCC"
auth = nil
auth = request.headers['HTTP_AUTHORIZATION'] if request.headers.include?('HTTP_AUTHORIZATION')
mode = 'byos' if @system.byos?
SccProxy.scc_upgrade(auth, @product, @system.login, mode, logger)
logger.info "System #{@system.login} successfully upgraded with SCC"
end

def update_params_system_info(mode)
params['hostname'] = @system.hostname
params['proxy_byos_mode'] = mode
params['scc_login'] = @system.login
params['scc_password'] = @system.password
params['hwinfo'] = JSON.parse(@system.system_information)
params['instance_data'] = @system.instance_data
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

Api::Connect::V4::Systems::ProductsController.class_eval do
before_action :scc_deactivate_product, only: %i[destroy]
Expand Down