conjure 0.2.3 → 0.2.4

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/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