vpsadmin-client 3.0.0.master.20190517.pre.0.3ab5ddfe → 3.0.0.master.20220121.pre.0.b5a81113
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 +4 -4
- data/README.md +13 -11
- data/lib/vpsadmin/cli/commands/vps_remote_console.rb +184 -58
- data/lib/vpsadmin/client/version.rb +1 -1
- data/vpsadmin-client.gemspec +1 -3
- metadata +8 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce5635948bc213752357b413d4e92f8b7f2089306b9a3e02194b76f44f3617c3
|
4
|
+
data.tar.gz: 4304acd24bbecf0389a954d61ce680fece999e1128651f84e75306cf61889195
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3c0c9029f6d14639adb9f901f4b1cc133d1518360be85d8e506e8aa285fa5a1b3e8be5cfa475ae87d8147fadf78dd55bd168593e945f59c1dc237412f714705
|
7
|
+
data.tar.gz: 35e2c3b730bf246d1a14c0a6a7cdf77c08910efa4d460aeb878a52a9d4a0210058a7450c556c7e30a08199b011464a45b17b155b13d965c2da057e14a3878309
|
data/README.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
# vpsAdmin client
|
2
2
|
|
3
|
-
|
3
|
+
vpsAdmin client is a Ruby CLI and client library for vpsAdmin API. It is based
|
4
|
+
on [haveapi-client](https://github.com/vpsfreecz/haveapi/tree/master/clients/ruby).
|
5
|
+
|
6
|
+
vpsAdmin client extends `haveapi-client` with several command-line operations
|
7
|
+
specific to vpsAdmin, including:
|
8
|
+
|
9
|
+
- VPS remote console
|
10
|
+
- Snapshot downloads, either ZFS streams or tar archives
|
11
|
+
- Automated utility for local backups using ZFS
|
12
|
+
- Live IP traffic monitor
|
4
13
|
|
5
14
|
## Installation
|
6
15
|
|
@@ -17,13 +26,6 @@ Or install it yourself as:
|
|
17
26
|
$ gem install vpsadmin-client
|
18
27
|
|
19
28
|
## Usage
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
## Contributing
|
24
|
-
|
25
|
-
1. Fork it ( https://github.com/[my-github-username]/vpsadminctl/fork )
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create a new Pull Request
|
29
|
+
See
|
30
|
+
[haveapi-client](https://github.com/vpsfreecz/haveapi/tree/master/clients/ruby)
|
31
|
+
for usage information.
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'em-http'
|
1
|
+
require 'thread'
|
3
2
|
require 'time'
|
4
3
|
require 'json'
|
5
4
|
require 'base64'
|
@@ -11,16 +10,35 @@ module VpsAdmin::CLI::Commands
|
|
11
10
|
args 'VPS_ID'
|
12
11
|
desc 'Open VPS remote console'
|
13
12
|
|
14
|
-
class InputHandler
|
15
|
-
|
16
|
-
|
17
|
-
def initialize
|
13
|
+
class InputHandler
|
14
|
+
def initialize(http_client)
|
15
|
+
@http_client = http_client
|
18
16
|
@private_buffer = ''
|
19
|
-
@buffer = ''
|
20
17
|
@end_seq = ["\r", "\e", "."]
|
21
18
|
@end_i = 0
|
19
|
+
@stop = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_from(io)
|
23
|
+
begin
|
24
|
+
data = io.read_nonblock(4096)
|
25
|
+
rescue IO::WaitReadable
|
26
|
+
return
|
27
|
+
rescue Errno::EIO
|
28
|
+
stop
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
write(data)
|
22
33
|
end
|
23
34
|
|
35
|
+
def stop?
|
36
|
+
@stop
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
attr_reader :http_client
|
41
|
+
|
24
42
|
# Data is checked on the presence of the end sequence. The first character
|
25
43
|
# in the sequence (ENTER) can be read multiple times in a row and it is
|
26
44
|
# to be forwarded.
|
@@ -29,38 +47,160 @@ module VpsAdmin::CLI::Commands
|
|
29
47
|
# but stored in a private buffer. If the sequence is later broken, the private
|
30
48
|
# buffer is forwarded and reset.
|
31
49
|
#
|
32
|
-
# If the whole end sequence is read,
|
33
|
-
def
|
50
|
+
# If the whole end sequence is read, we exit.
|
51
|
+
def write(data)
|
52
|
+
buffer = ''
|
53
|
+
|
34
54
|
data.each_char do |char|
|
35
55
|
if char == @end_seq[ @end_i ]
|
36
|
-
if @end_i == @end_seq.size-1
|
37
|
-
|
56
|
+
if @end_i == @end_seq.size - 1
|
57
|
+
@stop = true
|
38
58
|
return
|
39
59
|
end
|
40
60
|
|
41
61
|
@end_i += 1
|
42
62
|
|
43
63
|
if @end_i == 1
|
44
|
-
|
45
|
-
|
64
|
+
buffer += char
|
46
65
|
else
|
47
66
|
@private_buffer += char
|
48
67
|
end
|
49
68
|
|
50
69
|
elsif char == @end_seq.first
|
51
|
-
|
52
|
-
|
70
|
+
buffer += char
|
53
71
|
else
|
54
72
|
@end_i = 0
|
55
73
|
|
56
74
|
unless @private_buffer.empty?
|
57
|
-
|
75
|
+
buffer += @private_buffer
|
58
76
|
@private_buffer.clear
|
59
77
|
end
|
60
78
|
|
61
|
-
|
79
|
+
buffer += char
|
62
80
|
end
|
63
81
|
end
|
82
|
+
|
83
|
+
http_client.write(buffer) unless buffer.empty?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class HttpClient
|
88
|
+
def initialize(vps, token, rate)
|
89
|
+
@vps = vps
|
90
|
+
@token = token
|
91
|
+
@rate = rate
|
92
|
+
@mutex = Mutex.new
|
93
|
+
@write_buffer = ''
|
94
|
+
@stop = false
|
95
|
+
@error = false
|
96
|
+
end
|
97
|
+
|
98
|
+
def start
|
99
|
+
@thread = Thread.new { run }
|
100
|
+
end
|
101
|
+
|
102
|
+
def stop
|
103
|
+
@stop = true
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop?
|
107
|
+
@stop
|
108
|
+
end
|
109
|
+
|
110
|
+
def error?
|
111
|
+
@error != false
|
112
|
+
end
|
113
|
+
|
114
|
+
def error
|
115
|
+
@error
|
116
|
+
end
|
117
|
+
|
118
|
+
def join
|
119
|
+
stop
|
120
|
+
thread.join
|
121
|
+
end
|
122
|
+
|
123
|
+
def write(data)
|
124
|
+
mutex.synchronize do
|
125
|
+
write_buffer << data
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def resize(width, height)
|
130
|
+
@width = width
|
131
|
+
@height = height
|
132
|
+
end
|
133
|
+
|
134
|
+
protected
|
135
|
+
attr_reader :vps, :token, :rate, :width, :height, :write_buffer,
|
136
|
+
:mutex, :thread
|
137
|
+
|
138
|
+
def run
|
139
|
+
uri = URI("#{vps.node.location.remote_console_server}/console/feed/#{vps.id}")
|
140
|
+
start_args = [uri.host, uri.port, nil, nil, nil, nil, {
|
141
|
+
use_ssl: uri.scheme == 'https',
|
142
|
+
}]
|
143
|
+
|
144
|
+
Net::HTTP.start(*start_args) do |http|
|
145
|
+
loop do
|
146
|
+
break if stop? || error?
|
147
|
+
|
148
|
+
rate_limit { send_request(http, uri) }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def send_request(http, uri)
|
154
|
+
req = Net::HTTP::Post.new(uri)
|
155
|
+
|
156
|
+
keys =
|
157
|
+
mutex.synchronize do
|
158
|
+
s = write_buffer.dup
|
159
|
+
write_buffer.clear
|
160
|
+
s
|
161
|
+
end
|
162
|
+
|
163
|
+
req.set_form_data(
|
164
|
+
'session' => token,
|
165
|
+
'keys' => keys,
|
166
|
+
'width' => width,
|
167
|
+
'height' => height,
|
168
|
+
)
|
169
|
+
|
170
|
+
res = http.request(req)
|
171
|
+
|
172
|
+
unless res.is_a?(Net::HTTPSuccess)
|
173
|
+
set_error(
|
174
|
+
"Console server returned error: "+
|
175
|
+
"HTTP #{res.code} - #{res.message}\n\n#{res.body}"
|
176
|
+
)
|
177
|
+
stop
|
178
|
+
return
|
179
|
+
end
|
180
|
+
|
181
|
+
ret = JSON.parse(res.body, symbolize_names: true)
|
182
|
+
|
183
|
+
unless ret[:session]
|
184
|
+
$stdout.write(ret[:data])
|
185
|
+
set_error("Session closed.")
|
186
|
+
stop
|
187
|
+
return
|
188
|
+
end
|
189
|
+
|
190
|
+
$stdout.write(Base64.decode64(ret[:data]))
|
191
|
+
end
|
192
|
+
|
193
|
+
def rate_limit
|
194
|
+
t1 = Time.now
|
195
|
+
yield
|
196
|
+
t2 = Time.now
|
197
|
+
|
198
|
+
cooldown = rate - (t2 - t1)
|
199
|
+
sleep(cooldown) if cooldown > 0
|
200
|
+
end
|
201
|
+
|
202
|
+
def set_error(str)
|
203
|
+
@error = str
|
64
204
|
end
|
65
205
|
end
|
66
206
|
|
@@ -93,7 +233,7 @@ module VpsAdmin::CLI::Commands
|
|
93
233
|
end
|
94
234
|
|
95
235
|
puts " VPS is on #{vps.node.domain_name}, located in #{vps.node.location.label}."
|
96
|
-
puts "Console
|
236
|
+
puts "Console server URL is #{vps.node.location.remote_console_server}"
|
97
237
|
write "Obtaining authentication token..."
|
98
238
|
|
99
239
|
begin
|
@@ -105,30 +245,18 @@ module VpsAdmin::CLI::Commands
|
|
105
245
|
exit(false)
|
106
246
|
end
|
107
247
|
|
108
|
-
@token = t.token
|
109
|
-
|
110
248
|
puts
|
111
|
-
puts "Connecting to remote console..."
|
249
|
+
puts "Connecting to the remote console..."
|
112
250
|
puts "Press ENTER ESC . to exit"
|
113
251
|
puts
|
114
252
|
|
115
253
|
raw_mode do
|
116
|
-
|
117
|
-
@input = EventMachine.open_keyboard(InputHandler)
|
118
|
-
|
119
|
-
@http = EventMachine::HttpRequest.new(
|
120
|
-
"#{vps.node.location.remote_console_server}/console/feed/#{vps_id}"
|
121
|
-
)
|
122
|
-
communicate
|
123
|
-
end
|
254
|
+
run_console(vps, t.token)
|
124
255
|
end
|
125
256
|
end
|
126
257
|
|
127
258
|
protected
|
128
|
-
|
129
|
-
$stdout.write(s)
|
130
|
-
$stdout.flush
|
131
|
-
end
|
259
|
+
attr_reader :client
|
132
260
|
|
133
261
|
def raw_mode
|
134
262
|
state = `stty -g`
|
@@ -139,6 +267,7 @@ module VpsAdmin::CLI::Commands
|
|
139
267
|
|
140
268
|
Signal.trap('WINCH') do
|
141
269
|
@size = Terminal.size!
|
270
|
+
client.resize(@size[:width], @size[:height]) if client
|
142
271
|
end
|
143
272
|
|
144
273
|
yield
|
@@ -150,38 +279,35 @@ module VpsAdmin::CLI::Commands
|
|
150
279
|
puts
|
151
280
|
end
|
152
281
|
|
153
|
-
def
|
154
|
-
|
155
|
-
body: {
|
156
|
-
session: @token,
|
157
|
-
keys: @input.buffer,
|
158
|
-
width: @size[:width],
|
159
|
-
height: @size[:height],
|
160
|
-
},
|
161
|
-
keepalive: true
|
162
|
-
)
|
282
|
+
def run_console(vps, token)
|
283
|
+
Thread.abort_on_exception = true
|
163
284
|
|
164
|
-
@
|
285
|
+
@client = HttpClient.new(vps, token, @opts[:rate])
|
286
|
+
client.resize(@size[:width], @size[:height])
|
165
287
|
|
166
|
-
|
167
|
-
|
168
|
-
EventMachine.stop
|
169
|
-
end
|
288
|
+
input = InputHandler.new(client)
|
289
|
+
client.start
|
170
290
|
|
171
|
-
|
172
|
-
|
291
|
+
loop do
|
292
|
+
res = IO.select([$stdin], [], [], 1)
|
293
|
+
input.read_from($stdin) if res
|
173
294
|
|
174
|
-
|
175
|
-
|
176
|
-
puts "\nSession closed."
|
177
|
-
EM.stop
|
178
|
-
next
|
179
|
-
end
|
295
|
+
if input.stop? || client.stop?
|
296
|
+
client.join
|
180
297
|
|
181
|
-
|
298
|
+
if client.error?
|
299
|
+
write("\n")
|
300
|
+
write(client.error)
|
301
|
+
end
|
182
302
|
|
183
|
-
|
303
|
+
return
|
304
|
+
end
|
184
305
|
end
|
185
306
|
end
|
307
|
+
|
308
|
+
def write(s)
|
309
|
+
$stdout.write(s)
|
310
|
+
$stdout.flush
|
311
|
+
end
|
186
312
|
end
|
187
313
|
end
|
data/vpsadmin-client.gemspec
CHANGED
@@ -21,9 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency 'bundler'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
23
|
|
24
|
-
spec.add_runtime_dependency 'haveapi-client', '~> 0.
|
25
|
-
spec.add_runtime_dependency 'eventmachine', '~> 1.0.3'
|
26
|
-
spec.add_runtime_dependency 'em-http-request', '~> 1.1.3'
|
24
|
+
spec.add_runtime_dependency 'haveapi-client', '~> 0.15.1'
|
27
25
|
spec.add_runtime_dependency 'json'
|
28
26
|
spec.add_runtime_dependency 'curses'
|
29
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vpsadmin-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0.master.
|
4
|
+
version: 3.0.0.master.20220121.pre.0.b5a81113
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Skokan
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,42 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.15.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: eventmachine
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.0.3
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 1.0.3
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: em-http-request
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 1.1.3
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 1.1.3
|
54
|
+
version: 0.15.1
|
83
55
|
- !ruby/object:Gem::Dependency
|
84
56
|
name: json
|
85
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,7 +114,7 @@ homepage: ''
|
|
142
114
|
licenses:
|
143
115
|
- GPL
|
144
116
|
metadata: {}
|
145
|
-
post_install_message:
|
117
|
+
post_install_message:
|
146
118
|
rdoc_options: []
|
147
119
|
require_paths:
|
148
120
|
- lib
|
@@ -157,9 +129,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
129
|
- !ruby/object:Gem::Version
|
158
130
|
version: 1.3.1
|
159
131
|
requirements: []
|
160
|
-
|
161
|
-
|
162
|
-
signing_key:
|
132
|
+
rubygems_version: 3.2.26
|
133
|
+
signing_key:
|
163
134
|
specification_version: 4
|
164
135
|
summary: Ruby API and CLI for vpsAdmin API
|
165
136
|
test_files: []
|