conjure 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.md +6 -0
- data/lib/conjure/provision/docker/host.rb +32 -0
- data/lib/conjure/provision/docker/image.rb +22 -0
- data/lib/conjure/provision/docker/template.rb +50 -0
- data/lib/conjure/provision/instance.rb +24 -53
- data/lib/conjure/provision/local_docker.rb +16 -0
- data/lib/conjure/provision/passenger.rb +60 -0
- data/lib/conjure/provision/postgres.rb +44 -0
- data/lib/conjure/provision/server.rb +15 -2
- data/lib/conjure/version.rb +1 -1
- metadata +9 -5
- data/lib/conjure/provision/docker_image.rb +0 -20
- data/lib/conjure/provision/dockerfile.rb +0 -62
data/History.md
CHANGED
@@ -0,0 +1,32 @@
|
|
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 = "-d #{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
|
@@ -0,0 +1,22 @@
|
|
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(command, options = {})
|
13
|
+
container_id = @docker_host.started_container_id @name, command, options[:run_options]
|
14
|
+
sleep 2
|
15
|
+
ip_address = @docker_host.container_ip_address container_id
|
16
|
+
raise "Container failed to start" unless ip_address.present?
|
17
|
+
ip_address
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "conjure/provision/docker/host"
|
2
|
+
require "conjure/provision/docker/image"
|
3
|
+
|
4
|
+
module Conjure
|
5
|
+
module Provision
|
6
|
+
module Docker
|
7
|
+
class Template
|
8
|
+
def initialize(base_image_name)
|
9
|
+
@commands = ["FROM #{base_image_name}"]
|
10
|
+
@file_data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_file(filename, remote_name)
|
14
|
+
add_file_data File.read(filename), remote_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_file_data(data, remote_name)
|
18
|
+
local_name = "file#{@file_data.length+1}"
|
19
|
+
@file_data[local_name] = data
|
20
|
+
@commands << "ADD #{local_name} #{remote_name}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def run(command)
|
24
|
+
@commands << "RUN #{command}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def source
|
28
|
+
@commands.join "\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare_build_directory(&block)
|
32
|
+
Dir.mktmpdir do |dir|
|
33
|
+
@file_data.merge("Dockerfile" => source).each do |filename, data|
|
34
|
+
File.write "#{dir}/#{filename}", data
|
35
|
+
end
|
36
|
+
yield dir
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def build(platform)
|
41
|
+
docker_host = Host.new(platform)
|
42
|
+
image_name = prepare_build_directory do |dir|
|
43
|
+
docker_host.built_image_name dir
|
44
|
+
end
|
45
|
+
Image.new docker_host, image_name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
|
-
require "conjure/provision/
|
1
|
+
require "conjure/provision/docker/template"
|
2
|
+
require "conjure/provision/local_docker"
|
3
|
+
require "conjure/provision/postgres"
|
4
|
+
require "yaml"
|
2
5
|
|
3
6
|
module Conjure
|
4
7
|
module Provision
|
@@ -8,69 +11,37 @@ module Conjure
|
|
8
11
|
@rails_env = rails_env
|
9
12
|
end
|
10
13
|
|
11
|
-
def provision
|
12
|
-
|
14
|
+
def provision(options = {})
|
15
|
+
if options[:local]
|
16
|
+
platform = LocalDocker.new
|
17
|
+
else
|
18
|
+
platform = Server.create "#{@app_name}-#{@rails_env}"
|
19
|
+
end
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
db_ip_address = postgres_image.start("/sbin/my_init")
|
21
|
+
database = Postgres.new(platform)
|
22
|
+
database.start
|
17
23
|
|
18
|
-
|
19
|
-
|
24
|
+
webserver = Passenger.new(platform, database, @rails_env)
|
25
|
+
webserver.start
|
26
|
+
passenger_ip = webserver.ip_address
|
20
27
|
|
21
|
-
|
28
|
+
port = platform.ip_address ? "2222" : "22"
|
29
|
+
ip_address = platform.ip_address || passenger_ip
|
30
|
+
|
31
|
+
host = "root@#{ip_address} -p #{port}"
|
32
|
+
|
33
|
+
sleep 1
|
22
34
|
remote_command host, "/etc/init.d/nginx restart"
|
23
35
|
{
|
24
|
-
:ip_address =>
|
25
|
-
:port =>
|
36
|
+
:ip_address => ip_address,
|
37
|
+
:port => port,
|
26
38
|
:user => "app",
|
27
39
|
:rails_env => @rails_env
|
28
40
|
}
|
29
41
|
end
|
30
42
|
|
31
|
-
def postgres_dockerfile(db_password)
|
32
|
-
file = Dockerfile.new("conjure/postgres93:1.0.0")
|
33
|
-
file.run "echo \"ALTER USER db PASSWORD '#{db_password}'\" >/tmp/setpass"
|
34
|
-
file.run "/sbin/my_init -- /sbin/setuser postgres sh -c \"sleep 1; psql -f /tmp/setpass\""
|
35
|
-
file.run "rm /tmp/setpass"
|
36
|
-
file.run "/sbin/my_init -- /sbin/setuser db sh -c \"sleep 1; /usr/bin/createdb #{database_name}\""
|
37
|
-
file
|
38
|
-
end
|
39
|
-
|
40
|
-
def passenger_dockerfile(db_ip_address, db_password)
|
41
|
-
public_key = File.expand_path("~/.ssh/id_rsa.pub")
|
42
|
-
raise "Error: ~/.ssh/id_rsa.pub must exist." unless File.exist?(public_key)
|
43
|
-
file = Dockerfile.new("conjure/passenger-ruby21:1.0.1")
|
44
|
-
file.add_file public_key, "/root/.ssh/authorized_keys"
|
45
|
-
file.add_file public_key, "/home/app/.ssh/authorized_keys"
|
46
|
-
file.run "chown app.app /home/app/.ssh/authorized_keys"
|
47
|
-
file.run "chown root.root /root/.ssh/authorized_keys"
|
48
|
-
file.add_file_data application_conf, "/etc/nginx/sites-enabled/application.conf"
|
49
|
-
file.add_file_data database_yml(db_ip_address, db_password), "/home/app/application/shared/config/database.yml"
|
50
|
-
file
|
51
|
-
end
|
52
|
-
|
53
|
-
def new_db_password
|
54
|
-
require "securerandom"
|
55
|
-
SecureRandom.urlsafe_base64 20
|
56
|
-
end
|
57
|
-
|
58
|
-
def database_name
|
59
|
-
"#{@app_name}_#{@rails_env}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def database_yml(db_ip_address, db_password)
|
63
|
-
require "yaml"
|
64
|
-
{@rails_env => {"adapter" => "postgresql", "database" => database_name, "host" => db_ip_address, "username" => "db", "password" => db_password, "template" => "template0"}}.to_yaml
|
65
|
-
end
|
66
|
-
|
67
|
-
def application_conf
|
68
|
-
options = {listen: "80", root: "/home/app/application/current/public", passenger_enabled: "on", passenger_user: "app", passenger_ruby: "/usr/bin/ruby2.1", passenger_app_env: @rails_env}
|
69
|
-
"server {" + options.map{|k, v| " #{k} #{v};"}.join("\n") + "}\n"
|
70
|
-
end
|
71
|
-
|
72
43
|
def remote_command(host, command)
|
73
|
-
`ssh -o StrictHostKeyChecking=no #{host} #{command}`
|
44
|
+
`ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no #{host} #{command}`
|
74
45
|
end
|
75
46
|
end
|
76
47
|
end
|
@@ -0,0 +1,60 @@
|
|
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)
|
10
|
+
@platform = platform
|
11
|
+
@database = database
|
12
|
+
@rails_env = rails_env
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
@ip_address = dockerfile.build(@platform).start("/sbin/my_init", start_options)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def start_options
|
22
|
+
{:run_options => "-p 80:80 -p 2222:22"}
|
23
|
+
end
|
24
|
+
|
25
|
+
def dockerfile
|
26
|
+
public_key = File.expand_path("~/.ssh/id_rsa.pub")
|
27
|
+
raise "Error: ~/.ssh/id_rsa.pub must exist." unless File.exist?(public_key)
|
28
|
+
file = Docker::Template.new("conjure/passenger-ruby21:1.0.1")
|
29
|
+
file.add_file public_key, "/root/.ssh/authorized_keys"
|
30
|
+
file.add_file public_key, "/home/app/.ssh/authorized_keys"
|
31
|
+
file.run "chown app.app /home/app/.ssh/authorized_keys"
|
32
|
+
file.run "chown root.root /root/.ssh/authorized_keys"
|
33
|
+
file.add_file_data nginx_conf, "/etc/nginx/sites-enabled/application.conf"
|
34
|
+
file.add_file_data database_yml, "/home/app/application/shared/config/database.yml"
|
35
|
+
file.add_file_data secrets_yml, "/home/app/application/shared/config/secrets.yml"
|
36
|
+
file
|
37
|
+
end
|
38
|
+
|
39
|
+
def database_yml
|
40
|
+
{@rails_env => @database.rails_config}.to_yaml
|
41
|
+
end
|
42
|
+
|
43
|
+
def secrets_yml
|
44
|
+
{@rails_env => {"secret_key_base" => SecureRandom.hex(64)}}.to_yaml
|
45
|
+
end
|
46
|
+
|
47
|
+
def nginx_conf
|
48
|
+
options = {
|
49
|
+
:listen => "80",
|
50
|
+
:root => "/home/app/application/current/public",
|
51
|
+
:passenger_enabled => "on",
|
52
|
+
:passenger_user => "app",
|
53
|
+
:passenger_ruby => "/usr/bin/ruby2.1",
|
54
|
+
:passenger_app_env => @rails_env,
|
55
|
+
}
|
56
|
+
"server {" + options.map{|k, v| " #{k} #{v};"}.join("\n") + "}\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "conjure/provision/docker/template"
|
2
|
+
require "securerandom"
|
3
|
+
|
4
|
+
module Conjure
|
5
|
+
module Provision
|
6
|
+
class Postgres
|
7
|
+
def initialize(platform)
|
8
|
+
@platform = platform
|
9
|
+
@name = "conjure_db_#{SecureRandom.hex 8}"
|
10
|
+
@password = new_password
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
@ip_address = dockerfile.build(@platform).start("/sbin/my_init")
|
15
|
+
end
|
16
|
+
|
17
|
+
def rails_config
|
18
|
+
{
|
19
|
+
"adapter" => "postgresql",
|
20
|
+
"database" => @name,
|
21
|
+
"host" => @ip_address,
|
22
|
+
"username" => "db",
|
23
|
+
"password" => @password,
|
24
|
+
"template" => "template0",
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def dockerfile
|
31
|
+
file = Docker::Template.new("conjure/postgres93:1.0.0")
|
32
|
+
file.run "echo \"ALTER USER db PASSWORD '#{@password}'\" >/tmp/setpass"
|
33
|
+
file.run "/sbin/my_init -- /sbin/setuser postgres sh -c \"sleep 1; psql -f /tmp/setpass\""
|
34
|
+
file.run "rm /tmp/setpass"
|
35
|
+
file.run "/sbin/my_init -- /sbin/setuser db sh -c \"sleep 1; /usr/bin/createdb #{@name}\""
|
36
|
+
file
|
37
|
+
end
|
38
|
+
|
39
|
+
def new_password
|
40
|
+
SecureRandom.urlsafe_base64 20
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
1
3
|
module Conjure
|
2
4
|
module Provision
|
3
5
|
class Server
|
@@ -55,7 +57,7 @@ module Conjure
|
|
55
57
|
:name => name,
|
56
58
|
:flavor_id => "66",
|
57
59
|
:region_id => "4",
|
58
|
-
:image_id => "
|
60
|
+
:image_id => "5506141",
|
59
61
|
:private_key_path => "#{ssh_dir}/id_rsa",
|
60
62
|
:public_key_path => "#{ssh_dir}/id_rsa.pub",
|
61
63
|
}
|
@@ -66,9 +68,20 @@ module Conjure
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def self.uniquify(server_name)
|
69
|
-
require "securerandom"
|
70
71
|
"#{server_name}-#{SecureRandom.hex 4}"
|
71
72
|
end
|
73
|
+
|
74
|
+
def with_directory(local_path, &block)
|
75
|
+
local_archive = remote_archive = "/tmp/archive.tar.gz"
|
76
|
+
remote_path = "/tmp/unpacked_archive"
|
77
|
+
`cd #{local_path}; tar czf #{local_archive} *`
|
78
|
+
send_file local_archive, remote_archive
|
79
|
+
run "mkdir #{remote_path}; cd #{remote_path}; tar mxzf #{remote_archive}"
|
80
|
+
yield remote_path
|
81
|
+
ensure
|
82
|
+
`rm #{local_archive}`
|
83
|
+
run "rm -Rf #{remote_path} #{remote_archive}"
|
84
|
+
end
|
72
85
|
end
|
73
86
|
end
|
74
87
|
end
|
data/lib/conjure/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conjure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -127,8 +127,12 @@ files:
|
|
127
127
|
- lib/conjure/identity.rb
|
128
128
|
- lib/conjure/provision/server.rb
|
129
129
|
- lib/conjure/provision/instance.rb
|
130
|
-
- lib/conjure/provision/
|
131
|
-
- lib/conjure/provision/
|
130
|
+
- lib/conjure/provision/passenger.rb
|
131
|
+
- lib/conjure/provision/postgres.rb
|
132
|
+
- lib/conjure/provision/docker/host.rb
|
133
|
+
- lib/conjure/provision/docker/template.rb
|
134
|
+
- lib/conjure/provision/docker/image.rb
|
135
|
+
- lib/conjure/provision/local_docker.rb
|
132
136
|
- lib/conjure/command.rb
|
133
137
|
- lib/conjure/data_set.rb
|
134
138
|
- lib/conjure/service/digital_ocean_account.rb
|
@@ -177,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
181
|
version: 1.3.6
|
178
182
|
requirements: []
|
179
183
|
rubyforge_project:
|
180
|
-
rubygems_version: 1.8.
|
184
|
+
rubygems_version: 1.8.29
|
181
185
|
signing_key:
|
182
186
|
specification_version: 3
|
183
187
|
summary: Magically powerful deployment for Rails applications
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
module Provision
|
3
|
-
class DockerImage
|
4
|
-
attr_reader :image_name
|
5
|
-
|
6
|
-
def initialize(server, base_image_name)
|
7
|
-
@server = server
|
8
|
-
@image_name = base_image_name
|
9
|
-
end
|
10
|
-
|
11
|
-
def start(shell_command, options = {})
|
12
|
-
container_id = @server.run("docker run -d #{options[:run_options].to_s} #{image_name} #{shell_command}").strip
|
13
|
-
sleep 2
|
14
|
-
ip_address = @server.run("docker inspect -format '{{ .NetworkSettings.IPAddress }}' #{container_id}").strip
|
15
|
-
raise "Container failed to start" unless ip_address.present?
|
16
|
-
ip_address
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require "conjure/provision/docker_image"
|
2
|
-
|
3
|
-
module Conjure
|
4
|
-
module Provision
|
5
|
-
class Dockerfile
|
6
|
-
def initialize(base_image_name)
|
7
|
-
@commands = ["FROM #{base_image_name}"]
|
8
|
-
@file_data = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def add_file(filename, remote_name)
|
12
|
-
add_file_data File.read(filename), remote_name
|
13
|
-
end
|
14
|
-
|
15
|
-
def add_file_data(data, remote_name)
|
16
|
-
local_name = "file#{@file_data.length+1}"
|
17
|
-
@file_data[local_name] = data
|
18
|
-
@commands << "ADD #{local_name} #{remote_name}"
|
19
|
-
end
|
20
|
-
|
21
|
-
def run(command)
|
22
|
-
@commands << "RUN #{command}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def source
|
26
|
-
@commands.join "\n"
|
27
|
-
end
|
28
|
-
|
29
|
-
def prepare_build_directory(&block)
|
30
|
-
Dir.mktmpdir do |dir|
|
31
|
-
@file_data.merge("Dockerfile" => source).each do |filename, data|
|
32
|
-
File.write "#{dir}/#{filename}", data
|
33
|
-
end
|
34
|
-
yield dir
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def upload_build_directory(server, &block)
|
39
|
-
archive = "/tmp/dockerfile.tar.gz"
|
40
|
-
build_dir = "/tmp/docker_build"
|
41
|
-
prepare_build_directory do |dir|
|
42
|
-
`cd #{dir}; tar czf #{archive} *`
|
43
|
-
server.send_file archive, "dockerfile.tar.gz"
|
44
|
-
server.run "mkdir #{build_dir}; cd #{build_dir}; tar mxzf ~/dockerfile.tar.gz"
|
45
|
-
result = yield "/tmp/docker_build"
|
46
|
-
server.run "rm -Rf #{build_dir} ~/dockerfile.tar.gz"
|
47
|
-
`rm #{archive}`
|
48
|
-
result
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def build(server)
|
53
|
-
result = upload_build_directory(server) { |dir| server.run "docker build #{dir}" }
|
54
|
-
if match = result.match(/Successfully built ([0-9a-z]+)/)
|
55
|
-
DockerImage.new server, match[1]
|
56
|
-
else
|
57
|
-
raise "Failed to build Docker image, output was #{result}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|