adminix 0.1.49 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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