console-launcher 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/console-launcher +257 -0
- metadata +51 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2013 Red Hat Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
# This script calls the RHEV-M Virt API and creates callable cmd-lines
|
18
|
+
# to the remote viewer.
|
19
|
+
#
|
20
|
+
# written by:
|
21
|
+
# Juergen Hoffmann <buddy@redhat.com>
|
22
|
+
# Thomas Crowe <tcrowe@redhat.com>
|
23
|
+
# Vinny Valdez <vvaldez@redhat.com>
|
24
|
+
#
|
25
|
+
# May 14, 2013
|
26
|
+
# - initial version
|
27
|
+
#
|
28
|
+
# May 22, 2013
|
29
|
+
# - Made sure to strip http and https from the host definition
|
30
|
+
|
31
|
+
require 'rubygems'
|
32
|
+
require 'rest_client'
|
33
|
+
require 'xmlsimple'
|
34
|
+
require 'optparse'
|
35
|
+
require 'tempfile' # required to download the certificate files on they fly
|
36
|
+
require 'net/http'
|
37
|
+
require 'highline/import' # Secure Password Prompting if a user does not provide it when the script is called
|
38
|
+
|
39
|
+
# queries the User for a password
|
40
|
+
def get_password(prompt="RHEV-M Password: ")
|
41
|
+
ask(prompt) {|q| q.echo = "*"}
|
42
|
+
end
|
43
|
+
|
44
|
+
def strip_url(url)
|
45
|
+
# Remove any leading http or https from the host
|
46
|
+
url = url.split("://")[1] if url.include? "://"
|
47
|
+
return url
|
48
|
+
end
|
49
|
+
|
50
|
+
@options = {}
|
51
|
+
|
52
|
+
optparse = OptionParser.new do |opts|
|
53
|
+
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
54
|
+
|
55
|
+
@options[:print] = false
|
56
|
+
opts.on( '--print', 'Print the command to launch the Remote Viewer instead of executing it') do |directory|
|
57
|
+
@options[:print] = true
|
58
|
+
end
|
59
|
+
|
60
|
+
@options[:dryrun] = false
|
61
|
+
opts.on( '-d', '--dry-run', 'Do not execute the Remote Viewer Application') do |dryrun|
|
62
|
+
@options[:dryrun] = true
|
63
|
+
end
|
64
|
+
|
65
|
+
@options[:host] = nil
|
66
|
+
opts.on( '-h', '--host HOSTNAME', 'The Hostname of your RHEV-M Installation') do |host|
|
67
|
+
@options[:host] = strip_url(host)
|
68
|
+
end
|
69
|
+
|
70
|
+
@options[:user] = "admin@internal"
|
71
|
+
opts.on( '-u', '--username USERNAME', 'The Username used to establish the connection to --host (defaults to admin@internal)') do |u|
|
72
|
+
@options[:user] = u
|
73
|
+
end
|
74
|
+
|
75
|
+
@options[:pass] = nil
|
76
|
+
opts.on( '-p', '--password PASSWORD', 'The Password used to establish the connection to --host') do |pass|
|
77
|
+
@options[:pass] = pass
|
78
|
+
end
|
79
|
+
|
80
|
+
# This displays the help screen, all programs are
|
81
|
+
# assumed to have this option.
|
82
|
+
opts.on( '', '--help', 'Display this Help Message' ) do
|
83
|
+
puts ""
|
84
|
+
puts "This script connects to a RHEV-M Instance and lists all running VMs. You can choose which VM you want to"
|
85
|
+
puts "connect to via SPICE Protocol."
|
86
|
+
puts ""
|
87
|
+
puts "This script requires a working SPICE Client for your platform. You can get it from"
|
88
|
+
puts " - MacOSX: http://people.freedesktop.org/~teuf/spice-gtk-osx/dmg/0.3.1/"
|
89
|
+
puts " - Linux: TBD"
|
90
|
+
puts " - Windows: TBD"
|
91
|
+
puts ""
|
92
|
+
puts opts
|
93
|
+
exit
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Parse the command-line. Remember there are two forms
|
98
|
+
# of the parse method. The 'parse' method simply parses
|
99
|
+
# ARGV, while the 'parse!' method parses ARGV and removes
|
100
|
+
# any @options found there, as well as any parameters for
|
101
|
+
# the @options. What's left is the list of files to resize.
|
102
|
+
optparse.parse!
|
103
|
+
|
104
|
+
if @options[:host] == nil
|
105
|
+
puts "ERROR: You have to configure RHEV-M Hostname to connect to"
|
106
|
+
puts optparse.help
|
107
|
+
exit 1
|
108
|
+
end
|
109
|
+
|
110
|
+
@options[:pass] = get_password if @options[:pass] == nil
|
111
|
+
|
112
|
+
class VM
|
113
|
+
attr_accessor :id, :name, :description, :host_uuid, :state, :port, :secure_port, :address
|
114
|
+
|
115
|
+
def initialize(vm)
|
116
|
+
@id = vm['id']
|
117
|
+
@name = vm['name']
|
118
|
+
@description = vm['description']
|
119
|
+
@address = vm['display']['address'] unless vm['display'].nil?
|
120
|
+
@port = vm['display']['port'] unless vm['display'].nil?
|
121
|
+
@secure_port = vm['display']['secure_port'] unless vm['display'].nil?
|
122
|
+
@state = vm['status']['state'] unless vm['status'].nil?
|
123
|
+
@host_uuid = vm['host']['id'] unless vm['host'].nil?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# download the certificate file on the fly
|
129
|
+
begin
|
130
|
+
cert = Tempfile.new(@options[:host] + ".crt")
|
131
|
+
Net::HTTP.start(@options[:host]) do |http|
|
132
|
+
begin
|
133
|
+
http.request_get('/ca.crt') do |resp|
|
134
|
+
resp.read_body do |segment|
|
135
|
+
cert.write(segment)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
ensure
|
139
|
+
cert.close()
|
140
|
+
end
|
141
|
+
end
|
142
|
+
@cert = cert.path
|
143
|
+
rescue => e
|
144
|
+
puts "There has been an error downloading the certificate file from #{@options[:host]}"
|
145
|
+
e.message
|
146
|
+
exit 1
|
147
|
+
end
|
148
|
+
|
149
|
+
# Create a little helper object that we will use to
|
150
|
+
# make connections to the REST API
|
151
|
+
@rhevm = RestClient::Resource.new(
|
152
|
+
"https://" + @options[:host],
|
153
|
+
:user => @options[:user],
|
154
|
+
:password => @options[:pass],
|
155
|
+
:ssl_ca_cert => @cert,
|
156
|
+
:ssl_version => "SSLv3",
|
157
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
158
|
+
|
159
|
+
def get_vms(vms_data)
|
160
|
+
# Iterate through the VM's and get all the
|
161
|
+
# required information
|
162
|
+
@vms = Array.new # Clear out array
|
163
|
+
vms_data['vm'].each do |vm|
|
164
|
+
# Making sure we only consider VM's that are in state up (so they do have a console to connect to)
|
165
|
+
# and that have the spice protocol enabled as the connection mode
|
166
|
+
if vm['status']['state'] == "up" && vm['display']['type'] == "spice"
|
167
|
+
@vms.push(VM.new(vm))
|
168
|
+
end
|
169
|
+
end
|
170
|
+
return @vms
|
171
|
+
end
|
172
|
+
|
173
|
+
def launch_viewer(index)
|
174
|
+
vm = @vms[index-1]
|
175
|
+
|
176
|
+
# let us no gather the host subject
|
177
|
+
hosts_data = XmlSimple.xml_in(@rhevm["/api/hosts/"+vm.host_uuid].get.body, { 'ForceArray' => false })
|
178
|
+
host_subject = hosts_data['certificate']['subject']
|
179
|
+
|
180
|
+
ticket_data = XmlSimple.xml_in(@rhevm["/api/vms/" + vm.id + "/ticket"].post("<action><ticket><expiry>300</expiry></ticket></action>", :content_type => 'application/xml').body, { 'ForceArray' => false })
|
181
|
+
password = ticket_data['ticket']['value']
|
182
|
+
|
183
|
+
# Creating the .vv File for the connection
|
184
|
+
# download the certificate file on the fly
|
185
|
+
vv = Tempfile.new("#{vm.name}.vv")
|
186
|
+
begin
|
187
|
+
vv.puts("[virt-viewer]")
|
188
|
+
vv.puts("type=spice")
|
189
|
+
vv.puts("host=#{vm.address}")
|
190
|
+
vv.puts("port=#{vm.port}")
|
191
|
+
vv.puts("password=#{password}")
|
192
|
+
vv.puts("tls-port=#{vm.secure_port}")
|
193
|
+
vv.puts("fullscreen=0")
|
194
|
+
vv.puts("title=vm:#{vm.name} - %d - Press SHIFT+F12 to Release Cursor")
|
195
|
+
vv.puts("enable-smartcard=0")
|
196
|
+
vv.puts("enable-usb-autoshare=1")
|
197
|
+
vv.puts("usb-filter=-1,-1,-1,-1,0")
|
198
|
+
vv.puts("host-subject=#{host_subject}")
|
199
|
+
vv.puts("toggle-fullscreen=shift+f11")
|
200
|
+
vv.puts("release-cursor=shift+f12")
|
201
|
+
ensure
|
202
|
+
vv.close()
|
203
|
+
end
|
204
|
+
|
205
|
+
# Now that we have all the information we can print the cmd line
|
206
|
+
puts "Console to VM: #{vm.name} state: #{vm.state} is started"
|
207
|
+
command = "/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer --spice-ca-file #{@cert} #{vv.path}"
|
208
|
+
puts command if @options[:print]
|
209
|
+
unless @options[:dryrun]
|
210
|
+
(pid = fork) ? Process.detach(pid) : exec(command)
|
211
|
+
end
|
212
|
+
puts "Reloading Virtual Machines Selection Menu ..."
|
213
|
+
sleep(5)
|
214
|
+
end
|
215
|
+
|
216
|
+
while true do
|
217
|
+
begin
|
218
|
+
@vms = Array.new # Clear out array
|
219
|
+
# get the vms api and get the list of vms
|
220
|
+
vms_data = XmlSimple.xml_in(@rhevm["/api/vms"].get.body, { 'ForceArray' => false })
|
221
|
+
@vms = get_vms(vms_data)
|
222
|
+
# Print the selection to the User
|
223
|
+
puts
|
224
|
+
puts "Running Virtual Machines found for #{@options[:host]}:"
|
225
|
+
@vms.each_with_index do |v, index|
|
226
|
+
puts "#{index+1}. Name: #{v.name} Description: #{v.description} State: #{v.state}"
|
227
|
+
end
|
228
|
+
puts
|
229
|
+
puts "r. Refresh"
|
230
|
+
puts "q. Quit"
|
231
|
+
puts
|
232
|
+
|
233
|
+
puts "Please select the VM you wish to open: "
|
234
|
+
|
235
|
+
STDOUT.flush
|
236
|
+
index = gets.chomp # Hackish, just wanting to add quit
|
237
|
+
if index.to_s == "q"
|
238
|
+
exit 0
|
239
|
+
elsif index.to_s == "r"
|
240
|
+
next
|
241
|
+
end
|
242
|
+
index = index.to_i
|
243
|
+
if (1..@vms.size).member?(index)
|
244
|
+
launch_viewer(index)
|
245
|
+
else
|
246
|
+
puts "ERROR: Your selection #{index} is out of range."
|
247
|
+
end
|
248
|
+
rescue => e
|
249
|
+
puts "There was an error retrieving the Virtual Machines from #{@options[:host]}: #{e.message}"
|
250
|
+
puts e.backtrace
|
251
|
+
exit 1
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
exit 0
|
256
|
+
|
257
|
+
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: console-launcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Juergen Hoffmann
|
9
|
+
- Vinny Valdez
|
10
|
+
- Thomas Crowe
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2013-05-23 00:00:00.000000000 Z
|
15
|
+
dependencies: []
|
16
|
+
description: This gem provides the ability to launch console sessions on Mac
|
17
|
+
email:
|
18
|
+
- buddy@redhat.com
|
19
|
+
- vvaldez@redhat.com
|
20
|
+
- tcrowe@redhat.com
|
21
|
+
executables:
|
22
|
+
- console-launcher
|
23
|
+
extensions: []
|
24
|
+
extra_rdoc_files: []
|
25
|
+
files:
|
26
|
+
- bin/console-launcher
|
27
|
+
homepage: https://github.com/juhoffma/rhev-console-launcher
|
28
|
+
licenses: []
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 1.8.24
|
48
|
+
signing_key:
|
49
|
+
specification_version: 3
|
50
|
+
summary: RHEV-M Console Launcher
|
51
|
+
test_files: []
|