servitor 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +105 -0
- data/LICENSE +19 -0
- data/README.md +102 -0
- data/lib/cli/cli.rb +96 -0
- data/lib/configuration/configuration.rb +2 -0
- data/lib/configuration/configuration_resolver.rb +97 -0
- data/lib/configuration/yaml_configuration_provider.rb +28 -0
- data/lib/control/control.rb +0 -0
- data/lib/deployment/bundle_deployer.rb +14 -0
- data/lib/deployment/deployment.rb +2 -0
- data/lib/deployment/envdir_deployer.rb +34 -0
- data/lib/helpers/child_process_helper.rb +41 -0
- data/lib/helpers/helpers.rb +1 -0
- data/lib/infrastructure/infrastructure.rb +16 -0
- data/lib/infrastructure/infrastructure_provisioner.rb +25 -0
- data/lib/infrastructure/infrastructure_requirements.rb +25 -0
- data/lib/provisioners/Vagrantfile.erb +16 -0
- data/lib/provisioners/provisioners.rb +6 -0
- data/lib/provisioners/ssh_key.rb +22 -0
- data/lib/provisioners/vagrant_box.rb +116 -0
- data/lib/provisioners/vagrant_box_provisioner.rb +37 -0
- data/lib/provisioners/vagrant_box_ruby_installer.rb +34 -0
- data/lib/provisioners/vagrantfile.rb +34 -0
- data/lib/provisioners/veewee_box.rb +91 -0
- data/lib/resource/mysql_resource.rb +33 -0
- data/lib/resource/resource.rb +1 -0
- data/lib/service/service.rb +12 -0
- data/lib/service/service_definition/Servicefile.erb +54 -0
- data/lib/service/service_definition/deployment_stages.rb +16 -0
- data/lib/service/service_definition/resource_configuration.rb +14 -0
- data/lib/service/service_definition/service_configuration.rb +19 -0
- data/lib/service/service_definition/service_definition.rb +49 -0
- data/lib/service/service_definition/variable.rb +22 -0
- data/lib/service/service_file_parser.rb +21 -0
- data/lib/service/service_graph/service_graph.rb +58 -0
- data/lib/service/service_graph/service_graph_flattener.rb +34 -0
- data/lib/service/service_graph/service_graph_node.rb +15 -0
- data/lib/service/service_linker.rb +56 -0
- data/lib/service/service_locator.rb +43 -0
- data/lib/servitor.rb +47 -0
- data/servitor.gemspec +18 -0
- data/spec/provisioners/vagrant_basebox_provisioner_spec.rb +63 -0
- data/spec/provisioners/vagrant_box_ruby_provisioner_spec.rb +48 -0
- data/spec/spec_helper.rb +7 -0
- metadata +171 -0
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Servitor
|
2
|
+
class EnvdirDeployer
|
3
|
+
include ChildProcessHelper
|
4
|
+
|
5
|
+
attr_reader :box, :path, :dirname, :variables
|
6
|
+
|
7
|
+
def initialize(box, service_name, path, dirname, variables)
|
8
|
+
@service_name = service_name
|
9
|
+
@box = box
|
10
|
+
@path = path
|
11
|
+
@dirname = dirname
|
12
|
+
@variables = variables
|
13
|
+
end
|
14
|
+
|
15
|
+
def deploy
|
16
|
+
# envdir is part of daemontools
|
17
|
+
box.ssh('which envdir || sudo apt-get install daemontools',
|
18
|
+
:vm_name => @service_name, :ignore_exit_code => true, :capture => true)
|
19
|
+
|
20
|
+
box.ruby(<<-RUBY, :vm_name => @service_name, :sudo => true)
|
21
|
+
require 'fileutils'
|
22
|
+
envdir = File.join(#{path.inspect}, #{dirname.inspect})
|
23
|
+
variables = #{variables.inspect}
|
24
|
+
FileUtils.rm_rf(envdir)
|
25
|
+
FileUtils.mkdir_p(envdir)
|
26
|
+
Dir.chdir(envdir) do
|
27
|
+
variables.each do |name, value|
|
28
|
+
File.open(name.upcase, 'w') {|f| f.write(value.gsub("\n", 0.chr)) } if value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
RUBY
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Servitor
|
2
|
+
module ChildProcessHelper
|
3
|
+
|
4
|
+
def execute_child_process(*args)
|
5
|
+
options = args.pop if args.last.is_a? Hash
|
6
|
+
options ||= {}
|
7
|
+
#puts "Executing: #{args.inspect}"
|
8
|
+
process = ChildProcess.build(*args)
|
9
|
+
if block_given?
|
10
|
+
yield process
|
11
|
+
else
|
12
|
+
process.io.inherit!
|
13
|
+
end
|
14
|
+
process.start
|
15
|
+
exit_code = process.wait
|
16
|
+
unless exit_code == 0 || options[:ignore_exit_code]
|
17
|
+
raise ServitorChildProcessError, "#{args.inspect}: exited with code #{exit_code}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute_child_process_and_capture_output(*args)
|
22
|
+
output = nil
|
23
|
+
Tempfile.open('ChildProcessHelper') do |tempfile|
|
24
|
+
execute_child_process(*args) do |process|
|
25
|
+
process.io.stdout = process.io.stderr = tempfile
|
26
|
+
end
|
27
|
+
tempfile.rewind
|
28
|
+
output = tempfile.read
|
29
|
+
end
|
30
|
+
output
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.included(base)
|
34
|
+
# this can work as a class method too
|
35
|
+
base.extend(ChildProcessHelper)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class ServitorChildProcessError < StandardError; end
|
41
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
servitor_require 'child_process_helper'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Servitor
|
2
|
+
|
3
|
+
class InfrastructureProvisioner
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Provisions an infrastructure that meets the requirements for the given service config.
|
8
|
+
# Returns an infrastructure.
|
9
|
+
def provision(requirements)
|
10
|
+
VagrantBox.define(requirements) do |box|
|
11
|
+
VagrantBoxRubyInstaller.new(requirements).install(box)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def create_box
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Servitor
|
4
|
+
|
5
|
+
class InfrastructureRequirements
|
6
|
+
|
7
|
+
%w(os_name os_version os_arch
|
8
|
+
chef_repo chef_refspec chef_runlist chef_attributes
|
9
|
+
ruby_version).each do |attr|
|
10
|
+
define_method(attr) do |*args|
|
11
|
+
value = args.length > 0 ? args.first : nil
|
12
|
+
attr_sym = "@#{attr}".to_sym
|
13
|
+
instance_variable_set(attr_sym, value) unless value.nil?
|
14
|
+
instance_variable_get(attr_sym)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a hash of the requirements that should be consistent between processes
|
19
|
+
def consistent_hash
|
20
|
+
Zlib.crc32(self.to_yaml, 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Vagrant::Config.run do |config|
|
2
|
+
<% @services.each do |service| %>
|
3
|
+
config.vm.define <%= service.name.to_sym.inspect %> do |service_config|
|
4
|
+
service_config.vm.box = <%= service.box.to_s.inspect %>
|
5
|
+
service_config.vm.network :hostonly, <%= service.ip_address.to_s.inspect %>
|
6
|
+
<% unless service.vm_root.blank? || service.root.blank? %>
|
7
|
+
service_config.vm.share_folder 'v-root', <%= service.vm_root.inspect %>, <%= service.root.inspect %>
|
8
|
+
<% end %>
|
9
|
+
service_config.vm.share_folder 'ssh-keys', '/mnt/ssh', <%= @ssh_dir.inspect %>
|
10
|
+
#service_config.ssh.private_key_path = <%= File.join(@ssh_dir, 'id_rsa').inspect %>
|
11
|
+
<% service.forwarded_ports.each do |from, to| %>
|
12
|
+
service_config.vm.forward_port <%= from.to_i.inspect %>, <%= to.to_i.inspect %>
|
13
|
+
<% end %>
|
14
|
+
end
|
15
|
+
<% end %>
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Servitor
|
2
|
+
class SshKey
|
3
|
+
def initialize(ssh_dir)
|
4
|
+
@ssh_dir = ssh_dir
|
5
|
+
end
|
6
|
+
|
7
|
+
def deploy
|
8
|
+
FileUtils.mkdir_p(@ssh_dir)
|
9
|
+
FileUtils.chown(ENV['USER'], nil, @ssh_dir)
|
10
|
+
home_ssh_dir = File.join(ENV['HOME'], '.ssh')
|
11
|
+
private_key_file, public_key_file = %w(id_rsa id_rsa.pub).map do |key_file|
|
12
|
+
File.join(home_ssh_dir, key_file).tap do |abs_key_file|
|
13
|
+
FileUtils.cp(abs_key_file, File.join(@ssh_dir, File.basename(abs_key_file)))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
FileUtils.chmod(0600, private_key_file)
|
17
|
+
File.open(File.join(@ssh_dir, 'authorized_keys'), 'w') do |f|
|
18
|
+
f.write(File.read(public_key_file))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
|
3
|
+
module Servitor
|
4
|
+
|
5
|
+
class VagrantBox
|
6
|
+
|
7
|
+
include ChildProcessHelper
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def exists?(name)
|
11
|
+
!!self.vagrant.boxes.find(name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def vagrant
|
15
|
+
@vagrant ||= Vagrant::Environment.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(box_name, box_file)
|
19
|
+
execute_child_process('vagrant', 'box', 'add', box_name, box_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def define(requirements)
|
23
|
+
name = box_name_for(requirements)
|
24
|
+
return name if exists?(name)
|
25
|
+
box = VagrantBoxProvisioner.new(requirements).provision
|
26
|
+
yield box
|
27
|
+
box_file = box.package
|
28
|
+
box.destroy
|
29
|
+
self.add(name, box_file)
|
30
|
+
name
|
31
|
+
end
|
32
|
+
|
33
|
+
def box_file_for(name)
|
34
|
+
File.join(Servitor.boxes_root, "#{name}.box")
|
35
|
+
end
|
36
|
+
|
37
|
+
def box_name_for(requirements)
|
38
|
+
"servitor-#{requirements.consistent_hash.to_s(32)}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :name, :path
|
43
|
+
|
44
|
+
def initialize(name, path=nil)
|
45
|
+
@name = name
|
46
|
+
@path = path || File.join(Servitor.boxes_root, @name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def init(base_box)
|
50
|
+
box_dir do
|
51
|
+
execute_child_process('vagrant', 'init', base_box)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def up
|
56
|
+
box_dir do
|
57
|
+
execute_child_process('vagrant', 'up', '--no-provision')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def halt
|
62
|
+
box_dir do
|
63
|
+
execute_child_process('vagrant', 'halt')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def destroy
|
68
|
+
box_dir do
|
69
|
+
execute_child_process('vagrant', 'destroy', '--force')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def package
|
74
|
+
box_dir do
|
75
|
+
box_file = self.class.box_file_for(@name)
|
76
|
+
execute_child_process('vagrant', 'package', '--output', box_file)
|
77
|
+
return box_file
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def ssh(command, options={})
|
82
|
+
box_dir do
|
83
|
+
sudo = options[:sudo] ? 'sudo ' : ''
|
84
|
+
args = ['vagrant', 'ssh', options[:vm_name], '-c', "#{sudo}#{command}"].compact
|
85
|
+
if options[:capture]
|
86
|
+
execute_child_process_and_capture_output(*args)
|
87
|
+
else
|
88
|
+
execute_child_process(*args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def ruby(script, options={})
|
94
|
+
escaped = script.gsub('"', '\"')
|
95
|
+
lines = escaped.split("\n")
|
96
|
+
cmd = "ruby #{lines.map {|l| "-e \"#{l}\""}.join(' ') }"
|
97
|
+
#puts "cmd = "+ cmd
|
98
|
+
ssh(cmd, options)
|
99
|
+
end
|
100
|
+
|
101
|
+
def provision
|
102
|
+
box_dir do
|
103
|
+
execute_child_process('vagrant', 'provision')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def box_dir(&block)
|
110
|
+
FileUtils.mkdir_p(self.path)
|
111
|
+
FileUtils.chdir(self.path, {}, &block)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Servitor
|
2
|
+
|
3
|
+
class VagrantBoxProvisioner
|
4
|
+
attr_reader :requirements
|
5
|
+
|
6
|
+
def initialize(requirements)
|
7
|
+
@requirements = requirements
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
@name ||= "#{@requirements.os_name}_#{@requirements.os_version}".gsub(/[^a-zA-Z0-9\-]/, '-')
|
12
|
+
end
|
13
|
+
|
14
|
+
def provision
|
15
|
+
create_base_box unless VagrantBox.exists?(name)
|
16
|
+
VagrantBox.new(name).tap do |box|
|
17
|
+
box.init(name)
|
18
|
+
box.up
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def create_base_box
|
25
|
+
base_box = VeeweeBox.new(name, @requirements.os_name, @requirements.os_version)
|
26
|
+
base_box.define
|
27
|
+
base_box.build(:nogui => true)
|
28
|
+
base_box.validate
|
29
|
+
base_box.export
|
30
|
+
base_box.up
|
31
|
+
box_file = "#{name}.box"
|
32
|
+
VagrantBox.add(name, box_file)
|
33
|
+
FileUtils.rm box_file
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Servitor
|
2
|
+
|
3
|
+
class VagrantBoxRubyInstaller
|
4
|
+
attr_reader :requirements
|
5
|
+
|
6
|
+
def initialize(requirements)
|
7
|
+
@requirements = requirements
|
8
|
+
end
|
9
|
+
|
10
|
+
def install(box)
|
11
|
+
return if already_installed?(box)
|
12
|
+
box.ssh('which curl || sudo apt-get install curl -y')
|
13
|
+
case @requirements.ruby_version
|
14
|
+
when /jruby/
|
15
|
+
box.ssh('sudo apt-get install g++ openjdk-6-jre-headless -y')
|
16
|
+
when /ironruby/
|
17
|
+
box.ssh('sudo apt-get install mono-2.0-devel -y')
|
18
|
+
else
|
19
|
+
box.ssh('sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion pkg-config -y')
|
20
|
+
end
|
21
|
+
box.ssh('which rvm || curl -L https://get.rvm.io | bash -s stable', :ignore_exit_code => true)
|
22
|
+
box.ssh('which curl || sudo apt-get install curl -y')
|
23
|
+
box.ssh("rvm install #{@requirements.ruby_version}", :ignore_exit_code => true)
|
24
|
+
box.ssh("rvm use #{@requirements.ruby_version} --default")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def already_installed?(box)
|
30
|
+
box.ssh('rvm current', :capture => true, :ignore_exit_code => true) == @requirements.ruby_version
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
class String
|
4
|
+
unless method_defined?(:blank?)
|
5
|
+
def blank?
|
6
|
+
self =~ /^\s*$/
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NilClass
|
12
|
+
unless method_defined?(:blank?)
|
13
|
+
def blank?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Servitor
|
20
|
+
|
21
|
+
class Vagrantfile
|
22
|
+
def initialize(services, ssh_dir)
|
23
|
+
@services = services
|
24
|
+
@ssh_dir = ssh_dir
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate
|
28
|
+
template_path = File.join(File.dirname(__FILE__), 'Vagrantfile.erb')
|
29
|
+
eruby = Erubis::Eruby.load_file(template_path)
|
30
|
+
context = Erubis::Context.new(:services => @services, :ssh_dir => @ssh_dir)
|
31
|
+
eruby.evaluate(context)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|