Commit a0f63c8f authored by John E. Vincent's avatar John E. Vincent

namespacing and standalone configuration

parent 7d1ba00d
......@@ -5,6 +5,7 @@ gem "ohm", "= 0.1.3"
gem "ohm-contrib", "= 0.1.0"
gem "haml", "= 3.0.25"
gem "rake", "= 0.8.7"
gem "vegas", "= 0.1.8"
group :development do
gem "sinatra-reloader", "= 0.5.0"
gem "rspec", "= 2.4.0"
......
......@@ -25,6 +25,8 @@ GEM
ohm-contrib (0.1.0)
ohm
rack (1.2.1)
rack-jetty (0.2.0)
rack (>= 1.0.0)
rack-test (0.5.7)
rack (>= 1.0)
rake (0.8.7)
......@@ -56,6 +58,8 @@ GEM
monkey-lib (~> 0.5.0)
sinatra (~> 1.0)
tilt (1.2.2)
vegas (0.1.8)
rack (>= 1.0.0)
warbler (1.2.1)
jruby-jars (>= 1.4.0)
jruby-rack (>= 1.0.0)
......@@ -76,6 +80,7 @@ DEPENDENCIES
json-jruby (= 1.4.6)
ohm (= 0.1.3)
ohm-contrib (= 0.1.0)
rack-jetty (= 0.2.0)
rack-test (= 0.5.7)
rake (= 0.8.7)
rcov (= 0.9.9)
......@@ -83,5 +88,6 @@ DEPENDENCIES
sinatra (= 1.1.2)
sinatra-namespace (= 0.6.1)
sinatra-reloader (= 0.5.0)
vegas (= 0.1.8)
warbler (= 1.2.1)
yajl-ruby (= 0.7.9)
......@@ -12,17 +12,17 @@ require 'rspec/core'
require 'rspec/core/rake_task'
desc "Populate database with sample dataset"
task :sample do |t|
task :sample, :redis_url do |t, args|
require 'ohm'
begin
require 'yajl'
rescue LoadError
require 'json'
end
require File.join(File.dirname(__FILE__), 'lib','models')
require File.join(File.dirname(__FILE__), 'lib','noah')
config_file = YAML::load File.new(File.join(File.dirname(__FILE__),'config','db.yml')).read
Ohm::connect(:url => "redis://#{config_file["development"]["host"]}:#{config_file["development"]["port"]}/#{config_file["development"]["db"]}")
Ohm::connect(:url => args.redis_url)
Ohm::redis.flushdb
puts "Creating Host entry for 'localhost'"
h = Host.create(:name => 'localhost', :status => "up")
......
#!/usr/bin/env ruby
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
require 'noah/cli'
require 'noah'
require 'vegas'
n = Noah::CLI.new
n.parse_options
#NoahApp.run!
Vegas::Runner.new(Noah::App, 'noah') do |runner, opts, app|
opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r }
end
require File.join(File.dirname(__FILE__), 'noah')
run NoahApp
require File.join(File.dirname(__FILE__), 'lib','noah')
ENV['REDIS_URL'] = "redis://localhost:6379/0"
run Noah::App
logfile: logs/noah.log
loglevel: DEBUG
mode: development
production: "redis://localhost:6379/0"
development: "redis://localhost:6379/1"
test: "redis://localhost:6379/2"
production:
host: localhost
port: 6379
db: 0
development:
host: localhost
port: 6379
db: 1
test:
host: localhost
port: 6379
db: 2
# Disable automatic framework detection by uncommenting/setting to false
# Warbler.framework_detection = false
# Warbler web application assembly configuration file
Warbler::Config.new do |config|
# Features: additional options controlling how the jar is built.
# Currently the following features are supported:
# - gemjar: package the gem repository in a jar file in WEB-INF/lib
config.features = %w(gemjar)
# Application directories to be included in the webapp.
config.dirs = %w(config lib views)
# Additional files/directories to include, above those in config.dirs
config.includes = FileList["README.md", "config.ru", "noah.rb"]
# Additional files/directories to exclude
# config.excludes = FileList["lib/tasks/*"]
# Additional Java .jar files to include. Note that if .jar files are placed
# in lib (and not otherwise excluded) then they need not be mentioned here.
# JRuby and JRuby-Rack are pre-loaded in this list. Be sure to include your
# own versions if you directly set the value
# config.java_libs += FileList["lib/java/*.jar"]
# Loose Java classes and miscellaneous files to be placed in WEB-INF/classes.
# config.java_classes = FileList["target/classes/**.*"]
# One or more pathmaps defining how the java classes should be copied into
# WEB-INF/classes. The example pathmap below accompanies the java_classes
# configuration above. See http://rake.rubyforge.org/classes/String.html#M000017
# for details of how to specify a pathmap.
# config.pathmaps.java_classes << "%{target/classes/,}p"
# Path to the pre-bundled gem directory inside the war file. Default
# is 'WEB-INF/gems'. Specify path if gems are already bundled
# before running Warbler. This also sets 'gem.path' inside web.xml.
#config.gem_path = "WEB-INF/gems"
# Bundler support is built-in. If Warbler finds a Gemfile in the
# project directory, it will be used to collect the gems to bundle
# in your application. If you wish to explicitly disable this
# functionality, uncomment here.
# config.bundler = false
# An array of Bundler groups to avoid including in the war file.
# Defaults to ["development", "test"].
# config.bundle_without = []
# Files for WEB-INF directory (next to web.xml). This contains
# web.xml by default. If there is an .erb-File it will be processed
# with webxml-config. You may want to exclude this file via
# config.excludes.
# config.webinf_files += FileList["jboss-web.xml"]
# Other gems to be included. You need to tell Warbler which gems
# your application needs so that they can be packaged in the war
# file.
# The Rails gems are included by default unless the vendor/rails
# directory is present.
# config.gems += ["activerecord-jdbcmysql-adapter", "jruby-openssl"]
# config.gems << "tzinfo"
# Uncomment this if you don't want to package rails gem.
# config.gems -= ["rails"]
# The most recent versions of gems are used.
# You can specify versions of gems by using a hash assignment:
# config.gems["rails"] = "2.0.2"
# You can also use regexps or Gem::Dependency objects for flexibility or
# fine-grained control.
# config.gems << /^merb-/
# config.gems << Gem::Dependency.new("merb-core", "= 0.9.3")
# Include gem dependencies not mentioned specifically. Default is
# true, uncomment to turn off.
# config.gem_dependencies = false
# Array of regular expressions matching relative paths in gems to be
# excluded from the war. Defaults to empty, but you can set it like
# below, which excludes test files.
config.gem_excludes = [/^(test|spec)\//]
# Files to be included in the root of the webapp. Note that files in public
# will have the leading 'public/' part of the path stripped during staging.
# config.public_html = FileList["public/**/*", "doc/**/*"]
# Pathmaps for controlling how public HTML files are copied into the .war
# config.pathmaps.public_html = ["%{public/,}p"]
# Pathmaps for controlling how application files are copied into the .war
# config.pathmaps.application = ["WEB-INF/%p"]
# Name of the war file (without the .war) -- defaults to the basename
# of RAILS_ROOT
# config.war_name = "mywar"
# Name of the MANIFEST.MF template for the war file. Defaults to a simple
# MANIFEST.MF that contains the version of Warbler used to create the war file.
# config.manifest_file = "config/MANIFEST.MF"
# When using the 'compiled' feature and specified, only these Ruby
# files will be compiled. Default is to compile all \.rb files in
# the application.
# config.compiled_ruby_files = FileList['app/**/*.rb']
config.compiled_ruby_files = FileList['lib/**/*.rb', 'noah.rb']
# Value of RAILS_ENV for the webapp -- default as shown below
config.webxml.rails.env = ENV['RAILS_ENV'] || 'production'
# Application booter to use, one of :rack, :rails, or :merb (autodetected by default)
config.webxml.booter = :rack
# When using the :rack booter, "Rackup" script to use.
# - For 'rackup.path', the value points to the location of the rackup
# script in the web archive file. You need to make sure this file
# gets included in the war, possibly by adding it to config.includes
# or config.webinf_files above.
# - For 'rackup', the rackup script you provide as an inline string
# is simply embedded in web.xml.
# The script is evaluated in a Rack::Builder to load the application.
# Examples:
#config.webxml.rackup.path = 'WEB-INF/config.ru'
config.webxml.rackup = %{require './noah'; run NoahApp}
# config.webxml.rackup = require 'cgi' && CGI::escapeHTML(File.read("config.ru"))
# Control the pool of Rails runtimes. Leaving unspecified means
# the pool will grow as needed to service requests. It is recommended
# that you fix these values when running a production server!
# config.webxml.jruby.min.runtimes = 2
# config.webxml.jruby.max.runtimes = 4
# JNDI data source name
# config.webxml.jndi = 'jdbc/rails'
end
module Sinatra
module NoahHelpers
def host(opts = {})
Host.find(opts).first
end
def hosts(opts = {})
Hosts.all(opts)
end
def service(opts = {})
Service.find(options)
end
def services(opts = {})
Services.all(opts)
end
def host_service(hostname, servicename)
h = Host.find(:name => hostname).first
if h.nil?
nil
else
Service.find(:host_id => h.id, :name => servicename).first
end
end
def host_services(hostname)
h = Host.find(:name => hostname).first
if h.nil?
nil
else
Services.all(:host_id => id)
end
end
def application(opts = {})
Application.find(opts).first
end
def applications(opts = {})
Applications.all(opts)
end
def configuration(opts = {})
Configuration.find(opts).first
end
def configurations(opts = {})
Configurations.all(opts)
end
end
helpers NoahHelpers
end
require 'ohm/contrib'
class Host < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
collection :services, Service
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_unique :name
assert_member :status, ["up","down","pending"]
end
def to_hash
arr = []
services.sort.each {|s| arr << s.to_hash}
h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => arr}
super.merge(h)
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
# exclude requested status from lookup
h = find(opts.reject{|key,value| key == :status}).first
host = h.nil? ? create(opts) : h
host.status = opts[:status]
if host.valid?
host.save
end
host
rescue Exception => e
e.message
end
end
end
end
class Service < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
reference :host, Host
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_present :host_id
assert_unique [:name, :host_id]
assert_member :status, ["up", "down", "pending"]
end
def to_hash
super.merge(:name => name, :status => status, :updated_at => updated_at, :host => Host[host_id].name)
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
# convert passed host object to host_id if passed
if opts.has_key?(:host)
opts.merge!({:host_id => opts[:host].id})
opts.reject!{|key, value| key == :host}
end
# exclude requested status from lookup
s = find(opts.reject{|key,value| key == :status}).first
service = s.nil? ? create(opts) : s
service.status = opts[:status]
if service.valid?
service.save
end
service
rescue Exception => e
e.message
end
end
end
end
class Configuration < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :format
attribute :body
attribute :new_record
reference :application, Application
index :name
def validate
assert_present :name
assert_present :format
assert_present :body
assert_unique [:name, :application_id]
end
def to_hash
super.merge(:name => name, :format => format, :body => body, :update_at => updated_at, :application => Application[application_id].name)
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts={})
begin
if find(opts).first.nil?
conf = create(opts)
else
conf = find(opts).first
end
rescue Exception => e
e.message
end
end
end
end
class Application < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
collection :configurations, Configuration
index :name
def validate
assert_present :name
assert_unique :name
end
def to_hash
arr = []
configurations.sort.each {|c| arr << c.to_hash}
super.merge(:name => name, :updated_at => updated_at, :configurations => arr)
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
find(opts).first.nil? ? (app = create(opts)) : (app = find(opts).first)
if app.valid?
app.save
end
app
rescue Exception => e
e.message
end
end
end
end
class Watcher < Ohm::Model #NYI
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
attribute :client
attribute :endpoint
attribute :event
attribute :action
index :client
index :event
def validate
assert_present :client, :endpoint, :event, :action
assert_unique [:client, :endpoint, :event, :action]
end
end
# Some pluralized helper models
class Hosts
def self.all(options = {})
options.empty? ? Host.all.sort : Host.find(options).sort
end
end
class Services
def self.all(options = {})
options.empty? ? Service.all.sort : Service.find(options).sort
end
end
class Applications
def self.all(options = {})
options.empty? ? Application.all.sort : Application.find(options).sort
end
end
class Configurations
def self.all(options = {})
options.empty? ? Configuration.all.sort : Configuration.find(options).sort
end
end
require 'sinatra/base'
require 'sinatra/namespace'
require 'ohm'
require 'ohm/contrib'
begin
......@@ -9,9 +7,12 @@ rescue LoadError
end
require 'haml'
require 'yaml'
require 'sinatra/base'
require 'sinatra/namespace'
require 'noah/config'
require 'noah/helpers'
require 'noah/models'
require 'noah/app'
require File.join(File.dirname(__FILE__), 'noah','hosts')
require File.join(File.dirname(__FILE__), 'noah','services')
require File.join(File.dirname(__FILE__), 'noah','applications')
require File.join(File.dirname(__FILE__), 'noah','configurations')
require File.join(File.dirname(__FILE__), 'noah','watchers')
require File.join(File.dirname(__FILE__), 'noah','app')
require 'sinatra/base'
require 'sinatra/namespace'
require 'ohm'
require 'ohm/contrib'
require File.join(File.dirname(__FILE__), 'helpers')
require File.join(File.dirname(__FILE__), 'models')
module Noah
class App < Sinatra::Base
register ::Sinatra::Namespace
helpers Noah::SinatraHelpers
configure do
set :app_file, __FILE__
set :root, File.expand_path(File.join(File.dirname(__FILE__), "..",".."))
set :server, %w[thin mongrel webrick]
set :logging, true
set :raise_errors, false
set :show_exceptions, false
end
@db_settings = YAML::load File.new(File.join(File.dirname(__FILE__),'config','db.yml')).read
class NoahApp < Sinatra::Base
register Sinatra::Namespace
helpers Sinatra::NoahHelpers
config_file = YAML::load File.new(File.join(File.dirname(__FILE__),'config','db.yml')).read
db = config_file["#{environment}"]
begin
Ohm.connect(:url => "redis://#{db["host"]}:#{db["port"]}/#{db["db"]}")
Ohm.redis.ping
rescue Errno::ECONNREFUSED => e
puts "Unable to connect to Redis. Shutting down...."
puts e.message
exit 1
end
configure do
set :app_file, __FILE__
set :root, File.dirname(__FILE__)
set :server, %w[thin mongrel webrick Jetty]
set :port, 9291
set :logging, true
set :raise_errors, false
set :show_exceptions, false
log = File.new("logs/noah.log", "a")
STDOUT.reopen(log)
STDERR.reopen(log)
end
configure(:development) do
require 'sinatra/reloader'
register Sinatra::Reloader
also_reload "models.rb"
also_reload "helpers.rb"
set :port, 9292
end
configure(:test) do
set :port, 9294
end
configure(:development) do
require 'sinatra/reloader'
register Sinatra::Reloader
also_reload File.join(File.dirname(__FILE__), 'models.rb')
also_reload File.join(File.dirname(__FILE__), 'helpers.rb')
end
get '/' do
content_type "text/html"
before do
content_type "application/json"
end
haml :index, :format => :html5
end
get '/' do
content_type "text/html"
before do
content_type "application/json"
end
haml :index, :format => :html5
end
not_found do
content_type "application/json"
erb :'404'
end
not_found do
content_type "application/json"
erb :'404'
end
error do
content_type "application/json"
erb :'500'
end
error do
content_type "application/json"
erb :'500'
end
namespace "/h" do
namespace "/h" do
get '/:hostname/:servicename/?' do |hostname, servicename|
h = host_service(hostname, servicename)
if h.nil?
halt 404
else
h.to_json
get '/:hostname/:servicename/?' do |hostname, servicename|
h = host_service(hostname, servicename)
if h.nil?
halt 404
else
h.to_json
end
end
end
get '/:hostname/?' do |hostname|
h = host(:name => hostname)
if h.nil?
halt 404
else
h.to_json
get '/:hostname/?' do |hostname|
h = host(:name => hostname)
if h.nil?
halt 404
else
h.to_json
end
end
end
get '/?' do
hosts.map {|h| h.to_hash}
if hosts.size == 0
halt 404
else
hosts.to_json
get '/?' do
hosts.map {|h| h.to_hash}
if hosts.size == 0
halt 404
else
hosts.to_json
end
end
end
put '/:hostname/?' do |hostname|
required_params = ["name", "status"]
data = JSON.parse(request.body.read)
(data.keys.sort == required_params.sort && data['name'] == hostname) ? (host = Host.find_or_create(:name => data['name'], :status => data['status'])) : (raise "Missing Parameters")
if host.valid?
r = {"result" => "success","id" => "#{host.id}","status" => "#{host.status}", "name" => "#{host.name}", "new_record" => host.is_new?}
r.to_json
else
raise "#{host.errors}"
put '/:hostname/?' do |hostname|
required_params = ["name", "status"]
data = JSON.parse(request.body.read)
(data.keys.sort == required_params.sort && data['name'] == hostname) ? (host = ::Host.find_or_create(:name => data['name'], :status => data['status'])) : (raise "Missing Parameters")
if host.valid?
r = {"result" => "success","id" => "#{host.id}","status" => "#{host.status}", "name" => "#{host.name}", "new_record" => host.is_new?}
r.to_json
else
raise "#{host.errors}"
end
end
end
delete '/:hostname/?' do |hostname|
host = Host.find(:name => hostname).first
if host
services = []
Service.find(:host_id => host.id).sort.each {|x| services << x; x.delete} if host.services.size > 0
host.delete
r = {"result" => "success", "id" => "#{host.id}", "name" => "#{hostname}", "service_count" => "#{services.size}"}
r.to_json
else
halt 404
delete '/:hostname/?' do |hostname|
host = ::Host.find(:name => hostname).first
if host
services = []
Service.find(:host_id => host.id).sort.each {|x| services << x; x.delete} if host.services.size > 0
host.delete
r = {"result" => "success", "id" => "#{host.id}", "name" => "#{hostname}", "service_count" => "#{services.size}"}
r.to_json
else
halt 404
end
end
end
end
namespace "/s" do
namespace "/s" do
get '/:servicename/:hostname/?' do |servicename, hostname|
hs = host_service(hostname, servicename)
if hs.nil?
halt 404
else
hs.to_json
end
end
get '/:servicename/:hostname/?' do |servicename, hostname|
hs = host_service(hostname, servicename)
if hs.nil?
halt 404
else
hs.to_json
end
end
get '/:servicename/?' do |servicename|
s = services(:name => servicename)
s.map {|x| x.to_hash}
if s.empty?
halt 404
else
s.to_json
end
end
get '/:servicename/?' do |servicename|
s = services(:name => servicename)
s.map {|x| x.to_hash}
if s.empty?
halt 404
else
s.to_json
end
end
get '/?' do
if services.empty?
halt 404
else
services.map {|s| s.to_hash}
services.to_json
end
end
get '/?' do
if services.empty?
halt 404
else
services.map {|s| s.to_hash}
services.to_json
end
end
put '/:servicename/?' do |servicename|
required_params = ["status", "host", "name"]
data = JSON.parse(request.body.read)
if data.keys.sort == required_params.sort
h = ::Host.find(:name => data['host']).first || (raise "Invalid Host")
service = ::Service.find_or_create(:name => servicename, :status => data['status'], :host => h)
if service.valid?
action = service.is_new? ? "create" : "update"
service.save
r = {"action" => action, "result" => "success", "id" => service.id, "host" => h.name, "name" => service.name}
r.to_json
else
raise "#{service.errors}"
end
else
raise "Missing Parameters"
end
end
put '/:servicename/?' do |servicename|
required_params = ["status", "host", "name"]
data = JSON.parse(request.body.read)
if data.keys.sort == required_params.sort
h = Host.find(:name => data['host']).first || (raise "Invalid Host")
service = Service.find_or_create(:name => servicename, :status => data['status'], :host => h)
if service.valid?
action = service.is_new? ? "create" : "update"
service.save
r = {"action" => action, "result" => "success", "id" => service.id, "host" => h.name, "name" => service.name}
delete '/:servicename/:hostname/?' do |servicename, hostname|
host = ::Host.find(:name => hostname).first || (halt 404)
service = ::Service.find(:name => servicename, :host_id => host.id).first || (halt 404)
if host && service
service.delete
r = {"action" => "delete", "result" => "success", "id" => service.id, "host" => host.name, "service" => servicename}
r.to_json
else
raise "#{service.errors}"
end
else
raise "Missing Parameters"
halt 404
end
end
end
delete '/:servicename/:hostname/?' do |servicename, hostname|
host = Host.find(:name => hostname).first || (halt 404)
service = Service.find(:name => servicename, :host_id => host.id).first || (halt 404)
if host && service
service.delete
r = {"action" => "delete", "result" => "success", "id" => service.id, "host" => host.name, "service" => servicename}
r.to_json
else
halt 404
end
end
end
end
namespace "/a" do
namespace "/a" do
get '/:appname/:config/?' do |appname, config|
app = ::Application.find(:name => appname).first
if app.nil?
halt 404
else
c = ::Configuration.find(:name => config, :application_id => app.id).first
c.to_json
end
end
get '/:appname/:config/?' do |appname, config|
app = Application.find(:name => appname).first
if app.nil?
halt 404
else
c = Configuration.find(:name => config, :application_id => app.id).first
c.to_json
end
end
get '/:appname/?' do |appname|
app = ::Application.find(:name => appname).first
if app.nil?
halt 404
else
app.to_json
end
end
get '/:appname/?' do |appname|
app = Application.find(:name => appname).first
if app.nil?
halt 404
else
app.to_json
put '/:appname/?' do |appname|
required_params = ["name"]
data = JSON.parse(request.body.read)
if data.keys.sort == required_params.sort && data['name'] == appname
app = ::Application.find_or_create(:name => appname)
else
raise "Missing Parameters"
end
if app.valid?
action = app.is_new? ? "create" : "update"
app.save
r = {"result" => "success","id" => app.id, "action" => action, "name" => app.name }
r.to_json
else
raise "#{app.errors}"
end
end
end
put '/:appname/?' do |appname|
required_params = ["name"]
data = JSON.parse(request.body.read)
if data.keys.sort == required_params.sort && data['name'] == appname
app = Application.find_or_create(:name => appname)
else
raise "Missing Parameters"
end
if app.valid?
action = app.is_new? ? "create" : "update"
app.save
r = {"result" => "success","id" => app.id, "action" => action, "name" => app.name }
r.to_json
else
raise "#{app.errors}"
delete '/:appname/?' do |appname|
app = ::Application.find(:name => appname).first
if app.nil?
halt 404
else
configurations = []
::Configuration.find(:application_id => app.id).sort.each {|x| configurations << x; x.delete} if app.configurations.size > 0
app.delete
r = {"result" => "success", "action" => "delete", "id" => "#{app.id}", "name" => "#{appname}", "configurations" => "#{configurations.size}"}
r.to_json
end
end
end
delete '/:appname/?' do |appname|
app = Application.find(:name => appname).first
if app.nil?
halt 404
else
configurations = []
Configuration.find(:application_id => app.id).sort.each {|x| configurations << x; x.delete} if app.configurations.size > 0
app.delete
r = {"result" => "success", "action" => "delete", "id" => "#{app.id}", "name" => "#{appname}", "configurations" => "#{configurations.size}"}
r.to_json
get '/?' do
apps = []
::Application.all.sort.each {|a| apps << a.to_hash}
if apps.empty?
halt 404
else
apps.to_json
end
end
end
get '/?' do
apps = []
Application.all.sort.each {|a| apps << a.to_hash}
if apps.empty?
halt 404
else
apps.to_json
end
end
end
namespace '/c' do
namespace '/c' do
# Need to move this out to configuration.
# Maybe bootstrap them from itself?
content_type_mapping = {
:yaml => "text/x-yaml",
:json => "application/json",
:xml => "text/xml",
:string => "text/plain"
}
get '/:appname/:element/?' do |appname, element|
a = Application.find(:name => appname).first
if a.nil?
halt 404
else
c = Configuration.find(:name => element, :application_id => a.id).first
content_type content_type_mapping[c.format.to_sym] if content_type_mapping[c.format.to_sym]
c.body
end
end
# Need to move this out to configuration.
# Maybe bootstrap them from itself?
content_type_mapping = {
:yaml => "text/x-yaml",
:json => "application/json",
:xml => "text/xml",
:string => "text/plain"
}
get '/:appname/?' do |appname|
config = []
a = Application.find(:name => appname).first
if a.nil?
halt 404
else
Configuration.find(:application_id => a.id).sort.each {|c| config << c.to_hash}
config.to_json
end
end
get '/:appname/:element/?' do |appname, element|
a = ::Application.find(:name => appname).first
if a.nil?
halt 404
else
c = ::Configuration.find(:name => element, :application_id => a.id).first
content_type content_type_mapping[c.format.to_sym] if content_type_mapping[c.format.to_sym]
c.body
end
end
get '/?' do
configs = []
Configuration.all.sort.each {|c| configs << c.to_hash}
if configs.empty?
halt 404
else
configs.to_json
end
end
get '/:appname/?' do |appname|
config = []
a = ::Application.find(:name => appname).first
if a.nil?
halt 404
else
::Configuration.find(:application_id => a.id).sort.each {|c| config << c.to_hash}
config.to_json
end
end
put '/:appname/:element?' do |appname, element|
app = Application.find_or_create(:name => appname)
config = Configuration.find_or_create(:name => element, :application_id => app.id)
required_params = ["format", "body"]
data = JSON.parse(request.body.read)
data.keys.sort == required_params.sort ? (config.format = data["format"]; config.body = data["body"]) : (raise "Missing Parameters")
if config.valid?
config.save
action = config.is_new? ? "create" : "update"
dependency_action = app.is_new? ? "created" : "updated"
r = {"result" => "success","id" => "#{config.id}", "action" => action, "dependencies" => dependency_action, "application" => app.name, "item" => config.name}
r.to_json
else
raise "#{config.errors}"
get '/?' do
configs = []
::Configuration.all.sort.each {|c| configs << c.to_hash}
if configs.empty?
halt 404
else
configs.to_json
end
end
end
delete '/:appname/:element?' do |appname, element|
app = Application.find(:name => appname).first
if app
config = Configuration.find(:name=> element, :application_id => app.id).first
if config
config.delete
r = {"result" => "success", "id" => "#{config.id}", "action" => "delete", "application" => "#{app.name}", "item" => "#{element}"}
put '/:appname/:element?' do |appname, element|
app = ::Application.find_or_create(:name => appname)
config = ::Configuration.find_or_create(:name => element, :application_id => app.id)
required_params = ["format", "body"]
data = JSON.parse(request.body.read)
data.keys.sort == required_params.sort ? (config.format = data["format"]; config.body = data["body"]) : (raise "Missing Parameters")
if config.valid?
config.save
action = config.is_new? ? "create" : "update"
dependency_action = app.is_new? ? "created" : "updated"
r = {"result" => "success","id" => "#{config.id}", "action" => action, "dependencies" => dependency_action, "application" => app.name, "item" => config.name}
r.to_json
else
raise "#{config.errors}"
end
end
delete '/:appname/:element?' do |appname, element|
app = ::Application.find(:name => appname).first
if app
config = ::Configuration.find(:name=> element, :application_id => app.id).first
if config
config.delete
r = {"result" => "success", "id" => "#{config.id}", "action" => "delete", "application" => "#{app.name}", "item" => "#{element}"}
r.to_json
else
halt 404
end
else
halt 404
end
else
halt 404
end
end
end
# run! if app_file == $0
end
run! if app_file == $0
end
module Noah
class Application < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
class Application < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
collection :configurations, Configuration
attribute :name
collection :configurations, Configuration
index :name
index :name
def validate
assert_present :name
assert_unique :name
end
def validate
assert_present :name
assert_unique :name
end
def to_hash
arr = []
configurations.sort.each {|c| arr << c.to_hash}
super.merge(:name => name, :updated_at => updated_at, :configurations => arr)
end
def to_hash
arr = []
configurations.sort.each {|c| arr << c.to_hash}
super.merge(:name => name, :updated_at => updated_at, :configurations => arr)
end
def is_new?
self.created_at == self.updated_at
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
find(opts).first.nil? ? (app = create(opts)) : (app = find(opts).first)
if app.valid?
app.save
end
app
rescue Exception => e
e.message
class << self
def find_or_create(opts = {})
begin
find(opts).first.nil? ? (app = create(opts)) : (app = find(opts).first)
if app.valid?
app.save
end
end
app
rescue Exception => e
e.message
end
end
class Applications
def self.all(options = {})
options.empty? ? Application.all.sort : Application.find(options).sort
end
end
end
class Applications
def self.all(options = {})
options.empty? ? Application.all.sort : Application.find(options).sort
end
end
require 'mixlib/cli'
module Noah
class CLI
include Mixlib::CLI
banner "noah (options)"
option :config,
:short => "-c CONFIG",
:long => "--config CONFIG",
:default => "config/config.yml",
:description => "Configuration file with path"
option :log_level,
:short => "-l LEVEL",
:long => "--log-level LEVEL",
:description => "Set the log level (debug, info, warn, error, fatal)",
:default => "info",
:proc => Proc.new { |l| l.to_sym }
option :port,
:short => "-p PORT",
:long => "--port PORT",
:description => "Port number to listen on",
:default => "9292"
option :rack_opts,
:short => "-r RACK_HANDLER",
:long => "--rack RACK_HANDLER",
:description => "Rack Handler to use. i.e. thin, mongrel, webbrick, Jetty (for JRuby)",
:default => "thin"
option :redis_url,
:short => "-u REDIS_URL",
:long => "--url REDIS_URL",
:description => "Ohm-compatibile redis url. i.e. redis://localhost:6379/0",
:default => "redis://lcoalhost:6379/0",
:proc => Proc.new { |u| begin; require 'ohm'; Ohm.connect(:url => u); Ohm.redis.ping; rescue Errno::ECONNREFUSED => e; puts "Unable to connect to Redis. Not starting."; exit 1; end }
option :help,
:short => "-h",
:long => "--help",
:description => "You're looking at it",
:on => :tail,
:boolean => true,
:show_options => true,
:exit => 0
end
end
module Noah
class Config
# attr_accessor :config_file
# attr_accessor :settings
# attr_accessor :log_file
# attr_accessor :log_level
# attr_accessor :mode
# attr_accessor :database_url
#
# @conf ||= "config/config.yml"
# @logfile ||= "logs/noah.log"
# @log_level ||= "debug"
# @mode ||= "development"
# @database_url ||= "redis://localhost:6379/0"
#
# def self.configured?
# @config_file.nil? ? false : true
# end
#
# def self.configure!
# puts "Configuring Noah from: #{@config_file}"
# parse
# end
#
# private
# def parse(conf_file = @congig_file)
# begin
# @settings = YAML.load_file(conf_file)
# rescue Exception => e
# puts "Unable to parse configuration: #{conf_file}"
# puts e.message
# end
# end
# end
def initialize(data = {})
@data = {}
update!(data)
end
def update!(data)
data.each do |k,v|
self[k] = v
end
end
def []=(k,v)
v.class == Hash ? @data[k.to_sym] = Config.new(v) : @data[k.to_sym] = v
end
def configured?
@data.size == 0 ? false : true
end
def method_missing(sym, *args)
if sym.to_s =~ /(.+)=$/
self[$1] = args.first
else
self[sym]
end
end
end
end
module Noah
class Configuration < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :format
attribute :body
attribute :new_record
reference :application, Application
index :name
def validate
assert_present :name
assert_present :format
assert_present :body
assert_unique [:name, :application_id]
end
def to_hash
super.merge(:name => name, :format => format, :body => body, :update_at => updated_at, :application => Application[application_id].name)
end
class Configuration < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :format
attribute :body
attribute :new_record
reference :application, Application
index :name
def validate
assert_present :name
assert_present :format
assert_present :body
assert_unique [:name, :application_id]
end
def is_new?
self.created_at == self.updated_at
end
def to_hash
super.merge(:name => name, :format => format, :body => body, :update_at => updated_at, :application => Application[application_id].name)
end
class << self
def find_or_create(opts={})
begin
if find(opts).first.nil?
conf = create(opts)
else
conf = find(opts).first
end
rescue Exception => e
e.message
end
end
end
def is_new?
self.created_at == self.updated_at
end
class Configurations
def self.all(options = {})
options.empty? ? Configuration.all.sort : Configuration.find(options).sort
class << self
def find_or_create(opts={})
begin
if find(opts).first.nil?
conf = create(opts)
else
conf = find(opts).first
end
rescue Exception => e
e.message
end
end
end
end
end
class Configurations
def self.all(options = {})
options.empty? ? Configuration.all.sort : Configuration.find(options).sort
end
end
require File.join(File.dirname(__FILE__), 'models')
module Noah
module SinatraHelpers
extend(Ohm)
def host(opts = {})
Noah::Models::Host.find(opts).first
Host.find(opts).first
end
def hosts(opts = {})
Noah::Models::Hosts.all(opts)
Hosts.all(opts)
end
def service(opts = {})
......@@ -52,4 +54,4 @@ module Noah
end
end
end
end
module Noah
class Host < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
collection :services, Service
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_unique :name
assert_member :status, ["up","down","pending"]
end
class Host < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
collection :services, Service
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_unique :name
assert_member :status, ["up","down","pending"]
end
def to_hash
arr = []
services.sort.each {|s| arr << s.to_hash}
h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => arr}
super.merge(h)
end
def to_hash
arr = []
services.sort.each {|s| arr << s.to_hash}
h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => arr}
super.merge(h)
end
def is_new?
self.created_at == self.updated_at
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
# exclude requested status from lookup
h = find(opts.reject{|key,value| key == :status}).first
host = h.nil? ? create(opts) : h
host.status = opts[:status]
if host.valid?
host.save
end
host
rescue Exception => e
e.message
class << self
def find_or_create(opts = {})
begin
# exclude requested status from lookup
h = find(opts.reject{|key,value| key == :status}).first
host = h.nil? ? create(opts) : h
host.status = opts[:status]
if host.valid?
host.save
end
end
host
rescue Exception => e
e.message
end
end
class Hosts
def self.all(options = {})
options.empty? ? Host.all.sort : Host.find(options).sort
end
end
end
class Hosts
def self.all(options = {})
options.empty? ? Host.all.sort : Host.find(options).sort
end
end
require 'hosts'
require 'services'
require 'applications'
require 'configurations'
require 'watchers'
require File.join(File.dirname(__FILE__),'hosts')
require File.join(File.dirname(__FILE__),'services')
require File.join(File.dirname(__FILE__),'applications')
require File.join(File.dirname(__FILE__),'configurations')
require File.join(File.dirname(__FILE__),'watchers')
module Noah
class Service < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
reference :host, Host
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_present :host_id
assert_unique [:name, :host_id]
assert_member :status, ["up", "down", "pending"]
end
class Service < Ohm::Model
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
include Ohm::ExtraValidations
attribute :name
attribute :status
reference :host, Host
index :name
index :status
def validate
assert_present :name
assert_present :status
assert_present :host_id
assert_unique [:name, :host_id]
assert_member :status, ["up", "down", "pending"]
end
def to_hash
super.merge(:name => name, :status => status, :updated_at => updated_at, :host => Host[host_id].name)
end
def to_hash
super.merge(:name => name, :status => status, :updated_at => updated_at, :host => Host[host_id].name)
end
def is_new?
self.created_at == self.updated_at
end
def is_new?
self.created_at == self.updated_at
end
class << self
def find_or_create(opts = {})
begin
# convert passed host object to host_id if passed
if opts.has_key?(:host)
opts.merge!({:host_id => opts[:host].id})
opts.reject!{|key, value| key == :host}
end
# exclude requested status from lookup
s = find(opts.reject{|key,value| key == :status}).first
service = s.nil? ? create(opts) : s
service.status = opts[:status]
if service.valid?
service.save
end
service
rescue Exception => e
e.message
class << self
def find_or_create(opts = {})
begin
# convert passed host object to host_id if passed
if opts.has_key?(:host)
opts.merge!({:host_id => opts[:host].id})
opts.reject!{|key, value| key == :host}
end
# exclude requested status from lookup
s = find(opts.reject{|key,value| key == :status}).first
service = s.nil? ? create(opts) : s
service.status = opts[:status]
if service.valid?
service.save
end
end
service
rescue Exception => e
e.message
end
end
class Services
def self.all(options = {})
options.empty? ? Service.all.sort : Service.find(options).sort
end
end
end
class Services
def self.all(options = {})
options.empty? ? Service.all.sort : Service.find(options).sort
end
end
module Noah
class Watcher < Ohm::Model #NYI
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
class Watcher < Ohm::Model #NYI
include Ohm::Typecast
include Ohm::Timestamping
include Ohm::Callbacks
attribute :client
attribute :endpoint
attribute :event
attribute :action
attribute :client
attribute :endpoint
attribute :event
attribute :action
index :client
index :event
index :client
index :event
def validate
assert_present :client, :endpoint, :event, :action
assert_unique [:client, :endpoint, :event, :action]
end
def validate
assert_present :client, :endpoint, :event, :action
assert_unique [:client, :endpoint, :event, :action]
end
end
......@@ -4,13 +4,14 @@ begin
require 'yajl'
rescue LoadError
require 'json'
end
end
ENV['RACK_ENV'] = 'test'
config_file = YAML::load File.new(File.join(File.dirname(__FILE__), '..', 'config','db.yml')).read
Ohm::connect(:url => "redis://#{config_file["test"]["host"]}:#{config_file["test"]["port"]}/#{config_file["test"]["db"]}")
ENV['REDIS_URL'] = 'redis://localhost:6379/3'
Ohm::connect
require File.join(File.dirname(__FILE__), '..', 'lib', 'models')
require File.join(File.dirname(__FILE__), '..', 'noah')
require File.join(File.dirname(__FILE__), '..', 'lib', 'noah')
require File.join(File.dirname(__FILE__), '..', 'lib', 'noah', 'app')
require 'rspec'
require 'rack/test'
......@@ -70,7 +71,7 @@ EOJ
end
def app
NoahApp
Noah::App
end
RSpec::Matchers.define :return_json do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment