servitor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,15 @@
|
|
1
|
+
module Servitor
|
2
|
+
|
3
|
+
class ServiceGraphNode
|
4
|
+
|
5
|
+
attr_reader :depends_on_nodes, :depended_on_by_nodes, :service_definition
|
6
|
+
|
7
|
+
def initialize(service_definition)
|
8
|
+
@service_definition = service_definition
|
9
|
+
@depends_on_nodes = []
|
10
|
+
@depended_on_by_nodes = []
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Servitor
|
2
|
+
class ServiceLinker
|
3
|
+
|
4
|
+
attr_reader :service_nodes, :service_box_names
|
5
|
+
|
6
|
+
def initialize(service_nodes, service_box_names)
|
7
|
+
@service_nodes = service_nodes
|
8
|
+
@service_box_names = service_box_names
|
9
|
+
end
|
10
|
+
|
11
|
+
# Transforms the list of service nodes to a list of services. Service nodes
|
12
|
+
# describe the requirements and dependencies of each app, while services describe
|
13
|
+
# the VMs that satisfy those requirements and dependencies.
|
14
|
+
def link(options={})
|
15
|
+
next_ip = (options[:first_ip] || 2).to_i
|
16
|
+
next_port = (options[:first_port] || 3000).to_i
|
17
|
+
@service_nodes.map do |service_node|
|
18
|
+
service = Service.new
|
19
|
+
service.service_node = service_node
|
20
|
+
service.name = service_node.service_definition.name
|
21
|
+
service.box = @service_box_names[service_node]
|
22
|
+
service.ip_address = ip_address(next_ip, options)
|
23
|
+
begin
|
24
|
+
next_ip += 1
|
25
|
+
end while ip_address(next_ip, options) == host_ip(options)
|
26
|
+
service.forwarded_ports = { 80 => next_port }.merge(ports_for(service_node))
|
27
|
+
next_port += 1
|
28
|
+
service.root = service_node.service_definition.service_root
|
29
|
+
service.vm_root = options[:vm_root] || '/mnt/app/current'
|
30
|
+
service
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def ports_for(service_node)
|
37
|
+
ports = {}
|
38
|
+
if service_node.service_definition.configuration.resources.any? {|r| r.options[:type] == 'mysql'}
|
39
|
+
# ports[3306] = 3306
|
40
|
+
end
|
41
|
+
ports
|
42
|
+
end
|
43
|
+
|
44
|
+
def ip_block(options)
|
45
|
+
options[:ip_block] || '192.168.51'
|
46
|
+
end
|
47
|
+
|
48
|
+
def ip_address(next_ip, options)
|
49
|
+
"#{ip_block(options)}.#{next_ip}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def host_ip(options)
|
53
|
+
"#{ip_block(options)}.1"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Servitor
|
2
|
+
|
3
|
+
class ServiceLocator
|
4
|
+
|
5
|
+
FILENAMES = %w(Servicefile .servicefile)
|
6
|
+
DEFAULT_SERVICES_DIR = ENV['SERVITOR_SERVICES_DIR'] || File.join(ENV['HOME'],'git')
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
attr_writer :services_dir
|
11
|
+
|
12
|
+
def services_dir
|
13
|
+
@services_dir || DEFAULT_SERVICES_DIR
|
14
|
+
end
|
15
|
+
|
16
|
+
# Locates the local service or a named service, returning a service config
|
17
|
+
def locate(service_name = nil)
|
18
|
+
if service_name
|
19
|
+
dir = File.join(services_dir, service_name)
|
20
|
+
else
|
21
|
+
dir = Dir.pwd
|
22
|
+
end
|
23
|
+
file = service_file_in_dir(dir)
|
24
|
+
ServiceFileParser.parse(file, dir)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def service_file_in_dir(dir)
|
30
|
+
file_names = FILENAMES + FILENAMES.map { |f| File.join('config', f) }
|
31
|
+
file_names.each do |file_name|
|
32
|
+
service_file_name = File.join(dir, file_name)
|
33
|
+
return service_file_name if File.exists?(service_file_name)
|
34
|
+
end
|
35
|
+
raise "No service file found in #{dir}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/servitor.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module ServitorRequire
|
2
|
+
# for 1.8 compatibility
|
3
|
+
def servitor_require(path)
|
4
|
+
require(File.join(File.dirname(caller[0]), path))
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
extend(ServitorRequire)
|
9
|
+
|
10
|
+
servitor_require 'helpers/helpers'
|
11
|
+
servitor_require 'cli/cli'
|
12
|
+
servitor_require 'configuration/configuration'
|
13
|
+
servitor_require 'control/control'
|
14
|
+
servitor_require 'deployment/deployment'
|
15
|
+
servitor_require 'infrastructure/infrastructure'
|
16
|
+
servitor_require 'provisioners/provisioners'
|
17
|
+
servitor_require 'resource/resource'
|
18
|
+
servitor_require 'service/service'
|
19
|
+
|
20
|
+
module Servitor
|
21
|
+
def self.root
|
22
|
+
@root
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.root=(path)
|
26
|
+
raise ServitorRootException, 'Servitor root has already been set; it can only be set once.' if @root
|
27
|
+
@root = path
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.data_root
|
31
|
+
File.join(Servitor.root, '.servitor')
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.boxes_root
|
35
|
+
File.join(Servitor.data_root, 'boxes')
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.vagrantfile
|
39
|
+
File.join(Servitor.data_root, 'Vagrantfile')
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.ssh_dir
|
43
|
+
File.join(Servitor.data_root, 'ssh')
|
44
|
+
end
|
45
|
+
|
46
|
+
class ServitorRootException < StandardError; end
|
47
|
+
end
|
data/servitor.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'servitor'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2012-11-02'
|
5
|
+
s.summary = "A tool to help compose an SOA from 12-factor apps"
|
6
|
+
s.description = "A tool to help compose an SOA from 12-factor apps"
|
7
|
+
s.authors = ["Harry Wilkinson"]
|
8
|
+
s.email = 'hwilkinson@mdsol.com'
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
11
|
+
s.homepage = 'http://github.com/harryw/servitor'
|
12
|
+
|
13
|
+
s.add_dependency 'veewee', '0.3.0.beta2'
|
14
|
+
s.add_dependency 'childprocess'
|
15
|
+
s.add_dependency 'erubis'
|
16
|
+
s.add_dependency 'mysql2'
|
17
|
+
s.add_development_dependency 'rspec'
|
18
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Servitor::VagrantBaseboxProvisioner do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@requirements = Servitor::InfrastructureRequirements.new
|
7
|
+
@requirements.os_name 'ubuntu'
|
8
|
+
@requirements.os_version '10.04'
|
9
|
+
@requirements.os_arch '64'
|
10
|
+
@provisioner = Servitor::VagrantBaseboxProvisioner.new(@requirements)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#name' do
|
14
|
+
it 'contains the os name and version' do
|
15
|
+
@provisioner.name.should == "#{@requirements.os_name}-#{@requirements.os_version}".gsub(/[^a-zA-Z0-9\-]/, '-')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#provision' do
|
20
|
+
|
21
|
+
# The result of a #provision call is that there is a base box available satisfying the specified requirements.
|
22
|
+
# So, to test #provision we need to build a new box from that base and inspect it.
|
23
|
+
|
24
|
+
before :all do
|
25
|
+
@pwd = Dir.pwd
|
26
|
+
@provisioner.provision
|
27
|
+
@box = Servitor::VagrantBox.new('VagrantBaseBoxProvisionerTest')
|
28
|
+
@tmpdir = File.join(@pwd, 'VagrantBaseBoxProvisionerTest')
|
29
|
+
FileUtils.mkdir_p @tmpdir
|
30
|
+
FileUtils.cd @tmpdir
|
31
|
+
@box.init(@provisioner.name)
|
32
|
+
@box.up
|
33
|
+
end
|
34
|
+
|
35
|
+
after :all do
|
36
|
+
@box.destroy
|
37
|
+
FileUtils.cd @pwd
|
38
|
+
FileUtils.rm_rf @tmpdir
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'has the requested OS' do
|
42
|
+
@box.ssh('lsb_release -si', :capture => true).should =~ Regexp.new(@requirements.os_name, true)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'has the requested OS version' do
|
46
|
+
@box.ssh('lsb_release -sr', :capture => true).should =~ Regexp.new(@requirements.os_version, true)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'has the requested OS architecture' do
|
50
|
+
arch = case @requirements.os_arch
|
51
|
+
when /64/
|
52
|
+
'64'
|
53
|
+
when /32/, /86/
|
54
|
+
'32'
|
55
|
+
else
|
56
|
+
raise "unrecognized architecture: #{@requirements.os_arch}"
|
57
|
+
end
|
58
|
+
@box.ssh("uname -m | sed 's/x86_//;s/i[3-6]86/32/'", :capture => true).should =~ Regexp.new(arch)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Servitor::VagrantBoxRubyProvisioner do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@requirements = Servitor::InfrastructureRequirements.new
|
7
|
+
@requirements.os_name 'ubuntu'
|
8
|
+
@requirements.os_version '10.04'
|
9
|
+
@requirements.os_arch '64'
|
10
|
+
@requirements.ruby_version '1.9.2'
|
11
|
+
@provisioner = Servitor::VagrantBoxRubyProvisioner.new(@requirements)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#name' do
|
15
|
+
it 'contains the ruby version' do
|
16
|
+
@provisioner.name.should == "#{@requirements.os_name}-#{@requirements.os_version}-ruby-#{@requirements.ruby_version}".gsub(/[^a-zA-Z0-9\-]/, '-')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#provision' do
|
21
|
+
|
22
|
+
# The result of a #provision call is that there is a base box available satisfying the specified requirements.
|
23
|
+
# So, to test #provision we need to build a new box from that base and inspect it.
|
24
|
+
|
25
|
+
before :all do
|
26
|
+
@pwd = Dir.pwd
|
27
|
+
@provisioner.provision
|
28
|
+
@box = Servitor::VagrantBox.new('VagrantBoxRubyProvisionerTest')
|
29
|
+
@tmpdir = File.join(@pwd, 'VagrantBoxRubyProvisionerTest')
|
30
|
+
FileUtils.mkdir_p @tmpdir
|
31
|
+
FileUtils.cd @tmpdir
|
32
|
+
@box.init(@provisioner.name)
|
33
|
+
@box.up
|
34
|
+
end
|
35
|
+
|
36
|
+
after :all do
|
37
|
+
@box.destroy
|
38
|
+
FileUtils.cd @pwd
|
39
|
+
FileUtils.rm_rf @tmpdir
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uses the requested ruby version' do
|
43
|
+
@box.ssh('ruby --version', :capture => true).should =~ Regexp.new(@requirements.ruby_version, true)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: servitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Harry Wilkinson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: veewee
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.0.beta2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.0.beta2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: childprocess
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: erubis
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: mysql2
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: A tool to help compose an SOA from 12-factor apps
|
95
|
+
email: hwilkinson@mdsol.com
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- .gitignore
|
101
|
+
- Gemfile
|
102
|
+
- Gemfile.lock
|
103
|
+
- LICENSE
|
104
|
+
- README.md
|
105
|
+
- lib/cli/cli.rb
|
106
|
+
- lib/configuration/configuration.rb
|
107
|
+
- lib/configuration/configuration_resolver.rb
|
108
|
+
- lib/configuration/yaml_configuration_provider.rb
|
109
|
+
- lib/control/control.rb
|
110
|
+
- lib/deployment/bundle_deployer.rb
|
111
|
+
- lib/deployment/deployment.rb
|
112
|
+
- lib/deployment/envdir_deployer.rb
|
113
|
+
- lib/helpers/child_process_helper.rb
|
114
|
+
- lib/helpers/helpers.rb
|
115
|
+
- lib/infrastructure/infrastructure.rb
|
116
|
+
- lib/infrastructure/infrastructure_provisioner.rb
|
117
|
+
- lib/infrastructure/infrastructure_requirements.rb
|
118
|
+
- lib/provisioners/Vagrantfile.erb
|
119
|
+
- lib/provisioners/provisioners.rb
|
120
|
+
- lib/provisioners/ssh_key.rb
|
121
|
+
- lib/provisioners/vagrant_box.rb
|
122
|
+
- lib/provisioners/vagrant_box_provisioner.rb
|
123
|
+
- lib/provisioners/vagrant_box_ruby_installer.rb
|
124
|
+
- lib/provisioners/vagrantfile.rb
|
125
|
+
- lib/provisioners/veewee_box.rb
|
126
|
+
- lib/resource/mysql_resource.rb
|
127
|
+
- lib/resource/resource.rb
|
128
|
+
- lib/service/service.rb
|
129
|
+
- lib/service/service_definition/Servicefile.erb
|
130
|
+
- lib/service/service_definition/deployment_stages.rb
|
131
|
+
- lib/service/service_definition/resource_configuration.rb
|
132
|
+
- lib/service/service_definition/service_configuration.rb
|
133
|
+
- lib/service/service_definition/service_definition.rb
|
134
|
+
- lib/service/service_definition/variable.rb
|
135
|
+
- lib/service/service_file_parser.rb
|
136
|
+
- lib/service/service_graph/service_graph.rb
|
137
|
+
- lib/service/service_graph/service_graph_flattener.rb
|
138
|
+
- lib/service/service_graph/service_graph_node.rb
|
139
|
+
- lib/service/service_linker.rb
|
140
|
+
- lib/service/service_locator.rb
|
141
|
+
- lib/servitor.rb
|
142
|
+
- servitor.gemspec
|
143
|
+
- spec/provisioners/vagrant_basebox_provisioner_spec.rb
|
144
|
+
- spec/provisioners/vagrant_box_ruby_provisioner_spec.rb
|
145
|
+
- spec/spec_helper.rb
|
146
|
+
homepage: http://github.com/harryw/servitor
|
147
|
+
licenses: []
|
148
|
+
post_install_message:
|
149
|
+
rdoc_options: []
|
150
|
+
require_paths:
|
151
|
+
- lib
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
160
|
+
requirements:
|
161
|
+
- - ! '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
requirements: []
|
165
|
+
rubyforge_project:
|
166
|
+
rubygems_version: 1.8.24
|
167
|
+
signing_key:
|
168
|
+
specification_version: 3
|
169
|
+
summary: A tool to help compose an SOA from 12-factor apps
|
170
|
+
test_files: []
|
171
|
+
has_rdoc:
|