adminix 0.1.49 → 0.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/adminix.gemspec +1 -4
  4. data/app/assets/images/logo.png +0 -0
  5. data/app/assets/javascripts/application.js +50 -0
  6. data/app/assets/javascripts/bootstrap.min.js +7 -0
  7. data/app/assets/javascripts/dataTables.bootstrap4.js +184 -0
  8. data/app/assets/javascripts/jquery.dataTables.js +15243 -0
  9. data/app/assets/javascripts/jquery.min.js +2 -0
  10. data/app/assets/javascripts/sb-admin-2.min.js +6 -0
  11. data/app/assets/stylesheets/bootstrap.min.css +6 -0
  12. data/app/assets/stylesheets/dataTables.bootstrap.css +314 -0
  13. data/app/assets/stylesheets/dataTables.responsive.css +106 -0
  14. data/app/assets/stylesheets/font-awesome.min.css +4 -0
  15. data/app/assets/stylesheets/sb-admin-2.min.css +5 -0
  16. data/app/views/scripts/restart_watcher.sh.erb +9 -0
  17. data/app/views/scripts/run_script.sh.erb +12 -0
  18. data/app/views/scripts/start_process.sh.erb +7 -0
  19. data/app/views/scripts/stop_process.sh.erb +7 -0
  20. data/app/views/scripts/update_process.sh.erb +24 -0
  21. data/app/views/scripts/update_watcher.sh.erb +3 -0
  22. data/app/views/web/dashboard.html.erb +90 -0
  23. data/app/views/web/job.html.erb +46 -0
  24. data/app/views/web/link.html.erb +12 -0
  25. data/app/views/web/loadstamp.html.erb +57 -0
  26. data/app/views/web/log.html.erb +49 -0
  27. data/app/views/web/partials/footer.html.erb +11 -0
  28. data/app/views/web/partials/header.html.erb +50 -0
  29. data/bin/install_adminix +40 -0
  30. data/bin/push +13 -0
  31. data/development.log +0 -0
  32. data/exe/adminix +91 -28
  33. data/lib/adminix.rb +42 -5
  34. data/lib/adminix/config.rb +170 -96
  35. data/lib/adminix/entities.rb +5 -0
  36. data/lib/adminix/entities/job.rb +54 -0
  37. data/lib/adminix/entities/log.rb +21 -0
  38. data/lib/adminix/entities/service.rb +211 -0
  39. data/lib/adminix/entities/sysload_stamp.rb +37 -0
  40. data/lib/adminix/entities/variable.rb +32 -0
  41. data/lib/adminix/helpers.rb +7 -2
  42. data/lib/adminix/helpers/command.rb +73 -0
  43. data/lib/adminix/helpers/files.rb +82 -0
  44. data/lib/adminix/helpers/log_reader.rb +16 -0
  45. data/lib/adminix/helpers/net_http.rb +63 -0
  46. data/lib/adminix/helpers/output.rb +28 -0
  47. data/lib/adminix/helpers/systemctl.rb +54 -0
  48. data/lib/adminix/services.rb +3 -0
  49. data/lib/adminix/services/app_service.rb +143 -0
  50. data/lib/adminix/services/logs_service.rb +13 -0
  51. data/lib/adminix/services/system_load_service.rb +16 -0
  52. data/lib/adminix/version.rb +1 -1
  53. data/lib/adminix/watcher.rb +76 -144
  54. data/lib/adminix/web.rb +4 -0
  55. data/lib/adminix/web/router.rb +98 -0
  56. data/lib/adminix/web/server.rb +60 -0
  57. data/lib/adminix/web/view_helper.rb +14 -0
  58. data/lib/event_machine.rb +2 -0
  59. data/lib/event_machine/http_server.rb +2 -0
  60. data/lib/event_machine/http_server/response.rb +314 -0
  61. data/lib/event_machine/http_server/server.rb +107 -0
  62. data/lib/event_machine/tail.rb +2 -0
  63. data/lib/event_machine/tail/filetail.rb +470 -0
  64. data/lib/event_machine/tail/globwatcher.rb +294 -0
  65. metadata +60 -45
  66. data/lib/adminix/errors.rb +0 -7
  67. data/lib/adminix/helpers/file.rb +0 -13
  68. data/lib/adminix/helpers/http.rb +0 -19
  69. data/lib/adminix/log_watch_handler.rb +0 -23
  70. data/lib/adminix/server_setup.rb +0 -76
  71. data/lib/adminix/service.rb +0 -179
  72. data/lib/adminix/setup.rb +0 -3
  73. data/lib/adminix/setup/routes.rb +0 -113
  74. data/lib/adminix/setup/services.rb +0 -139
  75. data/lib/adminix/setup/views.rb +0 -183
  76. data/lib/adminix/system.rb +0 -106
  77. data/views/daemon_scripts/upstart.conf.erb +0 -23
@@ -0,0 +1,4 @@
1
+ require_relative 'web/server'
2
+ require_relative 'web/view_helper'
3
+ require_relative 'web/router'
4
+
@@ -0,0 +1,98 @@
1
+ module Adminix
2
+ module Web
3
+ class Router < Server
4
+ include ViewHelper
5
+ def process_request
6
+ if @http_request_uri == '/ping'
7
+ render text: 'pong'
8
+ elsif @http_request_uri == '/'
9
+ dashboard_route
10
+ elsif @http_request_uri == '/link'
11
+ link_route
12
+ elsif @http_request_uri =="/log"
13
+ log_route
14
+ elsif @http_request_uri =="/job"
15
+ job_route
16
+ elsif @http_request_uri =="/loadstamp"
17
+ loadstamp_route
18
+ elsif @http_request_uri =="/start"
19
+ start_route
20
+ elsif @http_request_uri == "/stop"
21
+ stop_route
22
+
23
+ else
24
+ asset = Helpers::Files.read_asset(@http_request_uri)
25
+ if asset
26
+ render text: asset
27
+ else
28
+ not_found_route
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ # initialize
35
+ def params
36
+ params = {}
37
+ ls = @http_query_string.to_s.split('&')
38
+ return params if ls == ''
39
+
40
+ ls.each do |p|
41
+ parts = p.split('=')
42
+ params[parts[0]] = parts[1]
43
+ end
44
+ return params
45
+ end
46
+
47
+ # Routes
48
+
49
+ def dashboard_route
50
+ content = view('dashboard.html')
51
+ render html: content, content_type: 'text/html'
52
+ end
53
+
54
+ def link_route
55
+ @page = !params['page'].nil? ? params['page'].to_i : 1
56
+ @per_page = 2
57
+ content = view('link.html')
58
+ render html: content, content_type: 'text/html'
59
+ end
60
+
61
+ def log_route
62
+ @page = !params['page'].nil? ? params['page'].to_i : 1
63
+ @per_page = 2
64
+ content = view('log.html')
65
+ render html: content, content_type: 'text/html'
66
+ end
67
+
68
+ def job_route
69
+ @page = !params['page'].nil? ? params['page'].to_i : 1
70
+ @per_page = 2
71
+ content = view('job.html')
72
+ render html: content, content_type: 'text/html'
73
+ end
74
+
75
+
76
+ def loadstamp_route
77
+ # Adminix.logger.debug params
78
+ @page = !params['page'].nil? ? params['page'].to_i : 1
79
+ @per_page = 2
80
+ content = view('loadstamp.html')
81
+ render html: content, content_type: 'text/html'
82
+ end
83
+
84
+ def start_route
85
+ Adminix.watcher.app_service.start_process
86
+ content = {"status": "process started"}.to_json
87
+ render json: content
88
+ end
89
+
90
+ def stop_route
91
+ Adminix.watcher.app_service.stop_process
92
+ content = {"status": "process stopped"}.to_json
93
+ render json: content
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,60 @@
1
+ require 'erb'
2
+
3
+ module Adminix
4
+ module Web
5
+ class Server < EM::HttpServer::Server
6
+ def process_http_request
7
+ # puts @http_request_method
8
+ # puts @http_request_uri
9
+ # puts @http_query_string
10
+ # puts @http_protocol
11
+ # puts @http_content
12
+ # puts @http[:cookie]
13
+ # puts @http[:content_type]
14
+ # you have all the http headers in this hash
15
+ # puts @http.inspect
16
+ process_request
17
+ end
18
+
19
+ def http_request_errback(e)
20
+ # printing the whole exception
21
+ puts e.inspect
22
+ end
23
+
24
+ # Routes
25
+
26
+ def not_found_route
27
+ content = 'Page not found'
28
+ render text: content, status: 404
29
+ end
30
+
31
+ # Helpers
32
+
33
+ private
34
+
35
+ def render(opts)
36
+ res = if opts[:html]
37
+ construct_response(opts[:html], content_type: 'text/html')
38
+ elsif opts[:text]
39
+ construct_response(opts[:text])
40
+ elsif opts[:json]
41
+ construct_response(opts[:json], content_type: 'application/json')
42
+ end
43
+
44
+ res.send_response
45
+ end
46
+
47
+ def construct_response(content, opts = {})
48
+ res = EM::DelegatedHttpResponse.new(self)
49
+ res.status = opts[:status] || 200
50
+ res.content_type opts[:content_type] || 'text/plain'
51
+ res.content = content
52
+ res
53
+ end
54
+
55
+ def view(path)
56
+ Helpers::Files.read_erb_tpl(path, binding)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,14 @@
1
+ module Adminix
2
+ module Web
3
+ module ViewHelper
4
+
5
+ def retrieve_data(data, page, per_page)
6
+ from = (page - 1) * per_page
7
+ to = from + per_page - 1
8
+ data[from..to]
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,2 @@
1
+ require_relative 'event_machine/http_server'
2
+ require_relative 'event_machine/tail'
@@ -0,0 +1,2 @@
1
+ require_relative 'http_server/response'
2
+ require_relative 'http_server/server'
@@ -0,0 +1,314 @@
1
+ # EventMachine HTTP Server
2
+ # HTTP Response-support class
3
+ #
4
+ # Author:: blackhedd (gmail address: garbagecat10).
5
+ #
6
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
7
+ #
8
+ # This program is made available under the terms of the GPL version 2.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
13
+ #
14
+ # Gmail: garbagecat10
15
+ #
16
+ # This program is free software; you can redistribute it and/or modify
17
+ # it under the terms of the GNU General Public License as published by
18
+ # the Free Software Foundation; either version 2 of the License, or
19
+ # (at your option) any later version.
20
+ #
21
+ # This program is distributed in the hope that it will be useful,
22
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
+ # GNU General Public License for more details.
25
+ #
26
+ # You should have received a copy of the GNU General Public License
27
+ # along with this program; if not, write to the Free Software
28
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29
+ #
30
+ #---------------------------------------------------------------------------
31
+ #
32
+
33
+ module EventMachine
34
+
35
+ # This class provides a wide variety of features for generating and
36
+ # dispatching HTTP responses. It allows you to conveniently generate
37
+ # headers and content (including chunks and multiparts), and dispatch
38
+ # responses (including deferred or partially-complete responses).
39
+ #
40
+ # Although HttpResponse is coded as a class, it's not complete as it
41
+ # stands. It assumes that it has certain of the behaviors of
42
+ # EventMachine::Connection. You must add these behaviors, either by
43
+ # subclassing HttpResponse, or using the alternate version of this
44
+ # class, DelegatedHttpResponse. See the test cases for current information
45
+ # on which behaviors you have to add.
46
+ #
47
+ # TODO, someday it would be nice to provide a version of this functionality
48
+ # that is coded as a Module, so it can simply be mixed into an instance of
49
+ # EventMachine::Connection.
50
+ #
51
+ class HttpResponse
52
+ attr_accessor :status, :status_string, :content, :headers, :chunks, :multiparts
53
+
54
+ def initialize
55
+ @headers = {}
56
+ @keep_connection_open = false
57
+ end
58
+
59
+ def keep_connection_open arg=true
60
+ @keep_connection_open = arg
61
+ end
62
+
63
+ # sugarings for headers
64
+ def content_type *mime
65
+ if mime.length > 0
66
+ @headers["Content-type"] = mime.first.to_s
67
+ else
68
+ @headers["Content-type"]
69
+ end
70
+ end
71
+
72
+ # Sugaring for Set-cookie headers. These are a pain because there can easily and
73
+ # legitimately be more than one. So we use an ugly verb to signify that.
74
+ # #add_set_cookies does NOT disturb the set-cookie headers which may have been
75
+ # added on a prior call. #set_cookie clears them out first.
76
+ def add_set_cookie *ck
77
+ if ck.length > 0
78
+ h = (@headers["Set-cookie"] ||= [])
79
+ ck.each {|c| h << c}
80
+ end
81
+ end
82
+ def set_cookie *ck
83
+ h = (@headers["Set-cookie"] ||= [])
84
+ if ck.length > 0
85
+ h.clear
86
+ add_set_cookie *ck
87
+ else
88
+ h
89
+ end
90
+ end
91
+
92
+
93
+ # This is intended to send a complete HTTP response, including closing the connection
94
+ # if appropriate at the end of the transmission. Don't use this method to send partial
95
+ # or iterated responses. This method will send chunks and multiparts provided they
96
+ # are all available when we get here.
97
+ # Note that the default @status is 200 if the value doesn't exist.
98
+ def send_response
99
+ send_headers
100
+ send_body
101
+ send_trailer
102
+ close_connection_after_writing unless (@keep_connection_open and (@status || 200) < 500)
103
+ end
104
+
105
+ # Send the headers out in alpha-sorted order. This will degrade performance to some
106
+ # degree, and is intended only to simplify the construction of unit tests.
107
+ #
108
+ def send_headers
109
+ raise "sent headers already" if @sent_headers
110
+ @sent_headers = true
111
+
112
+ fixup_headers
113
+
114
+ ary = []
115
+ ary << "HTTP/1.1 #{@status || 200} #{@status_string || '...'}\r\n"
116
+ ary += generate_header_lines(@headers)
117
+ ary << "\r\n"
118
+
119
+ send_data ary.join
120
+ end
121
+
122
+
123
+ def generate_header_lines in_hash
124
+ out_ary = []
125
+ in_hash.keys.sort.each {|k|
126
+ v = in_hash[k]
127
+ if v.is_a?(Array)
128
+ v.each {|v1| out_ary << "#{k}: #{v1}\r\n" }
129
+ else
130
+ out_ary << "#{k}: #{v}\r\n"
131
+ end
132
+ }
133
+ out_ary
134
+ end
135
+ private :generate_header_lines
136
+
137
+
138
+ # Examine the content type and data and other things, and perform a final
139
+ # fixup of the header array. We expect this to be called just before sending
140
+ # headers to the remote peer.
141
+ # In the case of multiparts, we ASSUME we will get called before any content
142
+ # gets sent out, because the multipart boundary is created here.
143
+ #
144
+ def fixup_headers
145
+ if @content
146
+ @headers["Content-length"] = content.to_s.bytesize
147
+ elsif @chunks
148
+ @headers["Transfer-encoding"] = "chunked"
149
+ # Might be nice to ENSURE there is no content-length header,
150
+ # but how to detect all the possible permutations of upper/lower case?
151
+ elsif @multiparts
152
+ @multipart_boundary = self.class.concoct_multipart_boundary
153
+ @headers["Content-type"] = "multipart/x-mixed-replace; boundary=\"#{@multipart_boundary}\""
154
+ else
155
+ @headers["Content-length"] = 0
156
+ end
157
+ end
158
+
159
+ # we send either content, chunks, or multiparts. Content can only be sent once.
160
+ # Chunks and multiparts can be sent any number of times.
161
+ # DO NOT close the connection or send any goodbye kisses. This method can
162
+ # be called multiple times to send out chunks or multiparts.
163
+ def send_body
164
+ if @content
165
+ send_content
166
+ elsif @chunks
167
+ send_chunks
168
+ elsif @multiparts
169
+ send_multiparts
170
+ else
171
+ @content = ""
172
+ send_content
173
+ end
174
+ end
175
+
176
+ # send a trailer which depends on the type of body we're dealing with.
177
+ # The assumption is that we're about to end the transmission of this particular
178
+ # HTTP response. (A connection-close may or may not follow.)
179
+ #
180
+ def send_trailer
181
+ send_headers unless @sent_headers
182
+ if @content
183
+ # no-op
184
+ elsif @chunks
185
+ unless @last_chunk_sent
186
+ chunk ""
187
+ send_chunks
188
+ end
189
+ elsif @multiparts
190
+ # in the lingo of RFC 2046/5.1.1, we're sending an "epilog"
191
+ # consisting of a blank line. I really don't know how that is
192
+ # supposed to interact with the case where we leave the connection
193
+ # open after transmitting the multipart response.
194
+ send_data "\r\n--#{@multipart_boundary}--\r\n\r\n"
195
+ else
196
+ # no-op
197
+ end
198
+ end
199
+
200
+ def send_content
201
+ raise "sent content already" if @sent_content
202
+ @sent_content = true
203
+ send_data((@content || "").to_s)
204
+ end
205
+
206
+ # add a chunk to go to the output.
207
+ # Will cause the headers to pick up "content-transfer-encoding"
208
+ # Add the chunk to a list. Calling #send_chunks will send out the
209
+ # available chunks and clear the chunk list WITHOUT closing the connection,
210
+ # so it can be called any number of times.
211
+ # TODO!!! Per RFC2616, we may not send chunks to an HTTP/1.0 client.
212
+ # Raise an exception here if our user tries to do so.
213
+ # Chunked transfer coding is defined in RFC2616 pgh 3.6.1.
214
+ # The argument can be a string or a hash. The latter allows for
215
+ # sending chunks with extensions (someday).
216
+ #
217
+ def chunk text
218
+ @chunks ||= []
219
+ @chunks << text
220
+ end
221
+
222
+ # send the contents of the chunk list and clear it out.
223
+ # ASSUMES that headers have been sent.
224
+ # Does NOT close the connection.
225
+ # Can be called multiple times.
226
+ # According to RFC2616, phg 3.6.1, the last chunk will be zero length.
227
+ # But some caller could accidentally set a zero-length chunk in the middle
228
+ # of the stream. If that should happen, raise an exception.
229
+ # The reason for supporting chunks that are hashes instead of just strings
230
+ # is to enable someday supporting chunk-extension codes (cf the RFC).
231
+ # TODO!!! We're not supporting the final entity-header that may be
232
+ # transmitted after the last (zero-length) chunk.
233
+ #
234
+ def send_chunks
235
+ send_headers unless @sent_headers
236
+ while chunk = @chunks.shift
237
+ raise "last chunk already sent" if @last_chunk_sent
238
+ text = chunk.is_a?(Hash) ? chunk[:text] : chunk.to_s
239
+ send_data "#{format("%x", text.length).upcase}\r\n#{text}\r\n"
240
+ @last_chunk_sent = true if text.length == 0
241
+ end
242
+ end
243
+
244
+ # To add a multipart to the outgoing response, specify the headers and the
245
+ # body. If only a string is given, it's treated as the body (in this case,
246
+ # the header is assumed to be empty).
247
+ #
248
+ def multipart arg
249
+ vals = if arg.is_a?(String)
250
+ {:body => arg, :headers => {}}
251
+ else
252
+ arg
253
+ end
254
+
255
+ @multiparts ||= []
256
+ @multiparts << vals
257
+ end
258
+
259
+ # Multipart syntax is defined in RFC 2046, pgh 5.1.1 et seq.
260
+ # The CRLF which introduces the boundary line of each part (content entity)
261
+ # is defined as being part of the boundary, not of the preceding part.
262
+ # So we don't need to mess with interpreting the last bytes of a part
263
+ # to ensure they are CRLF-terminated.
264
+ #
265
+ def send_multiparts
266
+ send_headers unless @sent_headers
267
+ while part = @multiparts.shift
268
+ send_data "\r\n--#{@multipart_boundary}\r\n"
269
+ send_data( generate_header_lines( part[:headers] || {} ).join)
270
+ send_data "\r\n"
271
+ send_data part[:body].to_s
272
+ end
273
+ end
274
+
275
+ # TODO, this is going to be way too slow. Cache up the uuidgens.
276
+ #
277
+ def self.concoct_multipart_boundary
278
+ @multipart_index ||= 0
279
+ @multipart_index += 1
280
+ if @multipart_index >= 1000
281
+ @multipart_index = 0
282
+ @multipart_guid = nil
283
+ end
284
+ @multipart_guid ||= `uuidgen -r`.chomp.gsub(/\-/,"")
285
+ "#{@multipart_guid}#{@multipart_index}"
286
+ end
287
+
288
+ def send_redirect location
289
+ @status = 302 # TODO, make 301 available by parameter
290
+ @status_string = "Moved Temporarily"
291
+ @headers["Location"] = location
292
+ send_response
293
+ end
294
+ end
295
+ end
296
+
297
+ #----------------------------------------------------------------------------
298
+
299
+ require 'forwardable'
300
+
301
+ module EventMachine
302
+ class DelegatedHttpResponse < HttpResponse
303
+ extend Forwardable
304
+ def_delegators :@delegate,
305
+ :send_data,
306
+ :close_connection,
307
+ :close_connection_after_writing
308
+
309
+ def initialize dele
310
+ super()
311
+ @delegate = dele
312
+ end
313
+ end
314
+ end