conjure 0.2.10 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.md +8 -0
- data/README.md +35 -76
- data/lib/conjure.rb +1 -12
- data/lib/conjure/delayed_job.rb +39 -0
- data/lib/conjure/digital_ocean/droplet.rb +5 -2
- data/lib/conjure/docker/host.rb +75 -0
- data/lib/conjure/docker/template.rb +71 -0
- data/lib/conjure/instance.rb +31 -76
- data/lib/conjure/passenger.rb +123 -0
- data/lib/conjure/postgres.rb +67 -0
- data/lib/conjure/rails_application.rb +32 -0
- data/lib/conjure/server.rb +41 -0
- data/lib/conjure/swap.rb +28 -0
- data/lib/conjure/{provision/templates → templates}/application-no-ssl.conf.erb +2 -1
- data/lib/conjure/{provision/templates → templates}/application-ssl.conf.erb +2 -1
- data/lib/conjure/version.rb +1 -1
- metadata +12 -41
- data/lib/conjure/application.rb +0 -35
- data/lib/conjure/command.rb +0 -74
- data/lib/conjure/command_target.rb +0 -25
- data/lib/conjure/config.rb +0 -44
- data/lib/conjure/data_set.rb +0 -7
- data/lib/conjure/identity.rb +0 -25
- data/lib/conjure/log.rb +0 -26
- data/lib/conjure/provider.rb +0 -26
- data/lib/conjure/provision.rb +0 -1
- data/lib/conjure/provision/docker/host.rb +0 -32
- data/lib/conjure/provision/docker/image.rb +0 -55
- data/lib/conjure/provision/docker/template.rb +0 -55
- data/lib/conjure/provision/instance.rb +0 -52
- data/lib/conjure/provision/local_docker.rb +0 -16
- data/lib/conjure/provision/passenger.rb +0 -111
- data/lib/conjure/provision/postgres.rb +0 -70
- data/lib/conjure/provision/server.rb +0 -78
- data/lib/conjure/service/cloud_server.rb +0 -112
- data/lib/conjure/service/database.rb +0 -25
- data/lib/conjure/service/database/mysql.rb +0 -69
- data/lib/conjure/service/database/postgres.rb +0 -77
- data/lib/conjure/service/digital_ocean_account.rb +0 -31
- data/lib/conjure/service/docker_host.rb +0 -259
- data/lib/conjure/service/docker_shell.rb +0 -46
- data/lib/conjure/service/forwarded_shell.rb +0 -25
- data/lib/conjure/service/rails_codebase.rb +0 -67
- data/lib/conjure/service/rails_console.rb +0 -10
- data/lib/conjure/service/rails_log_view.rb +0 -14
- data/lib/conjure/service/rails_server.rb +0 -91
- data/lib/conjure/service/rake_task.rb +0 -11
- data/lib/conjure/service/remote_file_set.rb +0 -24
- data/lib/conjure/service/remote_shell.rb +0 -73
- data/lib/conjure/service/repository_link.rb +0 -52
- data/lib/conjure/service/volume.rb +0 -28
- data/lib/conjure/target.rb +0 -19
- data/lib/conjure/view/application_view.rb +0 -42
- data/lib/conjure/view/table_view.rb +0 -38
@@ -1,25 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
class CommandTarget
|
3
|
-
def initialize(options = {})
|
4
|
-
@origin = options[:origin]
|
5
|
-
@branch = options[:branch] || "master"
|
6
|
-
@rails_env = options[:rails_env] || "production"
|
7
|
-
end
|
8
|
-
|
9
|
-
def application
|
10
|
-
@application ||= Application.find(:path => Dir.pwd, :origin => @origin)
|
11
|
-
end
|
12
|
-
|
13
|
-
def existing_instance
|
14
|
-
@existing_instance ||= application.instances.first
|
15
|
-
end
|
16
|
-
|
17
|
-
def new_instance
|
18
|
-
@new_instance ||= Instance.new(
|
19
|
-
:origin => application.origin,
|
20
|
-
:branch => @branch,
|
21
|
-
:rails_environment => @rails_env,
|
22
|
-
)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/conjure/config.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
class Config
|
3
|
-
def self.load(root_path)
|
4
|
-
require "ostruct"
|
5
|
-
config_path = File.join root_path, "config", "conjure.yml"
|
6
|
-
if File.exists? config_path
|
7
|
-
data = YAML.load_file config_path
|
8
|
-
data["config_path"] = File.dirname config_path
|
9
|
-
else
|
10
|
-
data = {}
|
11
|
-
end
|
12
|
-
new data
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(options)
|
16
|
-
@options = options
|
17
|
-
find_default_keys unless @options["private_key"]
|
18
|
-
end
|
19
|
-
|
20
|
-
def method_missing(name)
|
21
|
-
@options[name.to_s]
|
22
|
-
end
|
23
|
-
|
24
|
-
def file_contents(name)
|
25
|
-
name = @options[name.to_s] if name.is_a? Symbol
|
26
|
-
name = File.join(@options["config_path"], name) unless name[0] == "/"
|
27
|
-
File.open name, "rb", &:read
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def find_default_keys
|
33
|
-
private_key_paths = ["~/.ssh/id_rsa", "~/.ssh/id_dsa", "~/.ssh/identity"]
|
34
|
-
private_key_paths.each do |path|
|
35
|
-
path = File.expand_path(path)
|
36
|
-
if File.exists?(path) and File.exists?("#{path}.pub")
|
37
|
-
@options["private_key_file"] = path
|
38
|
-
@options["public_key_file"] = "#{path}.pub"
|
39
|
-
return
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/lib/conjure/data_set.rb
DELETED
data/lib/conjure/identity.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
class Identity
|
3
|
-
require "digest/md5"
|
4
|
-
|
5
|
-
def initialize(config)
|
6
|
-
@config = config
|
7
|
-
end
|
8
|
-
|
9
|
-
def private_key_path
|
10
|
-
Pathname.new(@config.config_path).join @config.private_key_file
|
11
|
-
end
|
12
|
-
|
13
|
-
def public_key_path
|
14
|
-
Pathname.new(@config.config_path).join @config.public_key_file
|
15
|
-
end
|
16
|
-
|
17
|
-
def public_key_data
|
18
|
-
File.open(public_key_path, "rb") { |file| file.read }
|
19
|
-
end
|
20
|
-
|
21
|
-
def unique_identifier
|
22
|
-
"conjure_#{Digest::MD5.hexdigest(public_key_data)[0..7]}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/conjure/log.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
class Log
|
3
|
-
class << self
|
4
|
-
attr_accessor :level
|
5
|
-
attr_accessor :capture
|
6
|
-
attr_reader :history
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.info(message)
|
10
|
-
if @capture
|
11
|
-
@history ||= ""
|
12
|
-
@history << "#{message}\n"
|
13
|
-
else
|
14
|
-
puts message
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.debug(message)
|
19
|
-
info message if @level == :debug
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.clear
|
23
|
-
@history = ""
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/conjure/provider.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
module Provider
|
3
|
-
def self.included(base)
|
4
|
-
base.extend ClassMethods
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.all(service_type)
|
8
|
-
providers(service_type).map{|block| block.call}.flatten.compact
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.register_provider(service_type, &block)
|
12
|
-
providers(service_type) << block
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.providers(service_type)
|
16
|
-
@providers ||= {}
|
17
|
-
@providers[service_type] ||= []
|
18
|
-
end
|
19
|
-
|
20
|
-
module ClassMethods
|
21
|
-
def provides(service_type, &block)
|
22
|
-
Conjure::Provider.register_provider(service_type, &block)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/conjure/provision.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require "conjure/provision/instance"
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
module Provision
|
3
|
-
module Docker
|
4
|
-
class Host
|
5
|
-
def initialize(platform)
|
6
|
-
@platform = platform
|
7
|
-
end
|
8
|
-
|
9
|
-
def built_image_name(dockerfile_directory)
|
10
|
-
result = @platform.with_directory(dockerfile_directory) do |remote_dir|
|
11
|
-
@platform.run "docker build #{remote_dir}"
|
12
|
-
end
|
13
|
-
if match = result.match(/Successfully built ([0-9a-z]+)/)
|
14
|
-
match[1]
|
15
|
-
else
|
16
|
-
raise "Failed to build Docker image, output was #{result}"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def started_container_id(image_name, daemon_command, run_options = nil)
|
21
|
-
all_options = "#{run_options.to_s} #{image_name} #{daemon_command}"
|
22
|
-
@platform.run("docker run #{all_options}").strip
|
23
|
-
end
|
24
|
-
|
25
|
-
def container_ip_address(container_id)
|
26
|
-
format = "{{ .NetworkSettings.IPAddress }}"
|
27
|
-
@platform.run("docker inspect --format '#{format}' #{container_id}").strip
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
module Provision
|
3
|
-
module Docker
|
4
|
-
class Image
|
5
|
-
attr_reader :image_name
|
6
|
-
|
7
|
-
def initialize(docker_host, image_name)
|
8
|
-
@docker_host = docker_host
|
9
|
-
@name = image_name
|
10
|
-
end
|
11
|
-
|
12
|
-
def start_volume(options = {})
|
13
|
-
@docker_host.started_container_id @name, "/bin/true", daemon_options(options)
|
14
|
-
end
|
15
|
-
|
16
|
-
def start_daemon(command, options = {})
|
17
|
-
container_id = @docker_host.started_container_id @name, command, daemon_options(options)
|
18
|
-
sleep 2
|
19
|
-
ip_address = @docker_host.container_ip_address container_id
|
20
|
-
raise "Container failed to start" unless ip_address.present?
|
21
|
-
ip_address
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def volume_options(options)
|
27
|
-
"-d " + run_options(options)
|
28
|
-
end
|
29
|
-
|
30
|
-
def daemon_options(options)
|
31
|
-
"-d --restart=always " + run_options(options)
|
32
|
-
end
|
33
|
-
|
34
|
-
def run_options(options)
|
35
|
-
[
|
36
|
-
mapped_options("--link", options[:linked_containers]),
|
37
|
-
("--name #{options[:name]}" if options[:name]),
|
38
|
-
mapped_options("-p", options[:ports]),
|
39
|
-
listed_options("--volumes-from", options[:volume_containers]),
|
40
|
-
].flatten.compact.join(" ")
|
41
|
-
end
|
42
|
-
|
43
|
-
def listed_options(command, values)
|
44
|
-
values ||= []
|
45
|
-
values.map { |v| "#{command} #{v}" }
|
46
|
-
end
|
47
|
-
|
48
|
-
def mapped_options(command, values)
|
49
|
-
values ||= {}
|
50
|
-
values.map { |from, to| "#{command} #{from}:#{to}" }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require "conjure/provision/docker/host"
|
2
|
-
require "conjure/provision/docker/image"
|
3
|
-
require "tmpdir"
|
4
|
-
|
5
|
-
module Conjure
|
6
|
-
module Provision
|
7
|
-
module Docker
|
8
|
-
class Template
|
9
|
-
def initialize(base_image_name)
|
10
|
-
@commands = ["FROM #{base_image_name}"]
|
11
|
-
@file_data = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def add_file(filename, remote_name)
|
15
|
-
add_file_data File.read(filename), remote_name
|
16
|
-
end
|
17
|
-
|
18
|
-
def add_file_data(data, remote_name)
|
19
|
-
local_name = "file#{@file_data.length+1}"
|
20
|
-
@file_data[local_name] = data
|
21
|
-
@commands << "ADD #{local_name} #{remote_name}"
|
22
|
-
end
|
23
|
-
|
24
|
-
def run(command)
|
25
|
-
@commands << "RUN #{command}"
|
26
|
-
end
|
27
|
-
|
28
|
-
def volume(name)
|
29
|
-
@commands << "VOLUME #{name}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def source
|
33
|
-
@commands.join "\n"
|
34
|
-
end
|
35
|
-
|
36
|
-
def prepare_build_directory(&block)
|
37
|
-
Dir.mktmpdir do |dir|
|
38
|
-
@file_data.merge("Dockerfile" => source).each do |filename, data|
|
39
|
-
File.write "#{dir}/#{filename}", data
|
40
|
-
end
|
41
|
-
yield dir
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def build(platform)
|
46
|
-
docker_host = Host.new(platform)
|
47
|
-
image_name = prepare_build_directory do |dir|
|
48
|
-
docker_host.built_image_name dir
|
49
|
-
end
|
50
|
-
Image.new docker_host, image_name
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require "conjure/provision/docker/template"
|
2
|
-
require "conjure/provision/local_docker"
|
3
|
-
require "conjure/provision/server"
|
4
|
-
require "conjure/provision/postgres"
|
5
|
-
require "conjure/provision/passenger"
|
6
|
-
require "yaml"
|
7
|
-
|
8
|
-
module Conjure
|
9
|
-
module Provision
|
10
|
-
class Instance
|
11
|
-
def initialize(app_name, rails_env, options = {})
|
12
|
-
@app_name = app_name
|
13
|
-
@rails_env = rails_env
|
14
|
-
@options = options
|
15
|
-
end
|
16
|
-
|
17
|
-
def provision(options = {})
|
18
|
-
if options[:local]
|
19
|
-
platform = LocalDocker.new
|
20
|
-
else
|
21
|
-
platform = Server.create "#{@app_name}-#{@rails_env}", @options
|
22
|
-
end
|
23
|
-
|
24
|
-
database = Postgres.new(platform)
|
25
|
-
database.start
|
26
|
-
|
27
|
-
webserver = Passenger.new(platform, database, @rails_env, @options)
|
28
|
-
webserver.start
|
29
|
-
passenger_ip = webserver.ip_address
|
30
|
-
|
31
|
-
port = platform.ip_address ? "2222" : "22"
|
32
|
-
ip_address = platform.ip_address || passenger_ip
|
33
|
-
|
34
|
-
host = "root@#{ip_address} -p #{port}"
|
35
|
-
|
36
|
-
sleep 1
|
37
|
-
remote_command host, "/etc/init.d/nginx restart"
|
38
|
-
{
|
39
|
-
:ip_address => ip_address,
|
40
|
-
:port => port,
|
41
|
-
:user => "app",
|
42
|
-
:rails_env => @rails_env,
|
43
|
-
:pending_files => webserver.pending_files,
|
44
|
-
}
|
45
|
-
end
|
46
|
-
|
47
|
-
def remote_command(host, command)
|
48
|
-
`ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no #{host} #{command}`
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
require "conjure/provision/docker/template"
|
2
|
-
require "securerandom"
|
3
|
-
|
4
|
-
module Conjure
|
5
|
-
module Provision
|
6
|
-
class Passenger
|
7
|
-
attr_reader :ip_address
|
8
|
-
|
9
|
-
def initialize(platform, database, rails_env, options)
|
10
|
-
@platform = platform
|
11
|
-
@database = database
|
12
|
-
@rails_env = rails_env
|
13
|
-
@nginx_directives = options[:nginx_directives] || {}
|
14
|
-
@system_packages = options[:system_packages] || []
|
15
|
-
@rubygems_version = options[:rubygems_version]
|
16
|
-
@use_ssl = !!options[:ssl_hostname]
|
17
|
-
@ssl_hostname = options[:ssl_hostname] || "unknown"
|
18
|
-
end
|
19
|
-
|
20
|
-
def start
|
21
|
-
@ip_address = server_template.build(@platform).start_daemon("/sbin/my_init", start_options)
|
22
|
-
end
|
23
|
-
|
24
|
-
def pending_files
|
25
|
-
return [] unless @use_ssl
|
26
|
-
[
|
27
|
-
"/etc/ssl/certs/application.crt",
|
28
|
-
"/etc/ssl/certs/root_and_intermediates.crt",
|
29
|
-
"/etc/ssl/private/application.key",
|
30
|
-
"/etc/ssl/dhparam.pem",
|
31
|
-
]
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def start_options
|
37
|
-
{
|
38
|
-
:linked_containers => @database.container_link,
|
39
|
-
:name => "passenger",
|
40
|
-
:ports => {80 => 80, 443 => 443, 2222 => 22},
|
41
|
-
:volume_containers => [data_container_name],
|
42
|
-
}
|
43
|
-
end
|
44
|
-
|
45
|
-
def data_container_name
|
46
|
-
data_template.build(@platform).start_volume(:name => "passenger_data")
|
47
|
-
"passenger_data"
|
48
|
-
end
|
49
|
-
|
50
|
-
def data_template
|
51
|
-
file = Docker::Template.new("conjure/passenger-ruby22:1.0.0")
|
52
|
-
file.add_file_data database_yml, "/home/app/application/shared/config/database.yml"
|
53
|
-
file.add_file_data secrets_yml, "/home/app/application/shared/config/secrets.yml"
|
54
|
-
file.volume "/home/app/application"
|
55
|
-
file
|
56
|
-
end
|
57
|
-
|
58
|
-
def server_template
|
59
|
-
public_key = File.expand_path("~/.ssh/id_rsa.pub")
|
60
|
-
raise "Error: ~/.ssh/id_rsa.pub must exist." unless File.exist?(public_key)
|
61
|
-
file = Docker::Template.new("conjure/passenger-ruby22:1.0.1")
|
62
|
-
file.run apt_command if apt_command
|
63
|
-
file.run rubygems_command if rubygems_command
|
64
|
-
file.add_file public_key, "/root/.ssh/authorized_keys"
|
65
|
-
file.add_file public_key, "/home/app/.ssh/authorized_keys"
|
66
|
-
file.run "chown app.app /home/app/.ssh/authorized_keys"
|
67
|
-
file.run "chown root.root /root/.ssh/authorized_keys"
|
68
|
-
file.add_file_data nginx_conf, "/etc/nginx/sites-available/application-no-ssl.conf"
|
69
|
-
file.add_file_data nginx_ssl_conf, "/etc/nginx/sites-available/application-ssl.conf"
|
70
|
-
which_config = @use_ssl ? "application-ssl" : "application-no-ssl"
|
71
|
-
file.run "ln -s /etc/nginx/sites-available/#{which_config}.conf /etc/nginx/sites-enabled/application.conf"
|
72
|
-
file
|
73
|
-
end
|
74
|
-
|
75
|
-
def apt_command
|
76
|
-
if @system_packages.any?
|
77
|
-
"apt-get update && apt-get install -y #{@system_packages.join ' '}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def rubygems_command
|
82
|
-
if @rubygems_version
|
83
|
-
target_source = "/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb"
|
84
|
-
"sed -i '23d' #{target_source} && gem update --system #{@rubygems_version}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def database_yml
|
89
|
-
{@rails_env => @database.rails_config}.to_yaml
|
90
|
-
end
|
91
|
-
|
92
|
-
def secrets_yml
|
93
|
-
{@rails_env => {"secret_key_base" => SecureRandom.hex(64)}}.to_yaml
|
94
|
-
end
|
95
|
-
|
96
|
-
def nginx_conf
|
97
|
-
render_template "application-no-ssl.conf"
|
98
|
-
end
|
99
|
-
|
100
|
-
def nginx_ssl_conf
|
101
|
-
render_template "application-ssl.conf"
|
102
|
-
end
|
103
|
-
|
104
|
-
def render_template(name)
|
105
|
-
template_path = File.join File.dirname(__FILE__), "templates", "#{name}.erb"
|
106
|
-
template_data = File.read template_path
|
107
|
-
Erubis::Eruby.new(template_data).result :rails_env => @rails_env, :ssl_hostname => @ssl_hostname
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|