cloudflock-qt 0.7.2
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.
- checksums.yaml +7 -0
- data/bin/qtflock +9 -0
- data/lib/cloudflock-qt.rb +13 -0
- data/lib/cloudflock-qt/app.rb +214 -0
- data/lib/cloudflock-qt/error.rb +19 -0
- data/lib/cloudflock-qt/results.rb +73 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 40697a3970659343568a5908dba4f69e9fbd8478
|
4
|
+
data.tar.gz: bb34bf94706b9419f410d4fdc27b17b0a39a31f6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5e82a619a4e95fe5c8b695217ef5a3d3fd7d810839ae39645fbb3e1d616533db494f55d7f88ad6a77b4887797427f2ee0f903db02507e2cffe8fbc620783c46
|
7
|
+
data.tar.gz: a647877f2cc388b44d7c32037729479c01a1aa514e467818d173462a9268c2f72fddaa5148de89cc324cc4854e7d1059b8363d7bc5b18c3b1ffccc4839c3d54e
|
data/bin/qtflock
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Required to work around bug in Windows binary gem.
|
2
|
+
# Issue: https://github.com/ryanmelt/qtbindings/issues/69
|
3
|
+
require 'thread'
|
4
|
+
require 'Qt'
|
5
|
+
require 'cloudflock/app'
|
6
|
+
require 'cloudflock/task/server-profile'
|
7
|
+
|
8
|
+
# Public: Namespace for any application built around the CloudFlock API with a
|
9
|
+
# Qt interface.
|
10
|
+
module CloudFlockQt
|
11
|
+
# Public: Version number of the current gem.
|
12
|
+
VERSION = '0.7.2'
|
13
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'cloudflock-qt'
|
2
|
+
require 'cloudflock-qt/error'
|
3
|
+
require 'cloudflock-qt/results'
|
4
|
+
|
5
|
+
module CloudFlockQt
|
6
|
+
# Public: Class to be used for the main window.
|
7
|
+
class App < Qt::MainWindow
|
8
|
+
include CloudFlock::App::Common
|
9
|
+
include CloudFlock::Remote
|
10
|
+
# Public: Width of the main form window in pixels.
|
11
|
+
WINDOW_WIDTH = 300
|
12
|
+
# Public: Height of the main form window in pixels.
|
13
|
+
WINDOW_HEIGHT = 220
|
14
|
+
# Public: Title of the main form window.
|
15
|
+
WINDOW_TITLE = "QtFlock Profile #{CloudFlockQt::VERSION}"
|
16
|
+
|
17
|
+
# Public: Height of each row in the form in pixels
|
18
|
+
FORM_LINE_HEIGHT = 30
|
19
|
+
|
20
|
+
# Public: Raised when information provided to log in to a host is
|
21
|
+
# incomplete.
|
22
|
+
class HostNotConfigured < StandardError; end
|
23
|
+
|
24
|
+
# Public: Set up application state and create the main application window,
|
25
|
+
# populating it with the form to take target host details.
|
26
|
+
def initialize
|
27
|
+
super
|
28
|
+
|
29
|
+
init_instance_variables
|
30
|
+
init_ui
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Internal: Set the default values for instance variables.
|
36
|
+
#
|
37
|
+
# Returns nothing.
|
38
|
+
def init_instance_variables
|
39
|
+
@hostname = ''
|
40
|
+
@username = 'root'
|
41
|
+
@password = ''
|
42
|
+
@root_password = ''
|
43
|
+
@port = '22'
|
44
|
+
@sudo = false
|
45
|
+
|
46
|
+
@lines = 0
|
47
|
+
end
|
48
|
+
|
49
|
+
# Internal: Set up the main window and add the form UI for target host
|
50
|
+
# definition.
|
51
|
+
#
|
52
|
+
# Returns nothing.
|
53
|
+
def init_ui
|
54
|
+
set_window_title WINDOW_TITLE
|
55
|
+
resize WINDOW_WIDTH, WINDOW_HEIGHT
|
56
|
+
|
57
|
+
file = menu_bar.add_menu('&File')
|
58
|
+
add_menu_item('E&xit', file, :quit)
|
59
|
+
|
60
|
+
build_main_form
|
61
|
+
|
62
|
+
show
|
63
|
+
end
|
64
|
+
|
65
|
+
# Internal: Build the form to collect data on the host to profile.
|
66
|
+
#
|
67
|
+
# Returns nothing.
|
68
|
+
def build_main_form
|
69
|
+
add_form_line_text('Hostname: ', :@hostname)
|
70
|
+
add_form_line_text('Username: ', :@username)
|
71
|
+
add_form_pass_text('Password: ', :@password)
|
72
|
+
add_form_pass_text('Root Password: ', :@root_password)
|
73
|
+
add_form_line_text('Port: ', :@port)
|
74
|
+
|
75
|
+
add_form_line_toggle('Use Sudo', :@sudo)
|
76
|
+
add_submit_button('Run Profile') { run_profile }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Internal: Add an entry to a menu (e.g. 'File'), and assign an action to
|
80
|
+
# it.
|
81
|
+
#
|
82
|
+
# item_text - String containing the text to be displayed. An '&' character
|
83
|
+
# preceding a character will cause that character to be a
|
84
|
+
# hotkey for the item.
|
85
|
+
# menu - Qt::Menu to contain the new entry.
|
86
|
+
# action - Action to be taken upon triggering the menu item.
|
87
|
+
#
|
88
|
+
# Returns nothing.
|
89
|
+
def add_menu_item(item_text, menu, action)
|
90
|
+
item = Qt::Action.new item_text, self
|
91
|
+
menu.add_action item
|
92
|
+
connect(item, SIGNAL(:triggered), Qt::Application.instance, SLOT(action))
|
93
|
+
end
|
94
|
+
|
95
|
+
# Internal: Create a text input field and corrsponding label.
|
96
|
+
#
|
97
|
+
# item_text - String with which to populate a text label.
|
98
|
+
# varname - Symbol containing the name of the instance variable with
|
99
|
+
# which to associate the form entry.
|
100
|
+
#
|
101
|
+
# Returns the Qt::LineEdit object.
|
102
|
+
def add_form_line_text(item_text, varname)
|
103
|
+
@lines += 1
|
104
|
+
|
105
|
+
label = Qt::Label.new self
|
106
|
+
label.set_text item_text
|
107
|
+
label.adjust_size
|
108
|
+
label.move(5, FORM_LINE_HEIGHT * @lines)
|
109
|
+
|
110
|
+
input = Qt::LineEdit.new self
|
111
|
+
input.set_geometry 105, FORM_LINE_HEIGHT * @lines - 10, 190, FORM_LINE_HEIGHT
|
112
|
+
input.connect(SIGNAL('textChanged(QString)')) do |string|
|
113
|
+
instance_variable_set(varname, string)
|
114
|
+
end
|
115
|
+
input.set_text instance_variable_get(varname)
|
116
|
+
|
117
|
+
input
|
118
|
+
end
|
119
|
+
|
120
|
+
# Internal: Wrap add_form_line_text, ensuring the the text display mode is
|
121
|
+
# appropriate for passwords.
|
122
|
+
#
|
123
|
+
# item_text - String with which to populate a text label.
|
124
|
+
# varname - Symbol containing the name of the instance variable with
|
125
|
+
# which to associate the form entry.
|
126
|
+
#
|
127
|
+
# Returns nothing.
|
128
|
+
def add_form_pass_text(item_text, varname)
|
129
|
+
add_form_line_text(item_text, varname).echoMode = Qt::LineEdit::Password
|
130
|
+
end
|
131
|
+
|
132
|
+
# Internal: Create a toggle button input field.
|
133
|
+
#
|
134
|
+
# item_text - String which will be displayed on the toggle button.
|
135
|
+
# varname - Symbol containing the name of the instance variable with
|
136
|
+
# which to associate the form entry.
|
137
|
+
# block - Optional block to attach to clicking the toggle.
|
138
|
+
#
|
139
|
+
# Returns nothing.
|
140
|
+
def add_form_line_toggle(item_text, varname, &block)
|
141
|
+
@lines += 1
|
142
|
+
|
143
|
+
toggle = Qt::PushButton.new item_text, self
|
144
|
+
toggle.set_checkable true
|
145
|
+
toggle.set_geometry 5, FORM_LINE_HEIGHT * @lines - 5, 80, 30
|
146
|
+
if block.nil?
|
147
|
+
toggle.connect(SIGNAL(:clicked)) do
|
148
|
+
instance_variable_set(varname, toggle.is_checked)
|
149
|
+
end
|
150
|
+
else
|
151
|
+
toggle.connect(SIGNAL(:clicked), &block)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Internal: Create a submit button.
|
156
|
+
#
|
157
|
+
# item_text - String which will be displayed on the toggle button.
|
158
|
+
# varname - Symbol containing the name of the instance variable with
|
159
|
+
# which to associate the form entry.
|
160
|
+
# block - Optional block to attach to clicking the toggle.
|
161
|
+
#
|
162
|
+
# Returns nothing.
|
163
|
+
def add_submit_button(item_text, &block)
|
164
|
+
submit = Qt::PushButton.new item_text, self
|
165
|
+
submit.set_geometry 175, FORM_LINE_HEIGHT * @lines - 5, 120, 30
|
166
|
+
submit.connect(SIGNAL(:clicked), &block)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Internal: Check that all necessary data is present, alerting the user if
|
170
|
+
# not. If everything appears present, attempt to profile the host.
|
171
|
+
#
|
172
|
+
# Returns nothing.
|
173
|
+
def run_profile
|
174
|
+
source_host = { hostname: @hostname, username: @username, port: @port,
|
175
|
+
password: @password, sudo: @sudo, ssh_key: '' }
|
176
|
+
check_source(source_host)
|
177
|
+
|
178
|
+
source_ssh = SSH.new(source_host)
|
179
|
+
profile = CloudFlock::Task::ServerProfile.new(source_ssh)
|
180
|
+
|
181
|
+
CloudFlockQt::ResultsWindow.new(profile)
|
182
|
+
rescue HostNotConfigured => e
|
183
|
+
CloudFlockQt::ErrorWindow.new(e.message)
|
184
|
+
rescue CloudFlock::Remote::SSH::InvalidHostname
|
185
|
+
CloudFlockQt::ErrorWindow.new("Unable to resolve '#{@hostname}'")
|
186
|
+
rescue Net::SSH::AuthenticationFailed
|
187
|
+
CloudFlockQt::ErrorWindow.new("Unable to log in as '#{@username}'")
|
188
|
+
rescue CloudFlock::Remote::SSH::SSHCannotConnect
|
189
|
+
CloudFlockQt::ErrorWindow.new("Cannot connect to #{@hostname}:#{@port}")
|
190
|
+
end
|
191
|
+
|
192
|
+
# Internal: Verify that all entries necessary for logging in to a remote
|
193
|
+
# host are present.
|
194
|
+
#
|
195
|
+
# Raises HostNotConfigured if any necessary information is not present.
|
196
|
+
#
|
197
|
+
# Returns nothing.
|
198
|
+
def check_source(host)
|
199
|
+
[:hostname, :username, :port].each do |option|
|
200
|
+
if host[option].to_s.empty?
|
201
|
+
raise(HostNotConfigured, "Missing #{option.to_s.capitalize}")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
host[:sudo] = false if host[:username] == 'root'
|
205
|
+
|
206
|
+
# If non-root and using su, the root password is needed
|
207
|
+
if host[:username] == 'root' || host[:sudo]
|
208
|
+
host[:root_password] = host[:password]
|
209
|
+
else
|
210
|
+
raise HostNotConfigured if host[:root_password].to_s.empty?
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cloudflock-qt'
|
2
|
+
|
3
|
+
module CloudFlockQt
|
4
|
+
# Public: Class to be used for error notifications.
|
5
|
+
class ErrorWindow < Qt::ErrorMessage
|
6
|
+
# Public: Width of the results window in pixels.
|
7
|
+
WINDOW_WIDTH = 300
|
8
|
+
# Public: Height of the results window in pixels.
|
9
|
+
WINDOW_HEIGHT = 150
|
10
|
+
|
11
|
+
# Public: Create and populate the window with results from profiling a
|
12
|
+
# remote host.
|
13
|
+
def initialize(message)
|
14
|
+
super()
|
15
|
+
|
16
|
+
show_message(message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'cloudflock-qt'
|
2
|
+
|
3
|
+
module CloudFlockQt
|
4
|
+
# Public: Class to be used for results windows.
|
5
|
+
class ResultsWindow < Qt::Widget
|
6
|
+
# Public: Width of the results window in pixels.
|
7
|
+
WINDOW_WIDTH = 400
|
8
|
+
# Public: Height of the results window in pixels.
|
9
|
+
WINDOW_HEIGHT = 500
|
10
|
+
|
11
|
+
# Public: Create and populate the window with results from profiling a
|
12
|
+
# remote host.
|
13
|
+
def initialize(profile)
|
14
|
+
super()
|
15
|
+
|
16
|
+
init_ui(profile)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Internal: Create the results window and text field, then populate it with
|
22
|
+
# the results of a host profile.
|
23
|
+
#
|
24
|
+
# profile - CloudFlock::Task::ServerProfile object.
|
25
|
+
#
|
26
|
+
# Returns nothing.
|
27
|
+
def init_ui(profile)
|
28
|
+
hostname = profile.select_entries(/System/, /Hostname/).first.to_s
|
29
|
+
|
30
|
+
set_window_title "Results for #{hostname}"
|
31
|
+
resize WINDOW_WIDTH, WINDOW_HEIGHT
|
32
|
+
|
33
|
+
results = Qt::TextEdit.new self
|
34
|
+
results.set_geometry 5, 5, WINDOW_WIDTH - 5, WINDOW_HEIGHT - 5
|
35
|
+
results.set_text generate_report(profile)
|
36
|
+
|
37
|
+
show
|
38
|
+
end
|
39
|
+
|
40
|
+
# Internal: Generate a String representation of the profile run against a
|
41
|
+
# remote host.
|
42
|
+
#
|
43
|
+
# profile - CloudFlock::Task::ServerProfile object.
|
44
|
+
#
|
45
|
+
# Returns a String.
|
46
|
+
def host_info(profile)
|
47
|
+
data = profile.map { |section| [section.title, distill_entries(section)] }
|
48
|
+
data.map { |section| section.join("\n") }.join("\n\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
# Internal: Filter any empty entries from a section, then map the rest to
|
52
|
+
# Strings.
|
53
|
+
#
|
54
|
+
# section - CloudFlock::Task::ServerProfile::Section
|
55
|
+
#
|
56
|
+
# Returns an Array containing Strings.
|
57
|
+
def distill_entries(section)
|
58
|
+
non_empty = section.entries.reject { |entry| entry.values.to_s.empty? }
|
59
|
+
non_empty.map { |entry| "#{entry.name}: #{entry.values}" }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Internal: Produce a human-readable report from the results of profiling a
|
63
|
+
# target host.
|
64
|
+
#
|
65
|
+
# profile - CloudFlock::Task::ServerProfile object.
|
66
|
+
#
|
67
|
+
# Returns a String.
|
68
|
+
def generate_report(profile)
|
69
|
+
profile_hash = profile.to_hash
|
70
|
+
host_info(profile_hash[:info])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudflock-qt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Wuest
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cloudflock
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.7'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.7.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.7'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.7.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: qtbindings
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '4.8'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '4.8'
|
47
|
+
description: Graphical frontend for CloudFlock in Qt
|
48
|
+
email: chris@chriswuest.com
|
49
|
+
executables:
|
50
|
+
- qtflock
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- bin/qtflock
|
55
|
+
- lib/cloudflock-qt.rb
|
56
|
+
- lib/cloudflock-qt/app.rb
|
57
|
+
- lib/cloudflock-qt/error.rb
|
58
|
+
- lib/cloudflock-qt/results.rb
|
59
|
+
homepage: http://github.com/cwuest/cloudflock-qt
|
60
|
+
licenses:
|
61
|
+
- Apache 2.0
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.2.2
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Unix migration automation
|
83
|
+
test_files: []
|