Skip to content

Commit

Permalink
More product deactivation implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Shaidurov committed Apr 12, 2017
1 parent 0c9c64d commit d118d65
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 96 deletions.
5 changes: 5 additions & 0 deletions lib/suse/connect/cli.rb
Expand Up @@ -75,6 +75,11 @@ def execute! # rubocop:disable MethodLength, CyclomaticComplexity
# Zypper errors are in the range 1-7 and 100-105 (which connect will not cause)
log.fatal "Error: zypper returned (#{e.exitstatus}) with '#{e.output}'"
exit e.exitstatus
rescue SystemNotRegisteredError => e
log.fatal 'Deregistration failed. Check if the system has been '\
'registered using the --status-text option or use the '\
'--regcode parameter to register it.'
exit 69
end

private
Expand Down
27 changes: 12 additions & 15 deletions lib/suse/connect/client.rb
Expand Up @@ -31,23 +31,20 @@ def register!
print_success_message product
end

# Deregisters a whole system or a single product
#
# @returns: Empty body and 204 status code
def deregister!
if registered?
if @config.product
service = deactivate_product @config.product
System.remove_service service
Zypper.remove_release_package product.identifier
print_success_message product, action: 'Deregistered'
else
@api.deregister(system_auth)
System.cleanup!
log.info 'Successfully deregistered system.'
end
raise SystemNotRegisteredError unless registered?
if @config.product
service = deactivate_product @config.product
System.remove_service service
Zypper.remove_release_package @config.product.identifier
print_success_message @config.product, action: 'Deregistered'
else
log.fatal 'Deregistration failed. Check if the system has been '\
'registered using the -s option or use the --regcode parameter to '\
'register it.'
@api.deregister(system_auth)
System.cleanup!
log.info 'Successfully deregistered system.'
end
end

Expand Down Expand Up @@ -168,7 +165,7 @@ def list_installer_updates(product)
# Announces the system to the server, receiving and storing its credentials.
# When already announced, sends the current hardware details to the server
def announce_or_update
if System.credentials?
if registered?
update_system
else
login, password = announce_system(nil, @config.instance_data_file)
Expand Down
1 change: 1 addition & 0 deletions lib/suse/connect/errors.rb
Expand Up @@ -10,6 +10,7 @@ class CannotDetectBaseProduct < StandardError; end
class SystemCallError < StandardError; end
class UnsupportedStatusFormat < StandardError; end
class NetworkError < StandardError; end
class SystemNotRegisteredError < StandardError; end

# Basic error for API interactions. Collects HTTP response (which includes
# status code and response body) for future showing to user via {Cli}
Expand Down
4 changes: 4 additions & 0 deletions lib/suse/connect/zypper.rb
Expand Up @@ -151,6 +151,10 @@ def install_release_package(identifier)
call("--no-refresh --non-interactive install --no-recommends -t product #{identifier}") if identifier
end

def remove_release_package(identifier)
call("--no-refresh --non-interactive remove --no-recommends -t product #{identifier}") if identifier
end

# rubocop:disable AccessorMethodName
def set_release_version(version)
call("--non-interactive --releasever #{version} ref -f")
Expand Down
100 changes: 55 additions & 45 deletions spec/connect/cli_spec.rb
Expand Up @@ -2,17 +2,16 @@
require 'suse/connect/cli'

describe SUSE::Connect::Cli do
subject { SUSE::Connect::Cli }

let(:default_logger) { SUSE::Connect::GlobalLogger.instance.log }
let(:string_logger) { ::Logger.new(StringIO.new) }
let(:cli) { subject.new({}) }
let(:opts) { {} }
let(:cli) { described_class.new opts }
let(:config_file) { File.expand_path File.join(File.dirname(__FILE__), '../fixtures/SUSEConnect') }

before do
allow(Zypper).to receive_messages(base_product: {})
allow_any_instance_of(subject).to receive(:exit)
allow_any_instance_of(subject).to receive_messages(puts: true)
allow_any_instance_of(described_class).to receive(:exit)
allow_any_instance_of(described_class).to receive_messages(puts: true)
SUSE::Connect::GlobalLogger.instance.log = string_logger
allow_any_instance_of(Status).to receive(:activated_base_product?).and_return(true)
end
Expand All @@ -22,8 +21,10 @@
end

describe '#execute!' do
subject { cli.execute! }

context 'server errors' do
let(:cli) { subject.new(%w{-r 123}) }
let(:opts) { %w{-r 123} }

it 'should produce log output if ApiError encountered' do
expect(string_logger).to receive(:fatal).with("Error: SCC returned 'test' (222)")
Expand Down Expand Up @@ -95,7 +96,7 @@
end

context 'zypper error' do
let(:cli) { subject.new(%w{-r 456}) }
let(:opts) { %w{-r 456} }

it 'should produce log output if zypper errors' do
expect(string_logger).to receive(:fatal).with('Error: zypper returned (666) with \'<stream><error>zypper down</error></stream>\'')
Expand All @@ -106,13 +107,13 @@

context 'parameter dependencies' do
it 'requires no other parameters on --status' do
cli = subject.new(%w{--status})
cli = described_class.new(%w{--status})
expect_any_instance_of(Status).to receive(:print_product_statuses)
cli.execute!
end

it 'does not require --regcode or --url when specifying a product (eg. an extension)' do
cli = subject.new(%w{-p sle-module-web-scripting/12/x86_64})
cli = described_class.new(%w{-p sle-module-web-scripting/12/x86_64})
expect_any_instance_of(Client).to receive(:register!)
cli.execute!
end
Expand All @@ -127,13 +128,13 @@
end

it 'registers the system if --regcode was provided' do
cli = subject.new(%w{-r 456})
cli = described_class.new(%w{-r 456})
expect_any_instance_of(Client).to receive(:register!)
cli.execute!
end

it 'registers the system if --url was provided' do
cli = subject.new(%w{--url http://somewhere.com})
cli = described_class.new(%w{--url http://somewhere.com})
expect_any_instance_of(Client).to receive(:register!)
cli.execute!
end
Expand All @@ -153,21 +154,21 @@
end

it '--instance-data requires --url' do
cli = subject.new(%w{--instance-data /tmp/test})
cli = described_class.new(%w{--instance-data /tmp/test})
expect(string_logger).to receive(:error)
.with('Please use --instance-data only in combination with --url pointing to your SMT server')
cli.execute!
end

it '--instance-data is mutually exclusive with --regcode' do
cli = subject.new(%w{-r 123 --instance-data /tmp/test --url test})
cli = described_class.new(%w{-r 123 --instance-data /tmp/test --url test})
expect(string_logger).to receive(:error)
.with('Please use either --regcode or --instance-data')
cli.execute!
end

it '--url implies --write-config' do
cli = subject.new(%w{-r 123 --url http://foo.test.com})
cli = described_class.new(%w{-r 123 --url http://foo.test.com})
expect(cli.config.write_config).to eq true
allow_any_instance_of(SUSE::Connect::Client).to receive(:register!)
expect_any_instance_of(SUSE::Connect::Config).to receive(:write!)
Expand All @@ -176,16 +177,26 @@
end

context 'de-register command' do
let(:opts) { %w{--de-register} }

it '--de-register calls deregister! method' do
cli = subject.new(%w{--de-register})
expect_any_instance_of(Client).to receive(:deregister!)
cli.execute!
subject
end

context 'on unregistered system' do
before { allow(SUSE::Connect::System).to receive(:credentials).and_return(nil) }

it 'dies with error' do
expect(string_logger).to receive(:fatal).with(/Deregistration failed. Check if the system has been registered/)
subject
end
end
end

context 'cleanup command' do
it '--cleanup calls Systems cleanup! method' do
cli = subject.new(%w{--cleanup})
cli = described_class.new(%w{--cleanup})
expect(System).to receive(:cleanup!)
cli.execute!
end
Expand All @@ -194,20 +205,20 @@
context 'namespace option' do |_variables|
it '--namespace requires namespace' do
expect(string_logger).to receive(:error).with('Please provide a namespace')
subject.new('--namespace')
described_class.new('--namespace')
end
end

context 'status subcommand' do
it '--status calls json_product_status' do
cli = subject.new(%w{--status})
cli = described_class.new(%w{--status})
expect_any_instance_of(Client).to_not receive(:register!)
expect_any_instance_of(Status).to receive(:json_product_status)
cli.execute!
end

it '--status-text calls text_product_status' do
cli = subject.new(%w{--status-text})
cli = described_class.new(%w{--status-text})
expect_any_instance_of(Client).to_not receive(:register!)
expect_any_instance_of(Status).to receive(:text_product_status)
cli.execute!
Expand All @@ -217,7 +228,7 @@
describe 'list extensions subcommand' do
context 'on system with registered base product' do
it '--list-extensions lists all available extensions on the system' do
cli = subject.new(%w{--list-extensions})
cli = described_class.new(%w{--list-extensions})
expect_any_instance_of(Client).not_to receive(:register!)
expect_any_instance_of(Status).to receive(:print_extensions_list)
cli.execute!
Expand All @@ -227,12 +238,12 @@
context 'on system with no registered base product' do
it '--list-extensions exits with an error explaining that a base product has to be registered first' do
allow_any_instance_of(Status).to receive(:activated_base_product?).and_return(false)
cli = subject.new(%w{--list-extensions})
cli = described_class.new(%w{--list-extensions})
expect_any_instance_of(Client).not_to receive(:register!)
expect_any_instance_of(Status).not_to receive(:print_extensions_list)
expect(string_logger).to receive(:error)
.with(/To list extensions, you must first register the base product, using: SUSEConnect -r <registration code>/)
expect_any_instance_of(subject).to receive(:exit)
expect_any_instance_of(described_class).to receive(:exit)
cli.execute!
end
end
Expand All @@ -242,13 +253,13 @@
it '--rollback calls SUSE::Connect::Migration.rollback' do
expect_any_instance_of(Client).not_to receive(:register!)
expect(SUSE::Connect::Migration).to receive(:rollback)
subject.new(%w{--rollback})
described_class.new(%w{--rollback})
end
end

describe 'config write' do
it 'writes config if appropriate cli param been passed' do
cli = subject.new(%w{--write-config --status})
cli = described_class.new(%w{--write-config --status})
expect_any_instance_of(SUSE::Connect::Config).to receive(:write!)
allow_any_instance_of(Status).to receive(:print_product_statuses)
cli.execute!
Expand All @@ -259,75 +270,75 @@
describe '?extract_options' do
it 'sets token options' do
argv = %w{-r matoken}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:token]).to eq 'matoken'
end

it 'sets product options' do
argv = %w{--product sles/12/i386}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:product]).to eq Remote::Product.new(identifier: 'sles', version: '12', arch: 'i386')
end

it 'sets token options' do
argv = %w{--regcode matoken}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:token]).to eq 'matoken'
end

it 'sets email options' do
argv = %w{--email me@hotmail.com}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:email]).to eq 'me@hotmail.com'
end

it 'sets url options' do
argv = %w{--url test}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:url]).to eq 'test'
end

it 'puts version on version flag' do
argv = %w{--version}
expect_any_instance_of(subject).to receive(:puts).with(VERSION)
subject.new(argv)
expect_any_instance_of(described_class).to receive(:puts).with(VERSION)
described_class.new(argv)
end

it 'outputs help on help flag with no line longer than 80 characters' do
argv = %w{--help}
expect_any_instance_of(subject).to receive(:puts) do |option_parser|
expect_any_instance_of(described_class).to receive(:puts) do |option_parser|
expect(option_parser.instance_variable_get(:@opts).to_s.split("\n").map(&:length).max).to be <= 80
end
subject.new(argv)
described_class.new(argv)
end

it 'sets verbose options' do
argv = %w{--debug}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:debug]).to be true
end

it 'sets deregister option' do
argv = %w{--de-register}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:deregister]).to be true
end

it 'sets root option' do
argv = %w{--root /path/to/root}
subject.new(argv)
described_class.new(argv)
expect(SUSE::Connect::System.filesystem_root).to eq '/path/to/root'
SUSE::Connect::System.filesystem_root = nil
end

it 'requests status sub-command' do
argv = %w{--status}
expect(subject.new(argv).options[:status]).to be true
expect(described_class.new(argv).options[:status]).to be true
end

it 'sets write_config option' do
argv = %w{--write-config}
cli = subject.new(argv)
cli = described_class.new(argv)
expect(cli.options[:write_config]).to be true
end
end
Expand All @@ -336,23 +347,22 @@
it 'error on invalid product options format with hint where to find correct product identifiers' do
expect(string_logger).to receive(:error).with(/Please provide the product identifier in this format.*SUSEConnect --list-extensions/)
argv = %w{--product sles}
subject.new(argv)
described_class.new(argv)
end
end

describe '?check_if_param' do
it 'will exit with message if opt is nil' do
expect_any_instance_of(subject).to receive(:exit)
expect_any_instance_of(described_class).to receive(:exit)
expect(string_logger).to receive(:error).with('Kaboom')
subject.new({}).send(:check_if_param, nil, 'Kaboom')
cli.send(:check_if_param, nil, 'Kaboom')
end
end

describe 'reads environment variables' do
before { ENV['LANG'] = 'de' }

it 'sets language header based on LANG' do
# is ENV global?
ENV['LANG'] = 'de'
cli = subject.new([])
expect(cli.options[:language]).to eq 'de'
end
end
Expand Down

0 comments on commit d118d65

Please sign in to comment.