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.
Files changed (2) hide show
  1. data/bin/console-launcher +257 -0
  2. 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: []