console-launcher 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/bin/console-launcher +12 -27
- data/lib/console-launcher.rb +142 -89
- data/lib/console-launcher_version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NTU4NDAyMmFiMTAwNDZjYjNiODRkMTRmODg1MDcxOGFhZjNhYjFkMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjQ2ODFhMWNjZWIwNTg3ZjQ0MzIyMmRkNjFjMWJhZTFlNDIxODk5ZQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTQ4MDA2ZjEwZDAyZWJmZDMyYzgxMDliNGVkZDNjOWYwOGMzNWNmMmM1Y2U0
|
10
|
+
ZjdjYmU2MGEzYzc4ZDZiNDI0OWRjYjVjZTkyMjRmYzMzZDViYmFjZTFiNzFk
|
11
|
+
MzkxZmEzZjcyMDNmNjJlMTlmMWUyODExYTQ5ZjhmNTg0NmE4Njc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZWYzM2U2ZWFjZDlkMWQ3MjhjMWM4MDBjOWE5OTg1ODIxZmU1YTA3MTQ2NzIx
|
14
|
+
ZTE2YzE2NzgxN2Y5MzkyMjI0ZGVmMzZlNTYwNmQyODhkNjYzZTMwYzM4Y2M4
|
15
|
+
Zjg5NTUwMDc0ZmQ5ODdkYWVlY2JjZWM3ZDIyYjBkNGRmMWRiN2M=
|
data/bin/console-launcher
CHANGED
@@ -35,45 +35,30 @@ require 'optparse'
|
|
35
35
|
require 'yaml'
|
36
36
|
include Helper
|
37
37
|
|
38
|
-
|
39
|
-
print: false,
|
40
|
-
dryrun: false,
|
41
|
-
host: nil,
|
42
|
-
user: "admin@internal",
|
43
|
-
pass: nil
|
44
|
-
}
|
45
|
-
|
46
|
-
CONFIG_FILE = File.join(ENV['HOME'], '.config-launcher.rc.yaml')
|
47
|
-
if File.exists? CONFIG_FILE
|
48
|
-
config_options = YAML.load_file(CONFIG_FILE)
|
49
|
-
options.merge!(config_options)
|
50
|
-
else
|
51
|
-
File.open(CONFIG_FILE, 'w') { |file| YAML::dump(options, file) }
|
52
|
-
STDERR.puts "Initialized configuration file in #{CONFIG_FILE}"
|
53
|
-
end
|
38
|
+
Helper.load_options
|
54
39
|
|
55
40
|
optparse = OptionParser.new do |opts|
|
56
41
|
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
57
42
|
|
58
43
|
|
59
44
|
opts.on('--print', 'Print the command that is called to launch the Console Session') do
|
60
|
-
|
45
|
+
Helper::OPTIONS[:print] = true
|
61
46
|
end
|
62
47
|
|
63
48
|
opts.on('-d', '--dry-run', 'Do not execute the Remote Viewer Application') do
|
64
|
-
|
49
|
+
Helper::OPTIONS[:dryrun] = true
|
65
50
|
end
|
66
51
|
|
67
52
|
opts.on('-h', '--host HOSTNAME', 'The Hostname of your RHEV-M Installation') do |host|
|
68
|
-
|
53
|
+
Helper::OPTIONS[:host] = strip_url(host)
|
69
54
|
end
|
70
55
|
|
71
56
|
opts.on('-u', '--username USERNAME', 'The Username used to establish the connection to --host (defaults to admin@internal)') do |u|
|
72
|
-
|
57
|
+
Helper::OPTIONS[:user] = u
|
73
58
|
end
|
74
59
|
|
75
60
|
opts.on('-p', '--password PASSWORD', 'The Password used to establish the connection to --host') do |pass|
|
76
|
-
|
61
|
+
Helper::OPTIONS[:pass] = pass
|
77
62
|
end
|
78
63
|
|
79
64
|
# This displays the help screen, all programs are
|
@@ -102,15 +87,15 @@ end
|
|
102
87
|
# the @options. What's left is the list of files to resize.
|
103
88
|
optparse.parse!
|
104
89
|
|
105
|
-
if
|
90
|
+
if Helper::OPTIONS[:host] == nil
|
106
91
|
puts "ERROR: You have to configure RHEV-M Hostname to connect to"
|
107
92
|
puts optparse.help
|
108
93
|
exit 1
|
109
94
|
end
|
110
95
|
|
111
|
-
|
96
|
+
Helper::OPTIONS[:pass] = get_password() if Helper::OPTIONS[:pass] == nil
|
112
97
|
|
113
|
-
rhevm = RhevManager.new(
|
98
|
+
rhevm = RhevManager.new(Helper::OPTIONS[:host], Helper::OPTIONS[:user], Helper::OPTIONS[:pass])
|
114
99
|
|
115
100
|
while true do
|
116
101
|
begin
|
@@ -118,7 +103,7 @@ while true do
|
|
118
103
|
|
119
104
|
# Print the selection to the User
|
120
105
|
puts
|
121
|
-
puts "Running Virtual Machines found for #{
|
106
|
+
puts "Running Virtual Machines found for #{Helper::OPTIONS[:host]}:"
|
122
107
|
vms.each_with_index do |v, index|
|
123
108
|
puts "#{index+1}. Name: #{v.name} Description: #{v.description} State: #{v.state}"
|
124
109
|
end
|
@@ -140,8 +125,8 @@ while true do
|
|
140
125
|
|
141
126
|
if (1..vms.size).member?(index)
|
142
127
|
command = rhevm.launch_viewer(index)
|
143
|
-
puts command if
|
144
|
-
unless
|
128
|
+
puts command if Helper::OPTIONS[:print]
|
129
|
+
unless Helper::OPTIONS[:dryrun]
|
145
130
|
pid = Process.fork
|
146
131
|
|
147
132
|
if pid.nil?
|
data/lib/console-launcher.rb
CHANGED
@@ -12,6 +12,12 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
# Author:: Juergen Hoffmann (mailto:buddy@redhat.com)
|
16
|
+
# Author:: Vinny Valdez (mailto:vvaldez@redhat.com)
|
17
|
+
# Author:: Thomas Crowe (mailto:tcrowe@redhat.com)
|
18
|
+
# Copyright:: Copyright (c) 2013 Red Hat Inc.
|
19
|
+
# License:: http://www.apache.org/licenses/LICENSE-2.0
|
20
|
+
|
15
21
|
require 'rubygems'
|
16
22
|
require 'rest_client'
|
17
23
|
require 'xmlsimple'
|
@@ -19,121 +25,168 @@ require 'tmpdir' # required to download the certificate files on they fly
|
|
19
25
|
require 'net/http'
|
20
26
|
require 'highline/import' # Secure Password Prompting if a user does not provide it when the script is called
|
21
27
|
require 'rhev-manager/virtual-machine'
|
28
|
+
require 'rbconfig'
|
29
|
+
|
30
|
+
# This class provides utility methods to encapsulates RESTful access to the RHEV Manager.
|
31
|
+
# Since the returned response is in XML this class transforms the XML Response into Ruby Objects.
|
32
|
+
|
33
|
+
class RhevManager
|
34
|
+
|
35
|
+
TMP_DIR = Dir.tmpdir
|
36
|
+
|
37
|
+
def initialize(host, user, password)
|
38
|
+
@host = host
|
39
|
+
@user = user
|
40
|
+
@pass = password
|
41
|
+
|
42
|
+
# Create a little helper object that we will use to
|
43
|
+
# make connections to the REST API
|
44
|
+
@rhevm = RestClient::Resource.new(
|
45
|
+
"https://" + @host,
|
46
|
+
:user => @user,
|
47
|
+
:password => @pass,
|
48
|
+
:ssl_ca_cert => @cert,
|
49
|
+
:ssl_version => "SSLv3",
|
50
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
51
|
+
get_cert
|
52
|
+
end
|
22
53
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# Create a little helper object that we will use to
|
33
|
-
# make connections to the REST API
|
34
|
-
@rhevm = RestClient::Resource.new(
|
35
|
-
"https://" + @host,
|
36
|
-
:user => @user,
|
37
|
-
:password => @pass,
|
38
|
-
:ssl_ca_cert => @cert,
|
39
|
-
:ssl_version => "SSLv3",
|
40
|
-
:verify_ssl => OpenSSL::SSL::VERIFY_NONE)
|
41
|
-
get_cert
|
42
|
-
end
|
43
|
-
|
44
|
-
def get_cert()
|
45
|
-
# download the certificate file on the fly
|
46
|
-
begin
|
47
|
-
cert = File.new(TMP_DIR + "/" + @host + ".crt", "w+")
|
48
|
-
Net::HTTP.start(@host) do |http|
|
49
|
-
begin
|
50
|
-
http.request_get('/ca.crt') do |resp|
|
51
|
-
resp.read_body do |segment|
|
52
|
-
cert.write(segment)
|
53
|
-
end
|
54
|
+
# Download the Server SSL Certificate file on the fly
|
55
|
+
def get_cert()
|
56
|
+
begin
|
57
|
+
cert = File.new(TMP_DIR + "/" + @host + ".crt", "w+")
|
58
|
+
Net::HTTP.start(@host) do |http|
|
59
|
+
begin
|
60
|
+
http.request_get('/ca.crt') do |resp|
|
61
|
+
resp.read_body do |segment|
|
62
|
+
cert.write(segment)
|
54
63
|
end
|
55
|
-
ensure
|
56
|
-
cert.close()
|
57
64
|
end
|
65
|
+
ensure
|
66
|
+
cert.close()
|
58
67
|
end
|
59
|
-
@cert = cert.path
|
60
|
-
rescue => e
|
61
|
-
raise "There has been an error downloading the certificate file from #{@host}: #{e.message}"
|
62
68
|
end
|
69
|
+
@cert = cert.path
|
70
|
+
rescue => e
|
71
|
+
raise "There has been an error downloading the certificate file from #{@host}: #{e.message}"
|
63
72
|
end
|
73
|
+
end
|
64
74
|
|
65
|
-
|
66
|
-
@vms = Array.new # Clear out array
|
67
|
-
# get the vms api and get the list of vms
|
68
|
-
vms_data = XmlSimple.xml_in(@rhevm["/api/vms"].get.body, {'ForceArray' => false})
|
69
|
-
|
70
|
-
# Iterate through the VM's and get all the
|
71
|
-
# required information
|
72
|
-
vms_data['vm'].each do |vm|
|
73
|
-
# Making sure we only consider VM's that are in state up (so they do have a console to connect to)
|
74
|
-
# and that have the spice protocol enabled as the connection mode
|
75
|
-
if vm['status']['state'] == "up" && vm['display']['type'] == "spice"
|
76
|
-
@vms.push(VirtualMachine.new(vm))
|
77
|
-
end
|
78
|
-
end
|
79
|
-
return @vms
|
80
|
-
end
|
75
|
+
# Returns an array of VirtualMachine ruby objects that are running on the RHEV Manager
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
host_subject = hosts_data['certificate']['subject']
|
88
|
-
|
89
|
-
ticket_data = XmlSimple.xml_in(@rhevm["/api/vms/" + vm.id + "/ticket"].post("<action><ticket><expiry>30</expiry></ticket></action>", :content_type => 'application/xml').body, {'ForceArray' => false})
|
90
|
-
password = ticket_data['ticket']['value']
|
91
|
-
|
92
|
-
# Creating the .vv File for the connection
|
93
|
-
# download the certificate file on the fly
|
94
|
-
@vv = File.new(TMP_DIR + "/" + vm.name + ".vv", "w+")
|
95
|
-
begin
|
96
|
-
@vv.puts("[virt-viewer]")
|
97
|
-
@vv.puts("type=spice")
|
98
|
-
@vv.puts("host=#{vm.address}")
|
99
|
-
@vv.puts("port=#{vm.port}")
|
100
|
-
@vv.puts("password=#{password}")
|
101
|
-
@vv.puts("tls-port=#{vm.secure_port}")
|
102
|
-
@vv.puts("fullscreen=0")
|
103
|
-
@vv.puts("title=vm:#{vm.name} - %d - Press SHIFT+F12 to Release Cursor")
|
104
|
-
@vv.puts("enable-smartcard=0")
|
105
|
-
@vv.puts("enable-usb-autoshare=1")
|
106
|
-
@vv.puts("usb-filter=-1,-1,-1,-1,0")
|
107
|
-
@vv.puts("host-subject=#{host_subject}")
|
108
|
-
@vv.puts("toggle-fullscreen=shift+f11")
|
109
|
-
@vv.puts("release-cursor=shift+f12")
|
110
|
-
ensure
|
111
|
-
@vv.close()
|
112
|
-
end
|
77
|
+
def get_vms()
|
78
|
+
@vms = Array.new # Clear out array
|
79
|
+
|
80
|
+
# get the vms api and get the list of vms
|
81
|
+
vms_data = XmlSimple.xml_in(@rhevm["/api/vms"].get.body, {'ForceArray' => false})
|
113
82
|
|
114
|
-
|
115
|
-
|
83
|
+
# Iterate through the VM's and get all the
|
84
|
+
# required information
|
85
|
+
vms_data['vm'].each do |vm|
|
86
|
+
# Making sure we only consider VM's that are in state up (so they do have a console to connect to)
|
87
|
+
# and that have the spice protocol enabled as the connection mode
|
88
|
+
if vm['status']['state'] == "up" && vm['display']['type'] == "spice"
|
89
|
+
@vms.push(VirtualMachine.new(vm))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return @vms
|
93
|
+
end
|
116
94
|
|
117
|
-
|
95
|
+
# This method takes an index that is used to query the VirtualMachine Array for the VM that is supposed to
|
96
|
+
# be started. It then queries the RHEV Manager for the correct subject and then requests a ticket for the
|
97
|
+
# console session.
|
98
|
+
# It then creates a .vv file that is used to be passed to the RemoteViewer Application. It returns the command
|
99
|
+
# to be launched because we fork the process and detach from the RemoteViewer process so we are able to launch
|
100
|
+
# more than one Console Session at once.
|
101
|
+
def launch_viewer(index)
|
102
|
+
vm = @vms[index-1]
|
103
|
+
|
104
|
+
# let us no gather the host subject
|
105
|
+
hosts_data = XmlSimple.xml_in(@rhevm["/api/hosts/"+vm.host_uuid].get.body, {'ForceArray' => false})
|
106
|
+
host_subject = hosts_data['certificate']['subject']
|
107
|
+
|
108
|
+
ticket_data = XmlSimple.xml_in(@rhevm["/api/vms/" + vm.id + "/ticket"].post("<action><ticket><expiry>30</expiry></ticket></action>", :content_type => 'application/xml').body, {'ForceArray' => false})
|
109
|
+
password = ticket_data['ticket']['value']
|
110
|
+
|
111
|
+
# Creating the .vv File for the connection
|
112
|
+
# download the certificate file on the fly
|
113
|
+
@vv = File.new(TMP_DIR + "/" + vm.name + ".vv", "w+")
|
114
|
+
begin
|
115
|
+
@vv.puts("[virt-viewer]")
|
116
|
+
@vv.puts("type=spice")
|
117
|
+
@vv.puts("host=#{vm.address}")
|
118
|
+
@vv.puts("port=#{vm.port}")
|
119
|
+
@vv.puts("password=#{password}")
|
120
|
+
@vv.puts("tls-port=#{vm.secure_port}")
|
121
|
+
@vv.puts("fullscreen=0")
|
122
|
+
@vv.puts("title=vm:#{vm.name} - %d - Press SHIFT+F12 to Release Cursor")
|
123
|
+
@vv.puts("enable-smartcard=0")
|
124
|
+
@vv.puts("enable-usb-autoshare=1")
|
125
|
+
@vv.puts("usb-filter=-1,-1,-1,-1,0")
|
126
|
+
@vv.puts("host-subject=#{host_subject}")
|
127
|
+
@vv.puts("toggle-fullscreen=shift+f11")
|
128
|
+
@vv.puts("release-cursor=shift+f12")
|
129
|
+
ensure
|
130
|
+
@vv.close()
|
118
131
|
end
|
119
132
|
|
133
|
+
# Now that we have all the information we can print the cmd line
|
134
|
+
puts "Console to VM: #{vm.name} state: #{vm.state} is started"
|
120
135
|
|
136
|
+
command = "#{Helper::OPTIONS[:viewer]} --spice-ca-file #{@cert} #{@vv.path}"
|
121
137
|
end
|
122
138
|
|
139
|
+
|
140
|
+
end
|
141
|
+
|
123
142
|
module Helper
|
124
143
|
|
144
|
+
CONFIG_FILE = File.join(ENV['HOME'], '.console-launcher.rc.yaml')
|
145
|
+
|
146
|
+
OPTIONS = {
|
147
|
+
print: false,
|
148
|
+
dryrun: false,
|
149
|
+
host: nil,
|
150
|
+
user: "admin@internal",
|
151
|
+
pass: nil
|
152
|
+
}
|
153
|
+
|
154
|
+
OPTIONS[:viewer] = case RbConfig::CONFIG['host_os']
|
155
|
+
when /mac|darwin/ then
|
156
|
+
"/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer"
|
157
|
+
when /linux|bsd|cygwin/ then
|
158
|
+
"/usr/bin/remote-viewer"
|
159
|
+
when /mswin|mingw/ then
|
160
|
+
"C:/Program Files/VirtViewer/bin/remote-viewer.exe"
|
161
|
+
# when /solaris|sunos/ then :Linux # needs testing..
|
162
|
+
else
|
163
|
+
raise "Your OS(#{ RbConfig::CONFIG['host_os'] }) is not yet supported"
|
164
|
+
end
|
165
|
+
|
166
|
+
def load_options
|
167
|
+
if File.exists? CONFIG_FILE
|
168
|
+
config_options = YAML.load_file(CONFIG_FILE)
|
169
|
+
OPTIONS.merge!(config_options)
|
170
|
+
|
171
|
+
unless config_options.has_key?(:viewer)
|
172
|
+
File.open(CONFIG_FILE, 'w') { |file| YAML::dump(OPTIONS, file) }
|
173
|
+
end
|
174
|
+
else
|
175
|
+
File.open(CONFIG_FILE, 'w') { |file| YAML::dump(OPTIONS, file) }
|
176
|
+
STDERR.puts "Initialized configuration file in #{CONFIG_FILE}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
125
180
|
# queries the User for a password
|
126
181
|
def get_password(prompt="RHEV-M Password: ")
|
127
182
|
ask(prompt) { |q| q.echo = "*" }
|
128
183
|
end
|
129
184
|
|
185
|
+
# Remove any leading http or https from the host
|
130
186
|
def strip_url(url)
|
131
|
-
# Remove any leading http or https from the host
|
132
187
|
url = url.split("://")[1] if url.include? "://"
|
133
188
|
return url
|
134
189
|
end
|
135
190
|
|
136
|
-
def initialize
|
137
191
|
|
138
|
-
end
|
139
192
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: console-launcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juergen Hoffmann
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-05-
|
13
|
+
date: 2013-05-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rest-client
|