Skip to content

Commit

Permalink
Merge pull request #806 from SUSE/handle-proxy-byos
Browse files Browse the repository at this point in the history
Add proxy for BYOS instances
  • Loading branch information
jesusbv authored Nov 12, 2021
2 parents e30273f + 267bc56 commit a5a6058
Show file tree
Hide file tree
Showing 21 changed files with 816 additions and 18 deletions.
1 change: 1 addition & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Lint/ConstantDefinitionInBlock:
Lint/EmptyBlock:
Exclude:
- 'engines/zypper_auth/config/routes.rb'
- 'engines/scc_proxy/config/routes.rb'

# Offense count: 4
# Configuration parameters: MaximumRangeSize.
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/api/connect/v3/systems/products_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ def check_product_service_and_repositories
def create_product_activation
activation = @system.activations.where(service_id: @product.service.id).first_or_create

# in BYOS mode, we rely on the activation being performed in
# `engines/scc_proxy/lib/scc_proxy/engine.rb` and don't need further checks here
return activation if @system.proxy_byos

if params[:token].present?
subscription = Subscription.find_by(regcode: params[:token])

Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20211017185107_add_proxy_byos_to_systems.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class AddProxyByosToSystems < ActiveRecord::Migration[6.1]
def up
add_column :systems, :proxy_byos, :boolean
change_column_default :systems, :proxy_byos, false

System.update_all(proxy_byos: false)
end

def down
remove_column :systems, :proxy_byos
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2021_10_06_102307) do
ActiveRecord::Schema.define(version: 2021_10_17_185107) do

create_table "activations", charset: "utf8mb3", force: :cascade do |t|
t.bigint "service_id", null: false
Expand Down Expand Up @@ -159,6 +159,7 @@
t.datetime "updated_at", null: false
t.datetime "scc_registered_at"
t.bigint "scc_system_id", comment: "System ID in SCC (if the system registration was forwarded; needed for forwarding de-registrations)"
t.boolean "proxy_byos", default: false
t.index ["login"], name: "index_systems_on_login", unique: true
end

Expand Down
20 changes: 14 additions & 6 deletions engines/instance_verification/lib/instance_verification/engine.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
module InstanceVerification
def self.update_cache(remote_ip, system_login, product_id)
cache_key = [remote_ip, system_login, product_id].join('-')
# caches verification result to be used by zypper auth plugin
Rails.cache.write(cache_key, true, expires_in: 20.minutes)
end

class Engine < ::Rails::Engine
isolate_namespace InstanceVerification
config.generators.api_only = true
Expand Down Expand Up @@ -39,7 +45,13 @@ def verify_product_activation
verify_extension_activation(product)
end
rescue InstanceVerification::Exception => e
raise ActionController::TranslatedError.new('Instance verification failed: %{message}' % { message: e.message })
unless @system.proxy_byos
# BYOS instances that use RMT as a proxy are expected to fail the
# instance verification check, however, PAYG instances may send registration
# code, as such, instance verification engine checks for those BYOS
# instances once instance verification has failed
raise ActionController::TranslatedError.new('Instance verification failed: %{message}' % { message: e.message })
end
rescue StandardError => e
logger.error('Unexpected instance verification error has occurred:')
logger.error(e.message)
Expand Down Expand Up @@ -81,11 +93,7 @@ def verify_base_product_activation(product)
)

raise 'Unspecified error' unless verification_provider.instance_valid?

cache_key = [request.remote_ip, @system.login, product.id].join('-')

# caches verification result to be used by zypper auth plugin
Rails.cache.write(cache_key, true, expires_in: 20.minutes)
InstanceVerification.update_cache(request.remote_ip, @system.login, product.id)
end

# Verify that the base product doesn't change in the offline migration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def validate_instance_data(_instance_data)
# implementation route. In this example it is assumed the instance data is json and
# contains instance_product_id

return '1234_SUSE_SLES' if @product_hash[:identifier] == 'sles'
return '1234_SUSE_SLES' if @product_hash[:identifier].casecmp('sles').zero?

return '6789_SUSE_SAP' if @product_hash[:identifier] == 'sles_sap'
return '6789_SUSE_SAP' if @product_hash[:identifier].casecmp('sles_sap').zero?
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
describe '#announce_system' do
let(:instance_data) { '<instance_data/>' }

it 'saves instance data' do
post '/connect/subscriptions/systems', params: { hostname: 'test', instance_data: instance_data }
data = JSON.parse(response.body)
system = System.find_by(login: data['login'])
expect(system.hw_info.instance_data).to eq(instance_data)
context 'using RMT generated credentials' do
it 'saves instance data' do
post '/connect/subscriptions/systems', params: { hostname: 'test', instance_data: instance_data }
data = JSON.parse(response.body)
system = System.find_by(login: data['login'])
expect(system.hw_info.instance_data).to eq(instance_data)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
arch: product.arch
}
end
let(:payload_byos) do
{
identifier: product.identifier,
version: product.version,
arch: product.arch,
email: 'foo',
token: 'bar'
}
end

describe '#activate' do
let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') }
Expand Down Expand Up @@ -76,10 +85,19 @@
end

context 'when verification provider raises an instance verification exception' do
let(:scc_activate_url) { 'https://scc.suse.com/connect/systems/products' }

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)
expect(plugin_double).to receive(:instance_valid?).and_raise(InstanceVerification::Exception, 'Custom plugin error')
stub_request(:post, scc_activate_url)
.to_return(
status: 401,
body: 'bar',
headers: {}
)

post url, params: payload, headers: headers
end

Expand Down Expand Up @@ -124,10 +142,18 @@
base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
).to_json
end
let(:scc_activate_url) { 'https://scc.suse.com/connect/systems/products' }

before do
FactoryBot.create(:subscription, product_classes: product_classes)
expect(InstanceVerification::Providers::Example).not_to receive(:new)
stub_request(:post, scc_activate_url)
.to_return(
status: 401,
body: 'bar',
headers: {}
)

post url, params: payload, headers: headers
end

Expand Down
6 changes: 6 additions & 0 deletions engines/scc_proxy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/.bundle/
/doc/
/log/*.log
/pkg/
/tmp/
.byebug_history
24 changes: 24 additions & 0 deletions engines/scc_proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SccProxy
Engine to handle BYOS, that use RMT as an SCC proxy,
instances registration and activations


1. BYOS instance supplies registration code (regcode) during registration, if the regcode is valid
then, system is announced and product is registered against SCC.
2. BYOS instance, once registered, can activate products included in that subscription

in the BYOS instance, do

if `registercloudguest` is not installed:
```bash
SUSEConnect -r <regcode>
SUSEConnect -p Public Cloud Module // SUSEConnect -l to list the modules and extensions
zypper in cloud-regionsrv-client
```
once installed, then
```
registercloudguest -r regcode // to register the system
SUSEConnect -p <product> // activate a product
SUSEConnect -d -p <other_product> // to de-register a product
registercloudguest --clean // to de-register the system
```
12 changes: 12 additions & 0 deletions engines/scc_proxy/bin/rails
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails gems
# installed from the root of your application.

ENGINE_ROOT = File.expand_path('..', __dir__)
ENGINE_PATH = File.expand_path('../lib/scc_proxy/engine', __dir__)

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

require 'rails'
2 changes: 2 additions & 0 deletions engines/scc_proxy/config/routes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SccProxy::Engine.routes.draw do
end
6 changes: 6 additions & 0 deletions engines/scc_proxy/lib/scc_proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$LOAD_PATH.push File.expand_path(__dir__, '..')

require 'scc_proxy/engine'

module SccProxy
end
Loading

0 comments on commit a5a6058

Please sign in to comment.