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 CHANGED
@@ -1,3 +1,9 @@
1
+ ### Version 0.2.4
2
+ 2014-8-29
3
+
4
+ * Update to latest DigitalOcean Docker image ID
5
+ * Generate minimal secrets.yml when provisioning
6
+
1
7
  ### Version 0.2.3
2
8
  2014-3-28
3
9
 
@@ -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/dockerfile"
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
- server = Server.create "#{@app_name}-#{@rails_env}"
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
- db_password = new_db_password
15
- postgres_image = postgres_dockerfile(db_password).build(server)
16
- db_ip_address = postgres_image.start("/sbin/my_init")
21
+ database = Postgres.new(platform)
22
+ database.start
17
23
 
18
- passenger_image = passenger_dockerfile(db_ip_address, db_password).build(server)
19
- passenger_image.start("/sbin/my_init", :run_options => "-p 80:80 -p 2222:22")
24
+ webserver = Passenger.new(platform, database, @rails_env)
25
+ webserver.start
26
+ passenger_ip = webserver.ip_address
20
27
 
21
- host = "root@#{server.ip_address} -p 2222"
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 => server.ip_address,
25
- :port => "2222",
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,16 @@
1
+ module Conjure
2
+ module Provision
3
+ class LocalDocker
4
+ def run(command)
5
+ `#{command}`
6
+ end
7
+
8
+ def with_directory(path)
9
+ yield path
10
+ end
11
+
12
+ def ip_address
13
+ end
14
+ end
15
+ end
16
+ 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 => "2158507",
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
@@ -1,3 +1,3 @@
1
1
  module Conjure
2
- VERSION = "0.2.3" unless defined?(VERSION)
2
+ VERSION = "0.2.4" unless defined?(VERSION)
3
3
  end
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.3
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-03-28 00:00:00.000000000 Z
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/docker_image.rb
131
- - lib/conjure/provision/dockerfile.rb
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.28
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