mkit 0.6.2 → 0.7.0
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/Gemfile +1 -20
- data/README.md +15 -15
- data/bin/mkit +46 -334
- data/lib/mkit/app/controllers/pods_controller.rb +1 -7
- data/lib/mkit/app/controllers/services_controller.rb +28 -1
- data/lib/mkit/app/helpers/services_helper.rb +7 -0
- data/lib/mkit/app/mkit_server.rb +2 -0
- data/lib/mkit/app/model/service.rb +0 -1
- data/lib/mkit/client/command_parser.rb +214 -0
- data/lib/mkit/client/commands.yaml +203 -0
- data/lib/mkit/client/http_client.rb +90 -0
- data/lib/mkit/client/mkitd_client.rb +21 -0
- data/lib/mkit/client/websocket_client.rb +68 -0
- data/lib/mkit/cmd/shell_client.rb +57 -0
- data/lib/mkit/docker_listener.rb +46 -25
- data/lib/mkit/docker_log_listener.rb +29 -0
- data/lib/mkit/version.rb +1 -1
- data/lib/mkit.rb +1 -0
- data/mkit.gemspec +2 -1
- data/samples/apps/minio.yml +2 -2
- data/samples/soketi.yaml +32 -0
- metadata +34 -7
- data/Gemfile.lock +0 -140
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
class InvalidParametersException < Exception
|
8
|
+
attr_reader :command
|
9
|
+
|
10
|
+
def initialize(cause, command = nil)
|
11
|
+
super(cause)
|
12
|
+
@command = command
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class CommandParser
|
17
|
+
def initialize
|
18
|
+
@dict = YAML.safe_load(File.read("#{File.expand_path('..', __dir__)}/client/commands.yaml"), symbolize_names: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def dict
|
22
|
+
@dict
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse(args)
|
26
|
+
cmd = args[0]
|
27
|
+
c = nil
|
28
|
+
# short circuit for help
|
29
|
+
if cmd == 'help' || args.empty?
|
30
|
+
if args.size > 1
|
31
|
+
c = find_command(args[1])
|
32
|
+
raise InvalidParametersException, "'#{args[1]}' is not a valid help topic." if c.nil?
|
33
|
+
end
|
34
|
+
return help(cmd: c)
|
35
|
+
else
|
36
|
+
c = find_command(cmd)
|
37
|
+
end
|
38
|
+
raise InvalidParametersException, 'Command not found' if c.nil?
|
39
|
+
|
40
|
+
command = c
|
41
|
+
argv = args.dup
|
42
|
+
argv.delete(cmd)
|
43
|
+
|
44
|
+
request_data = {}
|
45
|
+
request = command[:request]
|
46
|
+
unless argv.empty?
|
47
|
+
# options
|
48
|
+
unless c[:options].nil?
|
49
|
+
command = c[:options].select { |o| o[:cmd] == argv[0] }.first
|
50
|
+
raise InvalidParametersException.new('Invalid parameters found.', c) if command.nil? || command.empty?
|
51
|
+
|
52
|
+
argv.delete_at(0)
|
53
|
+
request = command[:request]
|
54
|
+
end
|
55
|
+
fill_cmd_args(command[:args], argv, request, request_data)
|
56
|
+
end
|
57
|
+
raise InvalidParametersException.new('Invalid command or parameters.', c) if request.nil?
|
58
|
+
|
59
|
+
validate_command(command, request_data)
|
60
|
+
#
|
61
|
+
{
|
62
|
+
cmd: c[:cmd],
|
63
|
+
request: request,
|
64
|
+
data: request_data
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
# args = command[:args]
|
69
|
+
# argv = ARGV.dup - cmd
|
70
|
+
# request = command[:request]
|
71
|
+
# request_data = {}
|
72
|
+
def fill_cmd_args(args, argv, request, request_data)
|
73
|
+
return if args.nil?
|
74
|
+
# add to schema
|
75
|
+
args.each do |arg|
|
76
|
+
arg[:type] = 'value' unless arg[:type]
|
77
|
+
end
|
78
|
+
# flag and options
|
79
|
+
fill_flag_and_options_args(args, argv, request, request_data)
|
80
|
+
idx = 0
|
81
|
+
args.each do |arg|
|
82
|
+
if arg[:type].to_sym == :value
|
83
|
+
request_data[arg[:name].to_sym] = argv[idx]
|
84
|
+
fill_params_and_uri(arg, request)
|
85
|
+
end
|
86
|
+
|
87
|
+
idx += 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def fill_flag_and_options_args(args, argv, request, request_data)
|
92
|
+
# flags
|
93
|
+
# checking flags first, avoids -n -f, with -f being the value of -n
|
94
|
+
args.select { |arg| arg[:type].to_sym == :flag }.each do |arg|
|
95
|
+
idx = find_option_or_flag_index(arg, argv)
|
96
|
+
if idx
|
97
|
+
fill_params_and_uri(arg, request)
|
98
|
+
argv.delete_at(idx)
|
99
|
+
request_data[arg[:name].to_sym] = arg[:param]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
# options
|
103
|
+
args.select { |arg| arg[:type].to_sym == :option }.each do |arg|
|
104
|
+
idx = find_option_or_flag_index(arg, argv)
|
105
|
+
if idx
|
106
|
+
fill_params_and_uri(arg, request)
|
107
|
+
argv.delete_at(idx)
|
108
|
+
request_data[arg[:name].to_sym] = argv[idx]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def find_option_or_flag_index(arg, argv)
|
114
|
+
idx = nil
|
115
|
+
arg[:switch].each { | switch |
|
116
|
+
idx ||= argv.index(switch)
|
117
|
+
}
|
118
|
+
idx
|
119
|
+
end
|
120
|
+
|
121
|
+
def fill_params_and_uri(arg, request)
|
122
|
+
request[:uri] = request[:uri] + arg[:uri] unless arg[:uri].nil?
|
123
|
+
unless arg[:param].nil?
|
124
|
+
request[:params] ||= []
|
125
|
+
request[:params] << [ "#{arg[:name]}", "#{arg[:param]}"]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def validate_command(command, request_data)
|
130
|
+
return if command[:args].nil?
|
131
|
+
|
132
|
+
command[:args].select { |arg| arg[:mandatory] == true }.each do |arg|
|
133
|
+
if request_data[arg[:name].to_sym].nil?
|
134
|
+
raise InvalidParametersException.new("Missing mandatory parameter: #{arg[:name]}", command)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
request_data.select{|key, value| value.nil? }.each do |key, value|
|
138
|
+
raise InvalidParametersException.new("Missing parameter value for #{key}", command)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def find_command(cmd)
|
143
|
+
dict.select { |k| k[:cmd] == cmd }.first
|
144
|
+
end
|
145
|
+
|
146
|
+
def doIt(args)
|
147
|
+
result = parse_args(args)
|
148
|
+
puts result
|
149
|
+
rescue InvalidParametersException => e
|
150
|
+
help(cause: e)
|
151
|
+
end
|
152
|
+
|
153
|
+
def format_arg_help_msg(arg)
|
154
|
+
_format(arg[:help][0], arg[:help][1])
|
155
|
+
end
|
156
|
+
|
157
|
+
def format_cmd_help_msg(command)
|
158
|
+
_format(command[:cmd], command[:help])
|
159
|
+
end
|
160
|
+
|
161
|
+
def _format(arg1, srg2)
|
162
|
+
format("%-12s %s\n", arg1, srg2)
|
163
|
+
end
|
164
|
+
|
165
|
+
def help(cause: nil, cmd: nil)
|
166
|
+
msg = ''
|
167
|
+
if cause.nil?
|
168
|
+
my_cmd = cmd
|
169
|
+
else
|
170
|
+
msg += "MKIt: #{cause.message}\n"
|
171
|
+
my_cmd = cause.command
|
172
|
+
end
|
173
|
+
if my_cmd.nil?
|
174
|
+
msg += "\nUsage: mkit <command> [options]\n\n"
|
175
|
+
msg += "Micro k8s on Ruby - a simple tool to mimic a (very) minimalistic k8 cluster\n\n"
|
176
|
+
msg += "Commands:\n\n"
|
177
|
+
dict.each do |c|
|
178
|
+
msg += format_cmd_help_msg(c)
|
179
|
+
end
|
180
|
+
msg += "\n"
|
181
|
+
msg += "Run ' mkit help <command>' for specific command information.\n\n"
|
182
|
+
else
|
183
|
+
# todo mkit help profile set
|
184
|
+
msg += format("\nUsage: mkit %s %s\n\n", my_cmd[:cmd], my_cmd[:usage].nil? ? '' : my_cmd[:usage].join(' '))
|
185
|
+
msg += format("%s\n", my_cmd[:help])
|
186
|
+
if !my_cmd[:options].nil? || !my_cmd[:args].nil?
|
187
|
+
msg += "\nOptions:\n"
|
188
|
+
# command
|
189
|
+
unless my_cmd[:options].nil?
|
190
|
+
my_cmd[:options].each do |c|
|
191
|
+
msg += format_cmd_help_msg(c)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
# args
|
195
|
+
unless my_cmd[:args].nil?
|
196
|
+
# values only first
|
197
|
+
cmd_args = my_cmd[:args].select{ |arg| (arg[:type].nil? || arg[:type].to_sym == :value) && !arg[:help].nil?}
|
198
|
+
cmd_args.each do |arg|
|
199
|
+
msg += format_arg_help_msg(arg)
|
200
|
+
end
|
201
|
+
cmd_args = my_cmd[:args].select{ |arg| !arg[:type].nil? && (arg[:type].to_sym == :option || arg[:type].to_sym == :flag)}
|
202
|
+
cmd_args.each do |arg|
|
203
|
+
msg += format_arg_help_msg(arg)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
msg += "\n"
|
208
|
+
end
|
209
|
+
puts msg
|
210
|
+
exit 1
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
@@ -0,0 +1,203 @@
|
|
1
|
+
---
|
2
|
+
- cmd: init
|
3
|
+
help: init mkit client
|
4
|
+
request: {}
|
5
|
+
- cmd: ps
|
6
|
+
usage:
|
7
|
+
- "[service_id_or_name]"
|
8
|
+
help: show services status (alias for status)
|
9
|
+
args:
|
10
|
+
- name: id
|
11
|
+
help:
|
12
|
+
- id
|
13
|
+
- Service id or name
|
14
|
+
mandatory: false
|
15
|
+
uri: "/<%=id%>"
|
16
|
+
request:
|
17
|
+
verb: get
|
18
|
+
uri: "/services"
|
19
|
+
- cmd: status
|
20
|
+
usage:
|
21
|
+
- "[service_id_or_name]"
|
22
|
+
help: show services status
|
23
|
+
args:
|
24
|
+
- name: id
|
25
|
+
help:
|
26
|
+
- id
|
27
|
+
- Service id or name
|
28
|
+
mandatory: false
|
29
|
+
uri: "/<%=id%>"
|
30
|
+
request:
|
31
|
+
verb: get
|
32
|
+
uri: "/services"
|
33
|
+
- cmd: start
|
34
|
+
usage:
|
35
|
+
- "<service_id_or_name>"
|
36
|
+
help: start service
|
37
|
+
args:
|
38
|
+
- name: id
|
39
|
+
help:
|
40
|
+
- id
|
41
|
+
- Service id or name
|
42
|
+
mandatory: true
|
43
|
+
request:
|
44
|
+
verb: put
|
45
|
+
uri: "/services/<%=id%>/start"
|
46
|
+
- cmd: stop
|
47
|
+
usage:
|
48
|
+
- "<service_id_or_name>"
|
49
|
+
help: stop service
|
50
|
+
args:
|
51
|
+
- name: id
|
52
|
+
help:
|
53
|
+
- id
|
54
|
+
- Service id or name
|
55
|
+
mandatory: true
|
56
|
+
request:
|
57
|
+
verb: put
|
58
|
+
uri: "/services/<%=id%>/stop"
|
59
|
+
- cmd: restart
|
60
|
+
usage:
|
61
|
+
- "<service_id_or_name>"
|
62
|
+
help: restart service
|
63
|
+
args:
|
64
|
+
- name: id
|
65
|
+
help:
|
66
|
+
- id
|
67
|
+
- Service id or name
|
68
|
+
mandatory: true
|
69
|
+
request:
|
70
|
+
verb: put
|
71
|
+
uri: "/services/<%=id%>/restart"
|
72
|
+
- cmd: create
|
73
|
+
usage:
|
74
|
+
- "<service.yaml>"
|
75
|
+
help: create new service
|
76
|
+
args:
|
77
|
+
- name: file
|
78
|
+
help:
|
79
|
+
- file
|
80
|
+
- Service definition
|
81
|
+
mandatory: true
|
82
|
+
request:
|
83
|
+
verb: post
|
84
|
+
uri: "/services"
|
85
|
+
- cmd: update
|
86
|
+
usage:
|
87
|
+
- "<service.yaml>"
|
88
|
+
help: update service
|
89
|
+
args:
|
90
|
+
- name: file
|
91
|
+
help:
|
92
|
+
- file
|
93
|
+
- Service definition
|
94
|
+
mandatory: true
|
95
|
+
request:
|
96
|
+
verb: put
|
97
|
+
uri: "/services/<%=id%>"
|
98
|
+
- cmd: rm
|
99
|
+
usage:
|
100
|
+
- "<service_id_or_name>"
|
101
|
+
help: remove service
|
102
|
+
args:
|
103
|
+
- name: id
|
104
|
+
help:
|
105
|
+
- id
|
106
|
+
- Service id or name
|
107
|
+
mandatory: true
|
108
|
+
request:
|
109
|
+
verb: delete
|
110
|
+
uri: "/services/<%=id%>"
|
111
|
+
- cmd: logs
|
112
|
+
usage:
|
113
|
+
- "<service_id_or_name> [-f] [-n <lines>]"
|
114
|
+
help: view service logs
|
115
|
+
request:
|
116
|
+
verb: ws # new type
|
117
|
+
uri: "/services/<%=id%>/logs"
|
118
|
+
args:
|
119
|
+
- name: id
|
120
|
+
mandatory: true
|
121
|
+
# uri: "/<%=id%>" # if exists, add it to main
|
122
|
+
type: value # option | flag | value # option takes a value, flag does not takes a value, value is like id_or_name
|
123
|
+
help:
|
124
|
+
- id
|
125
|
+
- Service id or name
|
126
|
+
- name: follow
|
127
|
+
help:
|
128
|
+
- -f
|
129
|
+
- Follow log output
|
130
|
+
mandatory: false
|
131
|
+
param: "<%=true%>" # templated. param ou uri - param -> add query parameter name=param_value
|
132
|
+
type: flag
|
133
|
+
switch:
|
134
|
+
- "-f"
|
135
|
+
- name: nr_lines
|
136
|
+
help:
|
137
|
+
- -n <lines>
|
138
|
+
- Number of lines to show from the end of the logs
|
139
|
+
mandatory: false
|
140
|
+
param: "<%=nr_lines%>"
|
141
|
+
type: option
|
142
|
+
switch:
|
143
|
+
- "-n"
|
144
|
+
- name: pods
|
145
|
+
help:
|
146
|
+
- -p <[pods]>
|
147
|
+
- Show logs for specified logs, e.g. pod1, pod2 (default first)
|
148
|
+
mandatory: false
|
149
|
+
param: "<%=pods%>"
|
150
|
+
type: option
|
151
|
+
switch:
|
152
|
+
- "-n"
|
153
|
+
- cmd: version
|
154
|
+
help: prints mkit server version
|
155
|
+
request:
|
156
|
+
verb: get
|
157
|
+
uri: "/mkit/version"
|
158
|
+
- cmd: proxy
|
159
|
+
usage:
|
160
|
+
- "<start|stop|restart|status>"
|
161
|
+
help: haproxy status and control
|
162
|
+
options:
|
163
|
+
- cmd: start
|
164
|
+
help: start proxy service
|
165
|
+
request:
|
166
|
+
verb: put
|
167
|
+
uri: "/mkit/proxy/start"
|
168
|
+
- cmd: stop
|
169
|
+
help: stop proxy service
|
170
|
+
request:
|
171
|
+
verb: put
|
172
|
+
uri: "/mkit/proxy/stop"
|
173
|
+
- cmd: restart
|
174
|
+
help: restarts proxy service
|
175
|
+
request:
|
176
|
+
verb: put
|
177
|
+
uri: "/mkit/proxy/restart"
|
178
|
+
- cmd: status
|
179
|
+
help: proxy service status
|
180
|
+
request:
|
181
|
+
verb: get
|
182
|
+
uri: "/mkit/proxy/status"
|
183
|
+
- cmd: profile
|
184
|
+
usage:
|
185
|
+
- "<[set <profile_name>]|[show]>"
|
186
|
+
help: mkit client configuration profile
|
187
|
+
options:
|
188
|
+
- cmd: set
|
189
|
+
help: set mkit client configuration profile
|
190
|
+
usage:
|
191
|
+
- "<profile>"
|
192
|
+
request:
|
193
|
+
verb: set
|
194
|
+
args:
|
195
|
+
- name: profile
|
196
|
+
help:
|
197
|
+
- profile
|
198
|
+
- profile name
|
199
|
+
mandatory: true
|
200
|
+
- cmd: show
|
201
|
+
help: show mkit client current profile
|
202
|
+
request:
|
203
|
+
verb: show
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'net/http'
|
5
|
+
require 'json'
|
6
|
+
require 'net_http_unix'
|
7
|
+
require 'securerandom'
|
8
|
+
require 'erb'
|
9
|
+
require 'uri'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
module MKIt
|
13
|
+
class HttpClient
|
14
|
+
def initialize(server_url, my_id)
|
15
|
+
@server_url = server_url
|
16
|
+
@my_id = my_id
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# http client
|
21
|
+
#
|
22
|
+
|
23
|
+
def client(req)
|
24
|
+
req['X-API-KEY'] = @my_id
|
25
|
+
uri = URI(@server_url)
|
26
|
+
case uri.scheme
|
27
|
+
when 'https'
|
28
|
+
@client = NetX::HTTPUnix.new(uri.host, uri.port)
|
29
|
+
@client.use_ssl = true
|
30
|
+
@client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
31
|
+
when 'http'
|
32
|
+
@client = NetX::HTTPUnix.new(uri.host, uri.port)
|
33
|
+
when 'sock'
|
34
|
+
@client = NetX::HTTPUnix.new("unix://#{uri.path}")
|
35
|
+
else
|
36
|
+
raise InvalidParametersException, 'Invalid mkit server uri. Please check configuration'
|
37
|
+
end
|
38
|
+
@client.request(req)
|
39
|
+
end
|
40
|
+
|
41
|
+
def request(request, request_data = nil)
|
42
|
+
req = nil
|
43
|
+
uri = request[:uri]
|
44
|
+
request[:file] = request_data[:file]
|
45
|
+
|
46
|
+
unless request[:params].nil? || request[:params].empty?
|
47
|
+
uri = uri + '?' + request[:params].map { |k, v| "#{k}=#{v}" }.join('&')
|
48
|
+
end
|
49
|
+
uri = ERB.new(uri).result_with_hash(request_data)
|
50
|
+
case request[:verb].to_sym
|
51
|
+
when :post
|
52
|
+
req = Net::HTTP::Post.new(uri)
|
53
|
+
unless request[:file].nil?
|
54
|
+
(body, boundary) = attach(request[:file])
|
55
|
+
req.body = body
|
56
|
+
req['Content-Type'] = "multipart/form-data, boundary=#{boundary}"
|
57
|
+
end
|
58
|
+
when :put
|
59
|
+
req = Net::HTTP::Put.new(uri)
|
60
|
+
unless request[:file].nil?
|
61
|
+
(body, boundary) = attach(request[:file])
|
62
|
+
req.body = body
|
63
|
+
req['Content-Type'] = "multipart/form-data, boundary=#{boundary}"
|
64
|
+
end
|
65
|
+
when :patch
|
66
|
+
req = Net::HTTP::Patch.new(uri)
|
67
|
+
when :get
|
68
|
+
req = Net::HTTP::Get.new(uri)
|
69
|
+
when :delete
|
70
|
+
req = Net::HTTP::Delete.new(uri)
|
71
|
+
when :ws
|
72
|
+
|
73
|
+
end
|
74
|
+
client(req).body
|
75
|
+
end
|
76
|
+
|
77
|
+
def attach(file)
|
78
|
+
boundary = SecureRandom.alphanumeric
|
79
|
+
body = []
|
80
|
+
body << "--#{boundary}\r\n"
|
81
|
+
body << "Content-Disposition: form-data; name=file; filename='#{File.basename(file)}'\r\n"
|
82
|
+
body << "Content-Type: text/plain\r\n"
|
83
|
+
body << "\r\n"
|
84
|
+
body << File.read(file)
|
85
|
+
body << "\r\n--#{boundary}--\r\n"
|
86
|
+
[body.join, boundary]
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'mkit/client/http_client'
|
3
|
+
require 'mkit/client/websocket_client'
|
4
|
+
|
5
|
+
module MKIt
|
6
|
+
class MKItdClient
|
7
|
+
def initialize(request, server_url, my_id)
|
8
|
+
case request[:verb].to_sym
|
9
|
+
when :ws
|
10
|
+
@client = MKIt::WebSocketClient.new(server_url, my_id)
|
11
|
+
else
|
12
|
+
@client = MKIt::HttpClient.new(server_url, my_id)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def request(request, request_data)
|
17
|
+
@client.request(request, request_data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# # frozen_string_literal: true
|
2
|
+
require 'faye/websocket'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module MKIt
|
7
|
+
class WebSocketClient
|
8
|
+
def initialize(server_url, my_id)
|
9
|
+
@server_url = server_url
|
10
|
+
@my_id = my_id
|
11
|
+
uri = URI(@server_url)
|
12
|
+
use_ssl = uri.scheme == 'https'
|
13
|
+
@options = use_ssl ? { tls: { :verify_peer => false } } : {}
|
14
|
+
@options[:headers] = { 'X-API-KEY' => @my_id }
|
15
|
+
url_prefix = use_ssl ? "wss" : "ws"
|
16
|
+
@ws_url = "#{url_prefix}://#{uri.host}:#{uri.port}"
|
17
|
+
trap("SIGINT") do
|
18
|
+
puts "Bye..."
|
19
|
+
EventMachine.stop
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def request(request, request_data)
|
24
|
+
uri = request[:uri]
|
25
|
+
unless request[:params].nil? || request[:params].empty?
|
26
|
+
uri = uri + '?' + request[:params].map { |k, v| "#{k}=#{v}" }.join('&')
|
27
|
+
end
|
28
|
+
uri = ERB.new("#{@ws_url}#{uri}").result_with_hash(request_data)
|
29
|
+
|
30
|
+
EM.run {
|
31
|
+
ws = Faye::WebSocket::Client.new(uri, nil, @options)
|
32
|
+
|
33
|
+
ws.on :open do |event|
|
34
|
+
# no op
|
35
|
+
end
|
36
|
+
|
37
|
+
ws.on :message do |event|
|
38
|
+
puts event.data
|
39
|
+
end
|
40
|
+
|
41
|
+
ws.on :error do |event|
|
42
|
+
p [:error, event.message]
|
43
|
+
ws = nil
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
ws.on :close do |event|
|
48
|
+
ws = nil
|
49
|
+
EventMachine.stop
|
50
|
+
end
|
51
|
+
|
52
|
+
Thread.new do
|
53
|
+
loop do
|
54
|
+
input = STDIN.gets.chomp
|
55
|
+
if input == 'exit'
|
56
|
+
puts "bye..."
|
57
|
+
EventMachine.stop
|
58
|
+
break
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module MKIt
|
3
|
+
class ExitShell < RuntimeError; end
|
4
|
+
|
5
|
+
class ShellClient
|
6
|
+
def initialize(command:)
|
7
|
+
@command = command
|
8
|
+
@logger = MKItLogger
|
9
|
+
@logger.debug("Command initialized: [#{@command}]")
|
10
|
+
end
|
11
|
+
|
12
|
+
def unregister
|
13
|
+
@logger.info("ending [#{@command}]...")
|
14
|
+
if @client
|
15
|
+
begin
|
16
|
+
@client.raise ExitShell.new
|
17
|
+
rescue
|
18
|
+
@logger.error("Failed to raise ExitShell")
|
19
|
+
end
|
20
|
+
@client.exit rescue @logger.warn("Failed to exit client thread")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
# no op
|
26
|
+
end
|
27
|
+
|
28
|
+
def register
|
29
|
+
@client = Thread.new {
|
30
|
+
begin
|
31
|
+
PTY.spawn( @command ) do |stdout, stdin, pid |
|
32
|
+
begin
|
33
|
+
yield stdout, stdin, pid if block_given?
|
34
|
+
rescue Errno::EIO
|
35
|
+
@logger.warn(
|
36
|
+
"Errno:EIO error, but this probably just means that the process has finished giving output"
|
37
|
+
)
|
38
|
+
rescue ExitShell
|
39
|
+
@logger.info("#{@command} ended")
|
40
|
+
ensure
|
41
|
+
stdin.close rescue @logger.warn("Failed to close stdin")
|
42
|
+
stdout.close rescue @logger.warn("Failed to close stdout")
|
43
|
+
begin
|
44
|
+
close
|
45
|
+
rescue => e
|
46
|
+
@logger.warn("Error closing client", e)
|
47
|
+
end
|
48
|
+
Process.wait(pid)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue PTY::ChildExited
|
52
|
+
@logger.info("#{@command} exited.")
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|