summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaku Ytti <saku@ytti.fi>2014-02-23 19:11:29 +0200
committerSaku Ytti <saku@ytti.fi>2014-02-23 19:11:29 +0200
commit8880188001da23a5f0960e3970c4eb9bbd448306 (patch)
tree41a1f79450ff1683a2d5aa1f024a564e84230e25
parent06e5f68db6cfcbd80295874db1f00a25e8ba1229 (diff)
Migrate to sinatra/puma from webrick
As I can't do IO#select on sinatra/puma to run it when I have time, I have to run it on separate thread. This means Nodes container needs to be thread safe, it now has ghetto mutex locking, but I probably need to be be more focused what are the external methods that can be called and wrap those in @mutex.synchronize Provide also HTML UI not just JSON for ghetto UI to people who don't want to integrate
-rwxr-xr-xbin/oxidized2
-rw-r--r--lib/oxidized/api/web.rb19
-rw-r--r--lib/oxidized/api/web/public/css/oxidized.css35
-rw-r--r--lib/oxidized/api/web/views/default.haml4
-rw-r--r--lib/oxidized/api/web/views/head.haml3
-rw-r--r--lib/oxidized/api/web/views/node.haml6
-rw-r--r--lib/oxidized/api/web/views/nodes.haml27
-rw-r--r--lib/oxidized/api/web/webapp.rb98
-rw-r--r--lib/oxidized/config/core.rb2
-rw-r--r--lib/oxidized/config/defaults.rb2
-rw-r--r--lib/oxidized/core.rb7
-rw-r--r--lib/oxidized/input/cli.rb6
-rw-r--r--lib/oxidized/input/ssh.rb2
-rw-r--r--lib/oxidized/job.rb2
-rw-r--r--lib/oxidized/manager.rb2
-rw-r--r--lib/oxidized/node.rb12
-rw-r--r--lib/oxidized/nodes.rb32
-rw-r--r--lib/oxidized/output/file.rb3
-rw-r--r--lib/oxidized/worker.rb2
-rw-r--r--oxidized.gemspec6
20 files changed, 245 insertions, 27 deletions
diff --git a/bin/oxidized b/bin/oxidized
index 2509279..72db61a 100755
--- a/bin/oxidized
+++ b/bin/oxidized
@@ -2,6 +2,8 @@
require 'oxidized'
+trap("INT") { exit } # sinatra will otherwise steak this from us
+
begin
Process.daemon unless $DEBUG
Oxidized.new
diff --git a/lib/oxidized/api/web.rb b/lib/oxidized/api/web.rb
new file mode 100644
index 0000000..9a5a507
--- /dev/null
+++ b/lib/oxidized/api/web.rb
@@ -0,0 +1,19 @@
+module Oxidized
+ module API
+ class Web
+ attr_reader :thread
+ def initialize nodes, listen
+ require 'oxidized/api/web/webapp'
+ addr, port = listen.to_s.split ':'
+ port, addr = addr, nil if not port
+ WebApp.set :server, %w(puma)
+ WebApp.set :bind, addr if addr
+ WebApp.set :port, port
+ WebApp.set :nodes, nodes
+ end
+ def run
+ @thread = Thread.new { WebApp.run! }
+ end
+ end
+ end
+end
diff --git a/lib/oxidized/api/web/public/css/oxidized.css b/lib/oxidized/api/web/public/css/oxidized.css
new file mode 100644
index 0000000..8455513
--- /dev/null
+++ b/lib/oxidized/api/web/public/css/oxidized.css
@@ -0,0 +1,35 @@
+body {
+ background: #fdf6e3;
+ color: #002b36;
+}
+
+a:link {
+ /* color: #268bd2; */
+ color: #dc322f;
+ text-decoration: none;
+}
+
+a:visited {
+}
+
+a:hover {
+ color: #d33682;
+ text-decoration: underline;
+}
+
+a:active {
+}
+
+tr.odd {
+ background: #eee8d5;
+}
+
+tr.even {
+ background: #fdf6e3;
+}
+
+tr:hover {
+ background: #586e75;
+ color: #fdf6e3;
+}
+
diff --git a/lib/oxidized/api/web/views/default.haml b/lib/oxidized/api/web/views/default.haml
new file mode 100644
index 0000000..1ff1f4b
--- /dev/null
+++ b/lib/oxidized/api/web/views/default.haml
@@ -0,0 +1,4 @@
+%html
+ !=haml :head
+ %body
+ =@data
diff --git a/lib/oxidized/api/web/views/head.haml b/lib/oxidized/api/web/views/head.haml
new file mode 100644
index 0000000..1619512
--- /dev/null
+++ b/lib/oxidized/api/web/views/head.haml
@@ -0,0 +1,3 @@
+%head
+ %title oxidized
+ %link{:rel=>'stylesheet', :href=>'/css/oxidized.css'}
diff --git a/lib/oxidized/api/web/views/node.haml b/lib/oxidized/api/web/views/node.haml
new file mode 100644
index 0000000..6c68e07
--- /dev/null
+++ b/lib/oxidized/api/web/views/node.haml
@@ -0,0 +1,6 @@
+%html
+ !=haml :head
+ %body
+ -out='';PP.pp(@data,out)
+ %pre
+ =out
diff --git a/lib/oxidized/api/web/views/nodes.haml b/lib/oxidized/api/web/views/nodes.haml
new file mode 100644
index 0000000..4bc0b14
--- /dev/null
+++ b/lib/oxidized/api/web/views/nodes.haml
@@ -0,0 +1,27 @@
+%html
+ !=haml :head
+ %body
+ %a(href="/reload") reload list of nodes
+ %table
+ %tr
+ %th Name
+ %th IP
+ %th Group
+ %th Last Status
+ %th Last Time
+ %th Config
+ %th Update
+ -trclass = %w(even odd)
+ -@data.sort_by{|e|e[:name]}.each do |node|
+ -klass = trclass.rotate!.first
+ %tr{:class=>klass}
+ %td
+ %a(href="/node/show/#{node[:name]}") #{node[:name]}
+ %td= node[:ip]
+ %td= node[:group]
+ %td= node[:status]
+ %td= node[:time]
+ %td
+ %a(href="/node/fetch/#{node[:full_name]}") config
+ %td
+ %a(href="/node/next/#{node[:full_name]}") update
diff --git a/lib/oxidized/api/web/webapp.rb b/lib/oxidized/api/web/webapp.rb
new file mode 100644
index 0000000..13bd0ab
--- /dev/null
+++ b/lib/oxidized/api/web/webapp.rb
@@ -0,0 +1,98 @@
+require 'sinatra/base'
+require 'sinatra/json'
+require 'haml'
+require 'pp'
+module Oxidized
+ module API
+ class WebApp < Sinatra::Base
+
+ get '/nodes.?:format?' do
+ @data = nodes.list.map do |node|
+ node[:status] = 'never'
+ node[:time] = 'never'
+ node[:group] = 'default' unless node[:group]
+ if node[:last]
+ node[:status] = node[:last][:status]
+ node[:time] = node[:last][:end]
+ end
+ node
+ end
+ out :nodes
+ end
+
+ get '/reload.?:format?' do
+ nodes.load
+ @data = 'reloaded list of nodes'
+ out
+ end
+
+
+ get '/node/fetch/:node' do
+ node, @json = route_parse :node
+ @data = nodes.fetch node, nil
+ out :text
+ end
+
+ get '/node/fetch/:group/:node' do
+ node, @json = route_parse :node
+ @data = nodes.fetch node, params[:group]
+ out :text
+ end
+
+
+ get '/node/next/:node' do
+ node, @json = route_parse :node
+ nodes.next node
+ redirect '/nodes' unless @json
+ @data = 'ok'
+ out
+ end
+
+ # use this to attach author/email/message to commit
+ put '/node/next/:node' do
+ node, @json = route_parse :node
+ opt = JSON.load request.body.read
+ nodes.next node, opt
+ redirect '/nodes' unless @json
+ @data = 'ok'
+ out
+ end
+
+ get '/node/show/:node' do
+ node, @json = route_parse :node
+ @data = nodes.show node
+ out :node
+ end
+
+ #get '/node/:node' do
+ # @data = nodes.show params[:node]
+ # out
+ #end
+
+ def out template=:default
+ if @json or params[:format] == 'json'
+ json @data
+ elsif template == :text
+ content_type :text
+ @data
+ else
+ haml template
+ end
+ end
+
+ def nodes
+ settings.nodes
+ end
+
+ def route_parse param
+ json = false
+ e = params[param].split '.'
+ if e.last == 'json'
+ e.pop
+ json = true
+ end
+ [e.join('.'), json]
+ end
+ end
+ end
+end
diff --git a/lib/oxidized/config/core.rb b/lib/oxidized/config/core.rb
index 6c91920..c2cde58 100644
--- a/lib/oxidized/config/core.rb
+++ b/lib/oxidized/config/core.rb
@@ -11,7 +11,7 @@ module Oxidized
# load config from file or bootstrap with built-ins
def load
if File.exists? @file
- marshal_load YAML.load_file @file
+ marshal_load YAML.load_file @file
else
require 'oxidized/config/bootstrap'
end
diff --git a/lib/oxidized/config/defaults.rb b/lib/oxidized/config/defaults.rb
index d189ca3..c30143f 100644
--- a/lib/oxidized/config/defaults.rb
+++ b/lib/oxidized/config/defaults.rb
@@ -5,7 +5,7 @@ module Oxidized
InputDir = File.join Directory, %w(lib oxidized input)
OutputDir = File.join Directory, %w(lib oxidized output)
ModelDir = File.join Directory, %w(lib oxidized model)
- SourceDir = File.join Directory, %w(lib oxidized source)
+ SourceDir = File.join Directory, %w(lib oxidized source)
Sleep = 1
end
class << self
diff --git a/lib/oxidized/core.rb b/lib/oxidized/core.rb
index 59292f9..70e9e42 100644
--- a/lib/oxidized/core.rb
+++ b/lib/oxidized/core.rb
@@ -4,7 +4,7 @@ module Oxidized
require 'oxidized/worker'
require 'oxidized/nodes'
require 'oxidized/manager'
- require 'oxidized/api/rest'
+ require 'oxidized/api/web'
class << self
def new *args
Core.new args
@@ -16,7 +16,8 @@ module Oxidized
Oxidized.mgr = Manager.new
nodes = Nodes.new
@worker = Worker.new nodes
- @rest = API::Rest.new nodes, CFG.rest if CFG.rest
+ @rest = API::Web.new nodes, CFG.rest if CFG.rest
+ @rest.run
run
end
@@ -25,7 +26,7 @@ module Oxidized
def run
while true
@worker.work
- @rest ? @rest.work : sleep(Config::Sleep)
+ Config::Sleep
end
end
end
diff --git a/lib/oxidized/input/cli.rb b/lib/oxidized/input/cli.rb
index 8daddac..ab93b06 100644
--- a/lib/oxidized/input/cli.rb
+++ b/lib/oxidized/input/cli.rb
@@ -1,7 +1,7 @@
module Oxidized
class Input
module CLI
-
+
def initialize
@post_login = []
@pre_logout = []
@@ -17,13 +17,13 @@ module Oxidized
def disconnect_cli
@pre_logout.each { |command, block| block ? block.call : (cmd command) }
end
-
+
def post_login _post_login=nil, &block
unless @exec
@post_login << [_post_login, block]
end
end
-
+
def pre_logout _pre_logout=nil, &block
unless @exec
@pre_logout << [_pre_logout, block]
diff --git a/lib/oxidized/input/ssh.rb b/lib/oxidized/input/ssh.rb
index 67be180..5c9a4f0 100644
--- a/lib/oxidized/input/ssh.rb
+++ b/lib/oxidized/input/ssh.rb
@@ -77,7 +77,7 @@ module Oxidized
expect expect_re if expect_re
@output
end
-
+
def expect regexp
@ssh.loop(0.1) do
sleep 0.1
diff --git a/lib/oxidized/job.rb b/lib/oxidized/job.rb
index 6921c2b..6fb60a8 100644
--- a/lib/oxidized/job.rb
+++ b/lib/oxidized/job.rb
@@ -5,7 +5,7 @@ module Oxidized
@node = node
@start = Time.now.utc
super do |node|
- @status, @config = node.run
+ @status, @config = node.run
@end = Time.now.utc
@time = @end - @start
end
diff --git a/lib/oxidized/manager.rb b/lib/oxidized/manager.rb
index 8c53d64..5065617 100644
--- a/lib/oxidized/manager.rb
+++ b/lib/oxidized/manager.rb
@@ -34,7 +34,7 @@ module Oxidized
def model= _model
_model = Manager.load Config::ModelDir, _model
return false if _model.empty?
- @model.merge! _model
+ @model.merge! _model
end
def source= _source
return nil if @source.key? _source
diff --git a/lib/oxidized/node.rb b/lib/oxidized/node.rb
index 05a926c..6c7b3aa 100644
--- a/lib/oxidized/node.rb
+++ b/lib/oxidized/node.rb
@@ -58,12 +58,14 @@ module Oxidized
def serialize
h = {
- :name => @name,
- :ip => @ip,
- :group => @group,
- :model => @model.class.to_s,
- :last => nil,
+ :name => @name,
+ :full_name => @name,
+ :ip => @ip,
+ :group => @group,
+ :model => @model.class.to_s,
+ :last => nil,
}
+ h[:full_name] = [@group, @name].join('/') if @group
if @last
h[:last] = {
:start => @last.start,
diff --git a/lib/oxidized/nodes.rb b/lib/oxidized/nodes.rb
index affeea8..981e082 100644
--- a/lib/oxidized/nodes.rb
+++ b/lib/oxidized/nodes.rb
@@ -7,36 +7,43 @@ module Oxidized
alias :put :unshift
def initialize *args
super
+ @mutex= Mutex.new # we compete for the nodes with webapi thread
load if args.empty?
end
def load
+ lock
new = []
@source = CFG.source[:default]
Oxidized.mgr.source = @source
Oxidized.mgr.source[@source].new.load.each do |node|
new.push Node.new node
end
- replace new
+ unlock(replace new)
end
def list
- map { |e| e.name }
+ lock
+ unlock(map { |e| e.serialize })
end
def show node
+ lock
i = find_node_index node
- self[i].serialize
+ unlock(self[i].serialize)
end
def fetch node, group
+ lock
i = find_node_index node
output = self[i].output.new
+ unlock
raise Oxidized::NotSupported unless output.respond_to? :fetch
output.fetch node, group
end
def del node
- delete_at find_node_index
+ lock
+ unlock(delete_at find_node_index(node))
end
# @param node [String] name of the node moved into the head of array
def next node, opt={}
- require 'pp'
+ lock
n = del node
if n
n.user = opt['user']
@@ -44,21 +51,32 @@ module Oxidized
n.from = opt['from']
put n
end
+ unlock
end
alias :top :next
# @return [String] node from the head of the array
def get
- (self << shift).last
+ lock
+ unlock((self << shift).last)
end
private
+ def lock
+ @mutex.lock unless @mutex.owned?
+ end
+
+ def unlock arg=nil
+ @mutex.unlock if @mutex.owned?
+ arg
+ end
+
def find_index node
index { |e| e.name == node }
end
def find_node_index node
- find_index node or raise Oxidized::NodeNotFound
+ find_index node or raise Oxidized::NodeNotFound, "unable to find '#{node}'"
end
end
end
diff --git a/lib/oxidized/output/file.rb b/lib/oxidized/output/file.rb
index da778ff..ee8a9a6 100644
--- a/lib/oxidized/output/file.rb
+++ b/lib/oxidized/output/file.rb
@@ -25,7 +25,6 @@ class OxFile < Output
open(file, 'w') { |fh| fh.write data }
end
-
def fetch node, group
cfg_dir = @cfg[:directory]
if group # group is explicitly defined by user
@@ -39,6 +38,6 @@ class OxFile < Output
end
end
end
-
+
end
end
diff --git a/lib/oxidized/worker.rb b/lib/oxidized/worker.rb
index 14cf2a5..fcdd6f0 100644
--- a/lib/oxidized/worker.rb
+++ b/lib/oxidized/worker.rb
@@ -26,7 +26,7 @@ module Oxidized
msg = "update #{node.name}"
msg += " from #{node.from}" if node.from
msg += " with message '#{node.msg}'" if node.msg
- node.output.new.store node.name, job.config,
+ node.output.new.store node.name, job.config,
:msg => msg, :user => node.user, :group => node.group
node.reset
else
diff --git a/oxidized.gemspec b/oxidized.gemspec
index cd324f1..4c6839a 100644
--- a/oxidized.gemspec
+++ b/oxidized.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = 'oxidized'
- s.version = '0.0.20'
+ s.version = '0.0.21'
s.platform = Gem::Platform::RUBY
s.authors = [ 'Saku Ytti' ]
s.email = %w( saku@ytti.fi )
@@ -16,4 +16,8 @@ Gem::Specification.new do |s|
s.add_dependency 'sqlite3'
s.add_dependency 'net-ssh'
s.add_dependency 'grit'
+ s.add_dependency 'sinatra'
+ s.add_dependency 'haml'
+ s.add_dependency 'puma'
+
end