vines-services 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README +40 -0
- data/Rakefile +130 -0
- data/bin/vines-services +95 -0
- data/conf/config.rb +25 -0
- data/lib/vines/services/command/init.rb +209 -0
- data/lib/vines/services/command/restart.rb +14 -0
- data/lib/vines/services/command/start.rb +30 -0
- data/lib/vines/services/command/stop.rb +20 -0
- data/lib/vines/services/command/views.rb +26 -0
- data/lib/vines/services/component.rb +26 -0
- data/lib/vines/services/config.rb +105 -0
- data/lib/vines/services/connection.rb +120 -0
- data/lib/vines/services/controller/attributes_controller.rb +19 -0
- data/lib/vines/services/controller/base_controller.rb +99 -0
- data/lib/vines/services/controller/disco_info_controller.rb +61 -0
- data/lib/vines/services/controller/labels_controller.rb +17 -0
- data/lib/vines/services/controller/members_controller.rb +44 -0
- data/lib/vines/services/controller/messages_controller.rb +66 -0
- data/lib/vines/services/controller/probes_controller.rb +45 -0
- data/lib/vines/services/controller/services_controller.rb +81 -0
- data/lib/vines/services/controller/subscriptions_controller.rb +39 -0
- data/lib/vines/services/controller/systems_controller.rb +45 -0
- data/lib/vines/services/controller/transfers_controller.rb +58 -0
- data/lib/vines/services/controller/uploads_controller.rb +62 -0
- data/lib/vines/services/controller/users_controller.rb +127 -0
- data/lib/vines/services/core_ext/blather.rb +46 -0
- data/lib/vines/services/core_ext/couchrest.rb +33 -0
- data/lib/vines/services/indexer.rb +195 -0
- data/lib/vines/services/priority_queue.rb +94 -0
- data/lib/vines/services/roster.rb +70 -0
- data/lib/vines/services/storage/couchdb/fragment.rb +23 -0
- data/lib/vines/services/storage/couchdb/service.rb +170 -0
- data/lib/vines/services/storage/couchdb/system.rb +141 -0
- data/lib/vines/services/storage/couchdb/upload.rb +66 -0
- data/lib/vines/services/storage/couchdb/user.rb +137 -0
- data/lib/vines/services/storage/couchdb/vcard.rb +13 -0
- data/lib/vines/services/storage/couchdb.rb +157 -0
- data/lib/vines/services/storage.rb +33 -0
- data/lib/vines/services/throttle.rb +26 -0
- data/lib/vines/services/version.rb +7 -0
- data/lib/vines/services/vql/compiler.rb +94 -0
- data/lib/vines/services/vql/vql.citrus +115 -0
- data/lib/vines/services/vql/vql.rb +186 -0
- data/lib/vines/services.rb +71 -0
- data/test/config_test.rb +242 -0
- data/test/priority_queue_test.rb +23 -0
- data/test/storage/couchdb_test.rb +30 -0
- data/test/vql/compiler_test.rb +96 -0
- data/test/vql/vql_test.rb +233 -0
- data/web/coffeescripts/api.coffee +51 -0
- data/web/coffeescripts/commands.coffee +18 -0
- data/web/coffeescripts/files.coffee +315 -0
- data/web/coffeescripts/init.coffee +21 -0
- data/web/coffeescripts/services.coffee +356 -0
- data/web/coffeescripts/setup.coffee +503 -0
- data/web/coffeescripts/systems.coffee +371 -0
- data/web/images/default-service.png +0 -0
- data/web/images/linux.png +0 -0
- data/web/images/mac.png +0 -0
- data/web/images/run.png +0 -0
- data/web/images/windows.png +0 -0
- data/web/index.html +17 -0
- data/web/stylesheets/common.css +52 -0
- data/web/stylesheets/files.css +218 -0
- data/web/stylesheets/services.css +181 -0
- data/web/stylesheets/setup.css +117 -0
- data/web/stylesheets/systems.css +142 -0
- metadata +230 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2011 Negative Code
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
== Welcome to Vines Services
|
2
|
+
|
3
|
+
Vines Services are dynamically updated groups of systems based on criteria like
|
4
|
+
hostname, installed software, operating system, etc. Send a command to the
|
5
|
+
service and it runs on every system in the group. Services, files and permissions
|
6
|
+
are managed via the bundled web application.
|
7
|
+
|
8
|
+
Services are defined using VinesQL, a simple query language that finds systems
|
9
|
+
based on their machine attributes. A "Mac OS X Lion" service might be
|
10
|
+
defined as: platform is 'mac_os_x' and platform_version starts with '10.7'.
|
11
|
+
As machines update to Lion, they will join this service automatically and may
|
12
|
+
be managed as one group.
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
16
|
+
1. gem install vines-services
|
17
|
+
2. vines-services init wonderland.lit
|
18
|
+
3. cd wonderland.lit && vines-services start
|
19
|
+
|
20
|
+
== Dependencies
|
21
|
+
|
22
|
+
* bcrypt-ruby >= 3.0.0
|
23
|
+
* blather >= 0.5.4
|
24
|
+
* citrus >= 2.4.0
|
25
|
+
* eventmachine >= 0.12.10
|
26
|
+
* nokogiri >= 1.4.4
|
27
|
+
* sqlite3 >= 1.3.4
|
28
|
+
* ruby >= 1.9.2
|
29
|
+
|
30
|
+
== Ubuntu setup
|
31
|
+
$ sudo apt-get install build-essential ruby1.9.1 ruby1.9.1-dev libxml2-dev libxslt-dev
|
32
|
+
|
33
|
+
== Contact
|
34
|
+
|
35
|
+
* David Graham <david@negativecode.com>
|
36
|
+
* Chris Johnson <chris@negativecode.com>
|
37
|
+
|
38
|
+
== License
|
39
|
+
|
40
|
+
Vines Services is released under the MIT license. Check the LICENSE file for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
require 'nokogiri'
|
6
|
+
require_relative 'lib/vines/services/version'
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = "vines-services"
|
10
|
+
s.version = Vines::Services::VERSION
|
11
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
12
|
+
|
13
|
+
s.summary = "An XMPP component that broadcasts shell commands to many agents."
|
14
|
+
s.description = "Vines Services are dynamically updated groups of systems based
|
15
|
+
on criteria like hostname, installed software, operating system, etc. Send a
|
16
|
+
command to the service and it runs on every system in the group. Services, files
|
17
|
+
and permissions are managed via the bundled web application."
|
18
|
+
|
19
|
+
s.authors = ["David Graham", "Chris Johnson"]
|
20
|
+
s.email = %w[david@negativecode.com chris@negativecode.com]
|
21
|
+
s.homepage = "http://www.getvines.com"
|
22
|
+
|
23
|
+
s.files = FileList['[A-Z]*', '{bin,lib,conf,web}/**/*']
|
24
|
+
s.test_files = FileList["test/**/*"]
|
25
|
+
s.executables = %w[vines-services]
|
26
|
+
s.require_path = "lib"
|
27
|
+
|
28
|
+
s.add_dependency "bcrypt-ruby", "~> 3.0.0"
|
29
|
+
s.add_dependency "blather", "~> 0.5.4"
|
30
|
+
s.add_dependency "citrus", "~> 2.4.0"
|
31
|
+
s.add_dependency "couchrest_model", "~> 1.1.2"
|
32
|
+
s.add_dependency "em-http-request", "~> 0.3.0"
|
33
|
+
s.add_dependency "sqlite3", "~> 1.3.4"
|
34
|
+
s.add_dependency "vines", "~> 0.3"
|
35
|
+
|
36
|
+
s.add_development_dependency "minitest"
|
37
|
+
s.add_development_dependency "rake"
|
38
|
+
|
39
|
+
s.required_ruby_version = '>= 1.9.2'
|
40
|
+
end
|
41
|
+
|
42
|
+
Gem::PackageTask.new(spec) do |pkg|
|
43
|
+
pkg.need_tar = true
|
44
|
+
end
|
45
|
+
|
46
|
+
Rake::TestTask.new(:test) do |test|
|
47
|
+
test.libs << 'test'
|
48
|
+
test.pattern = 'test/**/*_test.rb'
|
49
|
+
test.warning = false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return an array of local, non-library, js includes.
|
53
|
+
def scripts(doc)
|
54
|
+
scripts = []
|
55
|
+
doc.css('script').each do |node|
|
56
|
+
file = node['src'].split('/').last()
|
57
|
+
if node['src'].start_with?('javascripts/')
|
58
|
+
scripts << file
|
59
|
+
end
|
60
|
+
end
|
61
|
+
scripts
|
62
|
+
end
|
63
|
+
|
64
|
+
# Replace script tags with combined and minimized files.
|
65
|
+
def rewrite_js(doc)
|
66
|
+
doc.css('script').each {|node| node.remove }
|
67
|
+
doc.css('head').each do |node|
|
68
|
+
%w[/lib/javascripts/base.js javascripts/app.js].each do |src|
|
69
|
+
script = doc.create_element('script',
|
70
|
+
'type' => 'text/javascript',
|
71
|
+
'src' => src)
|
72
|
+
node.add_child(script)
|
73
|
+
node.add_child(doc.create_text_node("\n"))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def stylesheets(doc)
|
79
|
+
sheets = []
|
80
|
+
doc.css('link[rel="stylesheet"]').each do |node|
|
81
|
+
file = node['href'].split('/').last()
|
82
|
+
if node['href'].start_with?('stylesheets/')
|
83
|
+
sheets << file
|
84
|
+
end
|
85
|
+
end
|
86
|
+
sheets
|
87
|
+
end
|
88
|
+
|
89
|
+
def rewrite_css(doc)
|
90
|
+
doc.css('link[rel="stylesheet"]').each {|node| node.remove }
|
91
|
+
doc.css('head').each do |node|
|
92
|
+
%w[/lib/stylesheets/base.css /lib/stylesheets/login.css stylesheets/app.css].each do |file|
|
93
|
+
link = doc.create_element('link',
|
94
|
+
'rel' => 'stylesheet',
|
95
|
+
'href' => file)
|
96
|
+
node.add_child(link)
|
97
|
+
node.add_child(doc.create_text_node("\n"))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
task :compile do
|
103
|
+
index = 'web/index.html'
|
104
|
+
doc = Nokogiri::HTML(File.read(index))
|
105
|
+
scripts, sheets = scripts(doc), stylesheets(doc)
|
106
|
+
|
107
|
+
rewrite_js(doc)
|
108
|
+
rewrite_css(doc)
|
109
|
+
|
110
|
+
# save index.html before rewriting
|
111
|
+
FileUtils.cp(index, '/tmp/index.html')
|
112
|
+
File.open(index, 'w') {|f| f.write(doc.to_xml(:indent => 2)) }
|
113
|
+
|
114
|
+
js_files = scripts.map {|f| "web/javascripts/#{f}"}.join(' ')
|
115
|
+
css_files = sheets.map {|f| "web/stylesheets/#{f}"}.join(' ')
|
116
|
+
|
117
|
+
sh %{coffee -c -b -o web/javascripts web/coffeescripts/*.coffee}
|
118
|
+
sh %{cat #{js_files} | uglifyjs -nc > web/javascripts/app.js}
|
119
|
+
|
120
|
+
sh %{cat #{css_files} > web/stylesheets/app.css}
|
121
|
+
end
|
122
|
+
|
123
|
+
task :cleanup do
|
124
|
+
# move index.html back into place after gem packaging
|
125
|
+
FileUtils.cp('/tmp/index.html', 'web/index.html')
|
126
|
+
File.delete('/tmp/index.html')
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
task :default => [:clobber, :test, :compile, :gem, :cleanup]
|
data/bin/vines-services
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'vines/services'
|
6
|
+
|
7
|
+
COMMANDS = %w[start stop restart init views]
|
8
|
+
|
9
|
+
def parse(args)
|
10
|
+
options = {}
|
11
|
+
parser = OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: vines-services [options] #{COMMANDS.join('|')}"
|
13
|
+
|
14
|
+
opts.separator ""
|
15
|
+
opts.separator "Daemon options:"
|
16
|
+
|
17
|
+
opts.on('-d', '--daemonize', 'Run daemonized in the background') do |daemonize|
|
18
|
+
options[:daemonize] = daemonize
|
19
|
+
end
|
20
|
+
|
21
|
+
options[:log] = 'log/vines-services.log'
|
22
|
+
opts.on('-l', '--log FILE', 'File to redirect output (default: log/vines-services.log)') do |log|
|
23
|
+
options[:log] = log
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:pid] = 'pid/vines-services.pid'
|
27
|
+
opts.on('-P', '--pid FILE', 'File to store PID (default: pid/vines-services.pid)') do |pid|
|
28
|
+
options[:pid] = pid
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.separator ""
|
32
|
+
opts.separator "Common options:"
|
33
|
+
|
34
|
+
opts.on('-h', '--help', 'Show this message') do |help|
|
35
|
+
options[:help] = help
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on('-v', '--version', 'Show version') do |version|
|
39
|
+
options[:version] = version
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
begin
|
44
|
+
parser.parse!(args)
|
45
|
+
rescue
|
46
|
+
puts parser
|
47
|
+
exit(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
if options[:version]
|
51
|
+
puts Vines::Services::VERSION
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
|
55
|
+
if options[:help]
|
56
|
+
puts parser
|
57
|
+
exit
|
58
|
+
end
|
59
|
+
|
60
|
+
command = args.shift
|
61
|
+
unless COMMANDS.include?(command)
|
62
|
+
puts parser
|
63
|
+
exit(1)
|
64
|
+
end
|
65
|
+
|
66
|
+
options.tap do |opts|
|
67
|
+
opts[:args] = args
|
68
|
+
opts[:command] = command
|
69
|
+
opts[:config] = File.expand_path('conf/config.rb')
|
70
|
+
opts[:pid] = File.expand_path(opts[:pid])
|
71
|
+
opts[:log] = File.expand_path(opts[:log])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def check_config(opts)
|
76
|
+
return if %w[init].include?(opts[:command])
|
77
|
+
unless File.exists?(opts[:config])
|
78
|
+
puts "No config file found at #{opts[:config]}"
|
79
|
+
exit(1)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
VINES_ROOT = Dir.pwd
|
84
|
+
opts = parse(ARGV)
|
85
|
+
check_config(opts)
|
86
|
+
command = Vines::Services::Command.const_get(opts[:command].capitalize).new
|
87
|
+
begin
|
88
|
+
command.run(opts)
|
89
|
+
rescue SystemExit
|
90
|
+
# do nothing
|
91
|
+
rescue Exception => e
|
92
|
+
puts e.message
|
93
|
+
puts e.backtrace
|
94
|
+
exit(1)
|
95
|
+
end
|
data/conf/config.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# This is the Vines Services configuration file. Restart the service with
|
4
|
+
# 'vines-services restart' after updating this file.
|
5
|
+
|
6
|
+
Vines::Services::Config.configure do
|
7
|
+
# Set the logging level to debug, info, warn, error, or fatal. The debug
|
8
|
+
# level logs all XML sent and received by the server.
|
9
|
+
log :info
|
10
|
+
|
11
|
+
host 'vines.wonderland.lit' do
|
12
|
+
upstream 'localhost', 5347, 'secr3t'
|
13
|
+
uploads 'data/upload'
|
14
|
+
|
15
|
+
storage 'couchdb' do
|
16
|
+
host 'localhost'
|
17
|
+
port 5984
|
18
|
+
database 'xmpp'
|
19
|
+
tls false
|
20
|
+
username ''
|
21
|
+
password ''
|
22
|
+
index_dir 'data/index'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
module Services
|
5
|
+
module Command
|
6
|
+
class Init
|
7
|
+
def run(opts)
|
8
|
+
raise 'vines-services init [domain]' unless opts[:args].size == 1
|
9
|
+
@domain = opts[:args].first.dup
|
10
|
+
dir = File.expand_path(@domain)
|
11
|
+
@component_password = Kit.generate_password
|
12
|
+
create_directories
|
13
|
+
initialize_server
|
14
|
+
initialize_component
|
15
|
+
initialize_agent
|
16
|
+
puts "Initialized service, agent, and server directories: #{@domain}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def initialize_server
|
22
|
+
Dir.chdir(File.join(@domain, "server"))
|
23
|
+
`vines init #{@domain}`
|
24
|
+
configure_database
|
25
|
+
FileUtils.mv Dir.glob("#{@domain}/*"), "./"
|
26
|
+
FileUtils.remove_dir(@domain)
|
27
|
+
`vines start -d`
|
28
|
+
FileUtils.cp_r(File.expand_path("../../../../../web/index.html", __FILE__), File.join("web", "index.html"))
|
29
|
+
FileUtils.cp_r(File.expand_path("../../../../../web/javascripts", __FILE__), File.join("web", "javascripts"))
|
30
|
+
FileUtils.cp_r(File.expand_path("../../../../../web/stylesheets", __FILE__), File.join("web", "stylesheets"))
|
31
|
+
FileUtils.cp_r(File.expand_path("../../../../../web/images", __FILE__), File.join("web", "images"))
|
32
|
+
FileUtils.cp_r(File.expand_path("../../../../../web/coffeescripts", __FILE__), File.join("web", "coffeescripts"))
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_agent
|
36
|
+
Dir.chdir("../agent/")
|
37
|
+
`vines-agent init #{@domain}`
|
38
|
+
FileUtils.cp("../server/conf/certs/#{@domain}.crt", File.join("#{@domain}", "conf", "certs"))
|
39
|
+
agent_password = Kit.generate_password
|
40
|
+
jid = Vines::JID.new(fqdn, @domain).bare
|
41
|
+
id = "user:#{jid}"
|
42
|
+
Fiber.new do
|
43
|
+
user = Vines::Services::CouchModels::User.new(id: id)
|
44
|
+
user.name = jid
|
45
|
+
user.system = true
|
46
|
+
user.password = agent_password
|
47
|
+
if user.valid?
|
48
|
+
user.save
|
49
|
+
log.debug("Saving user: #{user}")
|
50
|
+
end
|
51
|
+
end.resume
|
52
|
+
update_agent_config(File.join("#{@domain}", "conf", "config.rb"), agent_password)
|
53
|
+
FileUtils.mv Dir.glob("#{@domain}/*"), "./"
|
54
|
+
FileUtils.remove_dir(@domain)
|
55
|
+
`vines-agent start -d`
|
56
|
+
end
|
57
|
+
|
58
|
+
# Coordinate all the configuration required for the service
|
59
|
+
def initialize_component
|
60
|
+
Dir.chdir("../services/")
|
61
|
+
%w[conf].each do |sub|
|
62
|
+
FileUtils.cp_r(File.expand_path("../../../../../#{sub}", __FILE__), File.join("."))
|
63
|
+
end
|
64
|
+
log, pid = %w[log pid data data/index].map do |sub|
|
65
|
+
File.join(sub).tap {|subdir| Dir.mkdir(subdir) }
|
66
|
+
end
|
67
|
+
update_config(File.join("conf", "config.rb"))
|
68
|
+
`vines-services start -d`
|
69
|
+
end
|
70
|
+
|
71
|
+
#create all the directories for the server, agent, and service
|
72
|
+
def create_directories
|
73
|
+
Dir.mkdir(@domain)
|
74
|
+
%w[server services agent].each do |sub|
|
75
|
+
Dir.mkdir(File.join(@domain, sub))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_db(host, port, db)
|
80
|
+
url = "http://#{host}:#{port}/#{db}"
|
81
|
+
begin
|
82
|
+
RestClient.head(url)
|
83
|
+
rescue RestClient::ResourceNotFound
|
84
|
+
RestClient.put(url, nil)
|
85
|
+
end
|
86
|
+
true
|
87
|
+
rescue
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
# This will attempt to create a new couch database. If one exists
|
92
|
+
# by the name generated, it will not be deleted. This will loop until
|
93
|
+
# it gets a valid couch db address and port
|
94
|
+
def configure_database
|
95
|
+
server, port = "127.0.0.1", 5984
|
96
|
+
db_name = @domain.gsub(".", "_").downcase()
|
97
|
+
until create_db(server, port, db_name)
|
98
|
+
puts "Unable to connect."
|
99
|
+
$stdout.write('CouchDB Server: ')
|
100
|
+
server = $stdin.gets.chomp
|
101
|
+
$stdout.write('CouchDB Port: ')
|
102
|
+
port = $stdin.gets.chomp
|
103
|
+
end
|
104
|
+
@couch_server = server
|
105
|
+
@couch_port = port
|
106
|
+
@couch_db = db_name
|
107
|
+
update_config(File.join(@domain, "conf", "config.rb"))
|
108
|
+
@storage = Vines::Services::Storage::CouchDB.new do
|
109
|
+
host server
|
110
|
+
port port
|
111
|
+
database db_name
|
112
|
+
index_dir '.'
|
113
|
+
end
|
114
|
+
create_user
|
115
|
+
end
|
116
|
+
|
117
|
+
#Create a new vines user object in the couch database
|
118
|
+
def create_user
|
119
|
+
jid, password = nil, nil
|
120
|
+
until jid
|
121
|
+
$stdout.write('JID: ')
|
122
|
+
if node = $stdin.gets.chomp.split('@').first
|
123
|
+
jid = Vines::JID.new(node, @domain) rescue nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
until password
|
128
|
+
$stdout.write('Password: ')
|
129
|
+
`stty -echo`
|
130
|
+
password = $stdin.gets.chomp
|
131
|
+
password = nil if password.empty?
|
132
|
+
`stty echo`
|
133
|
+
end
|
134
|
+
puts "\nCreated #{jid}"
|
135
|
+
|
136
|
+
id = "user:#{jid}"
|
137
|
+
Fiber.new do
|
138
|
+
user = Vines::Services::CouchModels::User.new(id: id)
|
139
|
+
user.name = jid
|
140
|
+
user.password = password
|
141
|
+
if user.valid?
|
142
|
+
user.save
|
143
|
+
log.debug("\nSaving user: #{user}")
|
144
|
+
end
|
145
|
+
end.resume
|
146
|
+
end
|
147
|
+
|
148
|
+
# Set the agents password to the one we generated in this initialization
|
149
|
+
def update_agent_config(config, password)
|
150
|
+
text = File.read(config)
|
151
|
+
File.open(config, 'w') do |f|
|
152
|
+
f.write(text.gsub(/password.*/, "password '#{password}'"))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Return the fully qualified domain name for this machine. This is used
|
157
|
+
# to determine the agent's JID.
|
158
|
+
def fqdn
|
159
|
+
require 'ohai'
|
160
|
+
system = Ohai::System.new
|
161
|
+
system.require_plugin('os')
|
162
|
+
system.require_plugin('hostname')
|
163
|
+
system.fqdn.downcase
|
164
|
+
end
|
165
|
+
|
166
|
+
# Change the config file to contain the values we generated or validated.
|
167
|
+
def update_config(config)
|
168
|
+
# FIXME vines.local
|
169
|
+
orig_config = """
|
170
|
+
host 'vines.local' do
|
171
|
+
cross_domain_messages false
|
172
|
+
private_storage false
|
173
|
+
storage 'fs' do
|
174
|
+
dir 'data/users'
|
175
|
+
end
|
176
|
+
# components 'tea' => 'secr3t',
|
177
|
+
# 'cake' => 'passw0rd'
|
178
|
+
end"""
|
179
|
+
new_config = """
|
180
|
+
host '#{@domain}' do
|
181
|
+
cross_domain_messages false
|
182
|
+
private_storage true
|
183
|
+
storage 'couchdb' do
|
184
|
+
host '#{@couch_server}'
|
185
|
+
port #{@couch_port}
|
186
|
+
database '#{@couch_db}'
|
187
|
+
tls false
|
188
|
+
username ''
|
189
|
+
password ''
|
190
|
+
end
|
191
|
+
components 'vines' => '#{@component_password}'
|
192
|
+
end"""
|
193
|
+
text = File.read(config)
|
194
|
+
text = text.gsub(orig_config, new_config)
|
195
|
+
text = text.gsub("host 'vines.wonderland.lit'", "host 'vines.#{@domain}'")
|
196
|
+
text = text.gsub("secr3t", "#{@component_password}")
|
197
|
+
text = text.gsub("host 'localhost'", "host '#{@couch_server}'")
|
198
|
+
text = text.gsub("port 5984", "port #{@couch_port}")
|
199
|
+
text = text.gsub("database 'xmpp'", "database '#{@couch_db}'")
|
200
|
+
File.open(config, 'w') do |f|
|
201
|
+
f.write(text)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
module Services
|
5
|
+
module Command
|
6
|
+
class Start
|
7
|
+
def run(opts)
|
8
|
+
raise 'vines-services [--pid FILE] start' unless opts[:args].size == 0
|
9
|
+
require opts[:config]
|
10
|
+
component = Vines::Services::Component.new(Config.instance)
|
11
|
+
daemonize(opts) if opts[:daemonize]
|
12
|
+
component.start
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def daemonize(opts)
|
18
|
+
daemon = Vines::Daemon.new(:pid => opts[:pid], :stdout => opts[:log],
|
19
|
+
:stderr => opts[:log])
|
20
|
+
if daemon.running?
|
21
|
+
raise "The vines service is running as process #{daemon.pid}"
|
22
|
+
else
|
23
|
+
puts "The vines service has started"
|
24
|
+
daemon.start
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
module Services
|
5
|
+
module Command
|
6
|
+
class Stop
|
7
|
+
def run(opts)
|
8
|
+
raise 'vines-services [--pid FILE] stop' unless opts[:args].size == 0
|
9
|
+
daemon = Vines::Daemon.new(:pid => opts[:pid])
|
10
|
+
if daemon.running?
|
11
|
+
daemon.stop
|
12
|
+
puts 'The vines service has been shutdown'
|
13
|
+
else
|
14
|
+
puts 'The vines service is not running'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
module Services
|
5
|
+
module Command
|
6
|
+
class Views
|
7
|
+
def run(opts)
|
8
|
+
raise 'vines-services views <domain>' unless opts[:args].size == 1
|
9
|
+
require opts[:config]
|
10
|
+
domain = opts[:args].first
|
11
|
+
unless host = Config.instance.vhosts[domain]
|
12
|
+
raise "#{domain} virtual host not found in conf/config.rb"
|
13
|
+
end
|
14
|
+
unless host.storage.respond_to?(:create_views)
|
15
|
+
raise "CouchDB storage not configured for #{domain} virtual host"
|
16
|
+
end
|
17
|
+
begin
|
18
|
+
host.storage.create_views
|
19
|
+
rescue Exception => e
|
20
|
+
raise "View creation failed: #{e.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
module Services
|
5
|
+
# The main starting point for the Vines Services component process. Starts
|
6
|
+
# the EventMachine processing loop and registers the component with the
|
7
|
+
# configured upstream servers.
|
8
|
+
class Component
|
9
|
+
include Vines::Log
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
log.info('Vines component started')
|
17
|
+
at_exit { log.fatal('Vines component stopped') }
|
18
|
+
EM.epoll
|
19
|
+
EM.kqueue
|
20
|
+
EM.run do
|
21
|
+
@config.hosts.each {|host| host.start }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|