conjure 0.2.10 → 0.3.0

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.
Files changed (54) hide show
  1. data/History.md +8 -0
  2. data/README.md +35 -76
  3. data/lib/conjure.rb +1 -12
  4. data/lib/conjure/delayed_job.rb +39 -0
  5. data/lib/conjure/digital_ocean/droplet.rb +5 -2
  6. data/lib/conjure/docker/host.rb +75 -0
  7. data/lib/conjure/docker/template.rb +71 -0
  8. data/lib/conjure/instance.rb +31 -76
  9. data/lib/conjure/passenger.rb +123 -0
  10. data/lib/conjure/postgres.rb +67 -0
  11. data/lib/conjure/rails_application.rb +32 -0
  12. data/lib/conjure/server.rb +41 -0
  13. data/lib/conjure/swap.rb +28 -0
  14. data/lib/conjure/{provision/templates → templates}/application-no-ssl.conf.erb +2 -1
  15. data/lib/conjure/{provision/templates → templates}/application-ssl.conf.erb +2 -1
  16. data/lib/conjure/version.rb +1 -1
  17. metadata +12 -41
  18. data/lib/conjure/application.rb +0 -35
  19. data/lib/conjure/command.rb +0 -74
  20. data/lib/conjure/command_target.rb +0 -25
  21. data/lib/conjure/config.rb +0 -44
  22. data/lib/conjure/data_set.rb +0 -7
  23. data/lib/conjure/identity.rb +0 -25
  24. data/lib/conjure/log.rb +0 -26
  25. data/lib/conjure/provider.rb +0 -26
  26. data/lib/conjure/provision.rb +0 -1
  27. data/lib/conjure/provision/docker/host.rb +0 -32
  28. data/lib/conjure/provision/docker/image.rb +0 -55
  29. data/lib/conjure/provision/docker/template.rb +0 -55
  30. data/lib/conjure/provision/instance.rb +0 -52
  31. data/lib/conjure/provision/local_docker.rb +0 -16
  32. data/lib/conjure/provision/passenger.rb +0 -111
  33. data/lib/conjure/provision/postgres.rb +0 -70
  34. data/lib/conjure/provision/server.rb +0 -78
  35. data/lib/conjure/service/cloud_server.rb +0 -112
  36. data/lib/conjure/service/database.rb +0 -25
  37. data/lib/conjure/service/database/mysql.rb +0 -69
  38. data/lib/conjure/service/database/postgres.rb +0 -77
  39. data/lib/conjure/service/digital_ocean_account.rb +0 -31
  40. data/lib/conjure/service/docker_host.rb +0 -259
  41. data/lib/conjure/service/docker_shell.rb +0 -46
  42. data/lib/conjure/service/forwarded_shell.rb +0 -25
  43. data/lib/conjure/service/rails_codebase.rb +0 -67
  44. data/lib/conjure/service/rails_console.rb +0 -10
  45. data/lib/conjure/service/rails_log_view.rb +0 -14
  46. data/lib/conjure/service/rails_server.rb +0 -91
  47. data/lib/conjure/service/rake_task.rb +0 -11
  48. data/lib/conjure/service/remote_file_set.rb +0 -24
  49. data/lib/conjure/service/remote_shell.rb +0 -73
  50. data/lib/conjure/service/repository_link.rb +0 -52
  51. data/lib/conjure/service/volume.rb +0 -28
  52. data/lib/conjure/target.rb +0 -19
  53. data/lib/conjure/view/application_view.rb +0 -42
  54. data/lib/conjure/view/table_view.rb +0 -38
@@ -0,0 +1,123 @@
1
+ require "conjure/docker/template"
2
+ require "erubis"
3
+ require "securerandom"
4
+
5
+ module Conjure
6
+ class Passenger
7
+ def initialize(container_host, options)
8
+ @container_host = container_host
9
+ @database = options[:database]
10
+ @rails_env = options[:rails_env] || "staging"
11
+ @max_upload_mb = options[:max_upload_mb] || 20
12
+ @system_packages = options[:system_packages] || []
13
+ @ruby_version = options[:ruby_version] || "2.2"
14
+ @rubygems_version = options[:rubygems_version]
15
+ @use_ssl = !!options[:ssl_hostname]
16
+ @ssl_hostname = options[:ssl_hostname] || "unknown"
17
+ @services = options[:services] || []
18
+ @system_packages += ["libsqlite3-dev", "libpq-dev"]
19
+ @system_packages += ["libruby#{@ruby_version}", "ruby#{@ruby_version}"]
20
+ @system_packages += @services.flat_map(&:system_packages)
21
+ end
22
+
23
+ def install
24
+ server_template.start(@container_host, "/sbin/my_init", start_options)
25
+ end
26
+
27
+ def pending_files
28
+ return [] unless @use_ssl
29
+ [
30
+ "/etc/ssl/certs/application.crt",
31
+ "/etc/ssl/certs/root_and_intermediates.crt",
32
+ "/etc/ssl/private/application.key",
33
+ "/etc/ssl/dhparam.pem",
34
+ ]
35
+ end
36
+
37
+ private
38
+
39
+ def start_options
40
+ {
41
+ :linked_containers => @database.container_link,
42
+ :name => "passenger",
43
+ :ports => {80 => 80, 443 => 443, 2222 => 22},
44
+ :volumes => {"passenger_data" => "/home/app/application"},
45
+ }
46
+ end
47
+
48
+ def base_docker_image
49
+ {
50
+ "2.2" => "phusion/passenger-ruby22:0.9.18",
51
+ "2.1" => "phusion/passenger-ruby21:0.9.18",
52
+ "2.0" => "phusion/passenger-ruby20:0.9.18",
53
+ "1.9" => "phusion/passenger-ruby19:0.9.18",
54
+ }[@ruby_version] || raise("Unsupported ruby version #{@ruby_version.inspect}")
55
+ end
56
+
57
+ def server_template
58
+ public_key = File.expand_path("~/.ssh/id_rsa.pub")
59
+ raise "Error: ~/.ssh/id_rsa.pub must exist." unless File.exist?(public_key)
60
+ file = Docker::Template.new(base_docker_image)
61
+ file.environment HOME: "/root"
62
+ file.run "rm -f /etc/service/nginx/down /etc/nginx/sites-enabled/default"
63
+ file.run "mkdir -p /home/app/application/shared/bundle/ruby/1.9.0/bin"
64
+ file.run "chown -R app /home/app/application && chmod -R 755 /home/app/application"
65
+ file.run "ln -s /usr/bin/node /home/app/application/shared/bundle/ruby/1.9.0/bin/node"
66
+ file.run apt_command if apt_command
67
+ file.run rubygems_command if rubygems_command
68
+ file.run "passwd -u app"
69
+ file.run "rm -f /etc/service/sshd/down"
70
+ file.add_file public_key, "/root/.ssh/authorized_keys"
71
+ file.add_file public_key, "/home/app/.ssh/authorized_keys"
72
+ file.run "chown app.app /home/app/.ssh/authorized_keys"
73
+ file.run "chown root.root /root/.ssh/authorized_keys"
74
+ file.add_file_data nginx_conf, "/etc/nginx/sites-available/application-no-ssl.conf"
75
+ file.add_file_data nginx_ssl_conf, "/etc/nginx/sites-available/application-ssl.conf"
76
+ which_config = @use_ssl ? "application-ssl" : "application-no-ssl"
77
+ file.run "ln -s /etc/nginx/sites-available/#{which_config}.conf /etc/nginx/sites-enabled/application.conf"
78
+ file.add_file_data database_yml, "/home/app/application/shared/config/database.yml"
79
+ file.add_file_data secrets_yml, "/home/app/application/shared/config/secrets.yml"
80
+ @services.each { |service| service.apply(file) }
81
+ file
82
+ end
83
+
84
+ def apt_command
85
+ if @system_packages.any?
86
+ "apt-get update && apt-get install -y #{@system_packages.join ' '}"
87
+ end
88
+ end
89
+
90
+ def rubygems_command
91
+ if @rubygems_version
92
+ "gem update --system #{@rubygems_version}"
93
+ end
94
+ end
95
+
96
+ def database_yml
97
+ {@rails_env.to_s => @database.rails_config}.to_yaml
98
+ end
99
+
100
+ def secrets_yml
101
+ {@rails_env.to_s => {"secret_key_base" => SecureRandom.hex(64)}}.to_yaml
102
+ end
103
+
104
+ def nginx_conf
105
+ render_template "application-no-ssl.conf"
106
+ end
107
+
108
+ def nginx_ssl_conf
109
+ render_template "application-ssl.conf"
110
+ end
111
+
112
+ def render_template(name)
113
+ template_path = File.join File.dirname(__FILE__), "templates", "#{name}.erb"
114
+ template_data = File.read template_path
115
+ Erubis::Eruby.new(template_data).result(
116
+ :rails_env => @rails_env,
117
+ :ruby_version => @ruby_version,
118
+ :ssl_hostname => @ssl_hostname,
119
+ :max_upload_mb => @max_upload_mb,
120
+ )
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,67 @@
1
+ require "conjure/docker/template"
2
+ require "securerandom"
3
+
4
+ module Conjure
5
+ class Postgres
6
+ def initialize(container_host)
7
+ @container_host = container_host
8
+ @name = "conjure_db_#{SecureRandom.hex 8}"
9
+ @password = new_password
10
+ end
11
+
12
+ def install
13
+ server_template.start(@container_host, "/sbin/my_init", start_options)
14
+ end
15
+
16
+ def rails_config
17
+ {
18
+ "adapter" => "postgresql",
19
+ "database" => @name,
20
+ "host" => container_name,
21
+ "username" => "db",
22
+ "password" => @password,
23
+ "template" => "template0",
24
+ }
25
+ end
26
+
27
+ def container_link
28
+ {container_name => container_name}
29
+ end
30
+
31
+ def pending_files
32
+ []
33
+ end
34
+
35
+ private
36
+
37
+ def start_options
38
+ {
39
+ :name => container_name,
40
+ :volumes => {"postgres_data" => "/var/lib/postgresql/9.3/main"}
41
+ }
42
+ end
43
+
44
+ def container_name
45
+ "postgres"
46
+ end
47
+
48
+ def server_template
49
+ file = Docker::Template.new("atbaker/sd-postgres")
50
+ file.run "useradd db"
51
+ file.run "/sbin/my_init -- /sbin/setuser postgres sh -c \"sleep 1; psql -h localhost -c 'CREATE USER db CREATEDB'\""
52
+ file.run "/sbin/my_init -- /sbin/setuser db sh -c \"sleep 1; createdb db\""
53
+ file.run "echo 'local all all ident' >/usr/local/pgsql/data/pg_hba.conf"
54
+ file.run "echo 'host all all 0.0.0.0/0 md5' >>/usr/local/pgsql/data/pg_hba.conf"
55
+ file.run "echo 'host all all ::1/128 md5' >>/usr/local/pgsql/data/pg_hba.conf"
56
+ file.run "echo \"ALTER USER db PASSWORD '#{@password}'\" >/tmp/setpass"
57
+ file.run "/sbin/my_init -- /sbin/setuser postgres sh -c \"sleep 1; psql -f /tmp/setpass\""
58
+ file.run "rm /tmp/setpass"
59
+ file.run "/sbin/my_init -- /sbin/setuser db sh -c \"sleep 1; /usr/bin/createdb #{@name}\""
60
+ file
61
+ end
62
+
63
+ def new_password
64
+ SecureRandom.urlsafe_base64 20
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,32 @@
1
+ require "conjure/delayed_job"
2
+ require "conjure/postgres"
3
+ require "conjure/passenger"
4
+
5
+ module Conjure
6
+ class RailsApplication
7
+ def initialize(container_host, options)
8
+ @container_host = container_host
9
+ @options = options
10
+ end
11
+
12
+ def install
13
+ components.each(&:install)
14
+ end
15
+
16
+ def pending_files
17
+ components.flat_map(&:pending_files)
18
+ end
19
+
20
+ private
21
+
22
+ def components
23
+ [
24
+ database = Postgres.new(@container_host),
25
+ Passenger.new(@container_host, @options.merge(
26
+ database: database,
27
+ services: [DelayedJob.new(@options)],
28
+ )),
29
+ ]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ require "conjure/digital_ocean/droplet"
2
+
3
+ module Conjure
4
+ class Server < Struct.new(:ip_address)
5
+ def run(command)
6
+ `ssh #{self.class.ssh_options} root@#{ip_address} #{quote_command command}`
7
+ end
8
+
9
+ def send_file(local_name, remote_name)
10
+ `scp #{self.class.ssh_options} #{local_name} root@#{ip_address}:#{remote_name}`
11
+ end
12
+
13
+ def self.ssh_options
14
+ "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR"
15
+ end
16
+
17
+ def quote_command(command)
18
+ "'" + command.gsub("'", "'\"'\"'") + "'"
19
+ end
20
+
21
+ def self.create(name_prefix, options = {})
22
+ new DigitalOcean::Droplet.new(droplet_options(name_prefix, options)).ip_address
23
+ end
24
+
25
+ def self.droplet_options(name_prefix, options = {})
26
+ {
27
+ image: "docker",
28
+ key_data: key_data,
29
+ name_prefix: name_prefix,
30
+ region: "nyc3",
31
+ size: (options[:instance_size] || "512mb"),
32
+ }
33
+ end
34
+
35
+ def self.key_data
36
+ ssh_dir = File.expand_path "~/.ssh"
37
+ raise "Error: ~/.ssh/id_rsa.pub must exist." unless File.exist?(ssh_dir) && File.exist?("#{ssh_dir}/id_rsa.pub")
38
+ File.read "#{ssh_dir}/id_rsa.pub"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ module Conjure
2
+ class Swap
3
+ def initialize(server)
4
+ @server = server
5
+ end
6
+
7
+ def install
8
+ if exists?
9
+ puts "Swap space detected."
10
+ else
11
+ puts "Swap space not detected, installing..."
12
+ @server.run "dd if=/dev/zero of=/root/swapfile bs=4096 count=524288"
13
+ @server.run "mkswap /root/swapfile; swapon /root/swapfile"
14
+ puts "Swap space installed."
15
+ end
16
+ end
17
+
18
+ def pending_files
19
+ []
20
+ end
21
+
22
+ private
23
+
24
+ def exists?
25
+ @server.run("swapon -s | wc -l").to_i > 1
26
+ end
27
+ end
28
+ end
@@ -3,6 +3,7 @@ server {
3
3
  root /home/app/application/current/public;
4
4
  passenger_enabled on;
5
5
  passenger_user app;
6
- passenger_ruby /usr/bin/ruby2.2;
6
+ passenger_ruby /usr/bin/ruby<%= ruby_version %>;
7
7
  passenger_app_env <%= rails_env %>;
8
+ client_max_body_size <%= max_upload_mb %>M;
8
9
  }
@@ -9,8 +9,9 @@ server {
9
9
  root /home/app/application/current/public;
10
10
  passenger_enabled on;
11
11
  passenger_user app;
12
- passenger_ruby /usr/bin/ruby2.2;
12
+ passenger_ruby /usr/bin/ruby<%= ruby_version %>;
13
13
  passenger_app_env <%= rails_env %>;
14
+ client_max_body_size <%= max_upload_mb %>M;
14
15
 
15
16
  ssl_certificate /etc/ssl/certs/application.crt;
16
17
  ssl_certificate_key /etc/ssl/private/application.key;
@@ -1,3 +1,3 @@
1
1
  module Conjure
2
- VERSION = "0.2.10" unless defined?(VERSION)
2
+ VERSION = "0.3.0" 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.10
4
+ version: 0.3.0
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: 2015-06-24 00:00:00.000000000 Z
12
+ date: 2016-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-scp
@@ -163,52 +163,23 @@ executables:
163
163
  extensions: []
164
164
  extra_rdoc_files: []
165
165
  files:
166
- - lib/conjure/application.rb
167
- - lib/conjure/command.rb
168
- - lib/conjure/command_target.rb
169
- - lib/conjure/config.rb
170
- - lib/conjure/data_set.rb
166
+ - lib/conjure/delayed_job.rb
171
167
  - lib/conjure/digital_ocean/account.rb
172
168
  - lib/conjure/digital_ocean/droplet.rb
173
169
  - lib/conjure/digital_ocean/key.rb
174
170
  - lib/conjure/digital_ocean/key_set.rb
171
+ - lib/conjure/docker/host.rb
172
+ - lib/conjure/docker/template.rb
175
173
  - lib/conjure/http_request.rb
176
- - lib/conjure/identity.rb
177
174
  - lib/conjure/instance.rb
178
- - lib/conjure/log.rb
179
- - lib/conjure/provider.rb
180
- - lib/conjure/provision/docker/host.rb
181
- - lib/conjure/provision/docker/image.rb
182
- - lib/conjure/provision/docker/template.rb
183
- - lib/conjure/provision/instance.rb
184
- - lib/conjure/provision/local_docker.rb
185
- - lib/conjure/provision/passenger.rb
186
- - lib/conjure/provision/postgres.rb
187
- - lib/conjure/provision/server.rb
188
- - lib/conjure/provision/templates/application-no-ssl.conf.erb
189
- - lib/conjure/provision/templates/application-ssl.conf.erb
190
- - lib/conjure/provision.rb
191
- - lib/conjure/service/cloud_server.rb
192
- - lib/conjure/service/database/mysql.rb
193
- - lib/conjure/service/database/postgres.rb
194
- - lib/conjure/service/database.rb
195
- - lib/conjure/service/digital_ocean_account.rb
196
- - lib/conjure/service/docker_host.rb
197
- - lib/conjure/service/docker_shell.rb
198
- - lib/conjure/service/forwarded_shell.rb
199
- - lib/conjure/service/rails_codebase.rb
200
- - lib/conjure/service/rails_console.rb
201
- - lib/conjure/service/rails_log_view.rb
202
- - lib/conjure/service/rails_server.rb
203
- - lib/conjure/service/rake_task.rb
204
- - lib/conjure/service/remote_file_set.rb
205
- - lib/conjure/service/remote_shell.rb
206
- - lib/conjure/service/repository_link.rb
207
- - lib/conjure/service/volume.rb
208
- - lib/conjure/target.rb
175
+ - lib/conjure/passenger.rb
176
+ - lib/conjure/postgres.rb
177
+ - lib/conjure/rails_application.rb
178
+ - lib/conjure/server.rb
179
+ - lib/conjure/swap.rb
180
+ - lib/conjure/templates/application-no-ssl.conf.erb
181
+ - lib/conjure/templates/application-ssl.conf.erb
209
182
  - lib/conjure/version.rb
210
- - lib/conjure/view/application_view.rb
211
- - lib/conjure/view/table_view.rb
212
183
  - lib/conjure.rb
213
184
  - README.md
214
185
  - History.md
@@ -1,35 +0,0 @@
1
- module Conjure
2
- class Application
3
- attr_reader :origin
4
-
5
- def self.find(options = {})
6
- new(options)
7
- end
8
-
9
- def instances
10
- Instance.where(:origin => @origin)
11
- end
12
-
13
- def data_sets
14
- DataSet.find(:origin => @origin)
15
- end
16
-
17
- def name
18
- match = @origin.match(/\/([^.]+)\.git$/) if @origin
19
- match[1] if match
20
- end
21
-
22
- private
23
-
24
- def initialize(options = {})
25
- @origin = options[:origin] || origin_from_path(options[:path])
26
- end
27
-
28
- def origin_from_path(path)
29
- return unless path
30
- remote_info = `cd #{path}; git remote -v |grep origin`
31
- match = remote_info.match(/(git@github.com[^ ]+)/)
32
- match[1] if match
33
- end
34
- end
35
- end
@@ -1,74 +0,0 @@
1
- require "thor"
2
-
3
- module Conjure
4
- class Command < Thor
5
- class_option :verbose, :aliases => "-v", :type => :boolean, :desc => "Show details of low-level operations for debugging"
6
- def initialize(*args)
7
- super
8
- Log.level = :debug if options[:verbose]
9
- end
10
-
11
- desc "create", "Create and deploy a new instance of the application"
12
- method_option :branch, :aliases => "-b", :type => :string, :desc => "Specify branch to deploy, default 'master'"
13
- method_option :origin, :type => :string, :desc => "Specify git URL to deploy from"
14
- method_option :rails_env, :type => :string, :desc => "Specify the Rails environment, default 'production'"
15
- def create
16
- target.new_instance.create
17
- end
18
-
19
- desc "deploy", "Deploy the app"
20
- method_option :branch, :aliases => "-b", :type => :string, :desc => "Specify branch to deploy, default 'master'"
21
- method_option :origin, :type => :string, :desc => "Specify git URL to deploy from"
22
- method_option :rails_env, :type => :string, :desc => "Specify the Rails environment, default 'production'"
23
- def deploy
24
- (target.existing_instance || target.new_instance).deploy
25
- end
26
-
27
- desc "import FILE", "Import the production database from a postgres SQL dump"
28
- def import(file)
29
- target.existing_instance.database.import file
30
- end
31
-
32
- desc "export FILE", "Export the production database to a postgres SQL dump"
33
- def export(file)
34
- target.existing_instance.database.export file
35
- end
36
-
37
- desc "log", "Display the Rails log from the deployed application"
38
- method_option :num, :aliases => "-n", :type => :numeric, :default => 10, :desc => "Show N lines of output"
39
- method_option :tail, :aliases => "-t", :type => :boolean, :desc => "Continue streaming new log entries"
40
- def log
41
- Service::RailsLogView.new(:shell => target.existing_instance.shell, :rails_env => target.existing_instance.rails_env, :lines => options[:num], :tail => options[:tail]) do |stdout|
42
- print stdout
43
- end
44
- end
45
-
46
- desc "rake [ARGUMENTS...]", "Run the specified rake task on the deployed application"
47
- def rake(*arguments)
48
- task = arguments.join(" ")
49
- Service::RakeTask.new(:task => task, :shell => target.existing_instance.shell) do |stdout|
50
- print stdout
51
- end
52
- end
53
-
54
- desc "console", "Start a console on the deployed application"
55
- def console
56
- Service::RailsConsole.new(:shell => target.existing_instance.shell) do |stdout|
57
- print stdout
58
- end
59
- end
60
-
61
- desc "show", "Show info on deployed instances"
62
- def show
63
- puts View::ApplicationView.new(target.application).render
64
- end
65
-
66
- default_task :help
67
-
68
- private
69
-
70
- def target
71
- CommandTarget.new(options)
72
- end
73
- end
74
- end