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

Add support for vCloud console access via WebMKS #218

Merged
merged 1 commit into from
Apr 3, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions app/models/manageiq/providers/vmware/cloud_manager/vm.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class ManageIQ::Providers::Vmware::CloudManager::Vm < ManageIQ::Providers::CloudManager::Vm
include_concern 'Operations'
include_concern 'RemoteConsole'

supports :snapshots
supports :remove_all_snapshots
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module ManageIQ::Providers::Vmware::CloudManager::Vm::RemoteConsole
require_dependency 'securerandom'

def console_supported?(type)
%w(WEBMKS).include?(type.upcase)
end

def validate_remote_console_acquire_ticket(protocol, options = {})
raise(MiqException::RemoteConsoleNotSupportedError, "#{protocol} remote console requires the vm to be registered with a management system.") if ext_management_system.nil?
options[:check_if_running] = true unless options.key?(:check_if_running)
raise(MiqException::RemoteConsoleNotSupportedError, "#{protocol} remote console requires the vm to be running.") if options[:check_if_running] && state != "on"
end

def remote_console_acquire_ticket(userid, originating_server, protocol)
send("remote_console_#{protocol.to_s.downcase}_acquire_ticket", userid, originating_server)
end

def remote_console_acquire_ticket_queue(protocol, userid)
task_opts = {
:action => "Acquiring Vm #{name} #{protocol.to_s.upcase} remote console ticket for user #{userid}",
:userid => userid
}

queue_opts = {
:class_name => self.class.name,
:instance_id => id,
:method_name => 'remote_console_acquire_ticket',
:priority => MiqQueue::HIGH_PRIORITY,
:role => 'ems_operations',
:zone => my_zone,
:args => [userid, MiqServer.my_server.id, protocol]
}

MiqTask.generic_action_with_callback(task_opts, queue_opts)
end

#
# WebMKS
#

def remote_console_webmks_acquire_ticket(userid, originating_server = nil)
validate_remote_console_webmks_support
ticket = nil
ext_management_system.with_provider_connection do |service|
ticket = service.post_acquire_mks_ticket(ems_ref).body
end
raise(MiqException::RemoteConsoleNotSupportedError, 'Could not obtain WebMKS ticket') unless ticket && ticket[:Ticket]

SystemConsole.force_vm_invalid_token(id)

console_args = {
:user => User.find_by(:userid => userid),
:vm_id => id,
:ssl => true,
:protocol => 'webmks-uint8utf8',
:secret => ticket[:Ticket],
:url_secret => SecureRandom.hex,
:url => "/#{ticket[:Port]};#{ticket[:Ticket]}"
}
SystemConsole.launch_proxy_if_not_local(console_args, originating_server, ticket[:Host], 443).update(
:secret => 'is-in-url',
# vCloud specific querystring params
:is_vcloud => true,
:vmx => ticket[:Vmx]
)
end

def validate_remote_console_webmks_support
validate_remote_console_acquire_ticket('webmks')
if (api_version = ext_management_system.api_version.to_f) && api_version < 5.5
raise(MiqException::RemoteConsoleNotSupportedError, "vCloud version #{api_version} does not support WebMKS remote console.")
end
true
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
describe ManageIQ::Providers::Vmware::CloudManager::Vm::RemoteConsole do
let(:user) { FactoryGirl.create(:user) }
let(:ems) { FactoryGirl.create(:ems_vmware_cloud, :api_version => 5.5) }
let(:vm) { FactoryGirl.create(:vm_vcloud, :ext_management_system => ems, :raw_power_state => 'on') }

context '#remote_console_acquire_ticket' do
it 'with :webmks' do
expect(vm).to receive(:remote_console_webmks_acquire_ticket).with(user.userid, 1)
vm.remote_console_acquire_ticket(user.userid, 1, :webmks)
end
end

context '#remote_console_acquire_ticket_queue' do
let(:server) { double('MiqServer') }

before(:each) do
allow(vm).to receive_messages(:my_zone => nil)
allow(server).to receive_messages(:my_zone => nil)
allow(server).to receive_messages(:id => 1)
allow(MiqServer).to receive_messages(:my_server => server)
end

it 'with :webmks' do
vm.remote_console_acquire_ticket_queue(:webmks, user.userid)

q_all = MiqQueue.all
expect(q_all.length).to eq(1)
expect(q_all[0].method_name).to eq('remote_console_acquire_ticket')
expect(q_all[0].args).to eq([user.userid, 1, :webmks])
end
end

context '#remote_console_webmks_acquire_ticket' do
before(:each) do
allow(ems).to receive(:with_provider_connection).and_yield(connection)
allow(SecureRandom).to receive(:hex).and_return('hex')
end

let(:connection) { double('connection') }
let(:empty_response) { double('response', :body => {}) }
let(:response) do
double(
'response',
:body => {
:Ticket => 'ticket',
:Port => 1234,
:Host => 'host'
}
)
end

it 'performs validation' do
expect(connection).to receive(:post_acquire_mks_ticket).and_return(empty_response)
expect(vm).to receive(:validate_remote_console_webmks_support)
expect { vm.remote_console_webmks_acquire_ticket(user.userid) }.to raise_error MiqException::RemoteConsoleNotSupportedError
end

it 'launches proxy socket' do
expect(connection).to receive(:post_acquire_mks_ticket).and_return(response)
expect(SystemConsole).to receive(:launch_proxy_if_not_local).with(
{
:user => user,
:vm_id => vm.id,
:ssl => true,
:protocol => 'webmks-uint8utf8',
:secret => 'ticket',
:url_secret => 'hex',
:url => '/1234;ticket'
},
1, 'host', 443
).and_return({})
vm.remote_console_webmks_acquire_ticket(user.userid, 1)
end
end

context '#validate_remote_console_webmks_support' do
it 'normal case' do
ems.api_version = '5.5'
expect(vm.validate_remote_console_webmks_support).to be_truthy
end

it 'with vm with no ems' do
vm.ext_management_system = nil
vm.save!
expect { vm.validate_remote_console_webmks_support }.to raise_error MiqException::RemoteConsoleNotSupportedError
end

it 'with vm off' do
vm.raw_power_state = 'off'
expect { vm.validate_remote_console_webmks_support }.to raise_error MiqException::RemoteConsoleNotSupportedError
end

it 'on vCloud 5.1' do
ems.api_version = '5.1'
expect { vm.validate_remote_console_webmks_support }.to raise_error MiqException::RemoteConsoleNotSupportedError
end
end
end