-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for vCloud console access via WebMKS
With this commit we provide code needed for VMware vCloud Director's (i.e. CloudManager) console access to work. The code is similar to that of InfraManger, but with some important differences: * WebMKS SDK requires additional information (vmx location) * WebMKS SDK must know it's vCloud's VM to use uint8utf8 protocol (instead binary) * websocket proxy must connect to differently formed URL (port is part of URL, while actual port is always 443) Signed-off-by: Miha Pleško <miha.plesko@xlab.si>
- Loading branch information
1 parent
39f5e4e
commit 5c3f143
Showing
3 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
app/models/manageiq/providers/vmware/cloud_manager/vm/remote_console.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
98 changes: 98 additions & 0 deletions
98
spec/models/manageiq/providers/vmware/cloud_manager/vm/remote_console_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.update_attribute(: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.update_attribute(:raw_power_state, 'off') | ||
expect { vm.validate_remote_console_webmks_support }.to raise_error MiqException::RemoteConsoleNotSupportedError | ||
end | ||
|
||
it 'on vCloud 5.1' do | ||
ems.update_attribute(:api_version, '5.1') | ||
expect { vm.validate_remote_console_webmks_support }.to raise_error MiqException::RemoteConsoleNotSupportedError | ||
end | ||
end | ||
end |