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
@@ -1,259 +0,0 @@
1
- require 'digest/sha1'
2
-
3
- module Conjure
4
- module Service
5
- class DockerHost
6
- def initialize(server_name)
7
- @server_name = server_name
8
- end
9
-
10
- def server
11
- @server ||= Service::CloudServer.new @server_name
12
- end
13
-
14
- def ip_address
15
- @server.ip_address
16
- end
17
-
18
- def new_docker_path
19
- Log.info "[docker] Installing docker"
20
- server.run "dd if=/dev/zero of=/root/swapfile bs=1024 count=524288"
21
- server.run "mkswap /root/swapfile; swapon /root/swapfile"
22
- server.run "curl https://get.docker.io/gpg | apt-key add -"
23
- server.run "echo 'deb https://get.docker.io/ubuntu docker main' >/etc/apt/sources.list.d/docker.list"
24
- server.run "apt-get update"
25
- server.run "DEBIAN_FRONTEND=noninteractive apt-get install -y linux-image-extra-`uname -r` lxc-docker"
26
- existing_docker_path
27
- end
28
-
29
- def existing_docker_path
30
- path = server.run("which docker").stdout.to_s.strip
31
- path = nil if path == ""
32
- Log.info "[docker] Using installed #{path}" if path
33
- path
34
- end
35
-
36
- def docker_path
37
- @docker_path ||= existing_docker_path
38
- @docker_path ||= new_docker_path
39
- end
40
-
41
- def command(command, options = {}, &block)
42
- full_command = "#{docker_path} #{command}"
43
- full_command = "nohup #{full_command}" if options[:nohup]
44
- full_command = "echo '#{shell_escape options[:stdin]}' | #{full_command}" if options[:stdin]
45
- Log.debug " [scp] #{options[:files].inspect}" if options[:files]
46
- result = server.run full_command, :stream_stdin => options[:stream_stdin], :files => options[:files], &block
47
- raise "Docker error: #{result.stdout} #{result.stderr}" unless result.status == 0
48
- result.stdout
49
- end
50
-
51
- def ensure_host_directory(dir)
52
- server.run "mkdir -p #{dir}"
53
- end
54
-
55
- def shell_escape(text)
56
- text.gsub "'", "'\"'\"'"
57
- end
58
-
59
- def images
60
- ImageSet.new self
61
- end
62
-
63
- def containers
64
- ContainerSet.new :host => self
65
- end
66
-
67
- def shell
68
- DockerShell.new :docker_host => self
69
- end
70
- end
71
-
72
- class ImageSet
73
- def initialize(host)
74
- @host = host
75
- end
76
-
77
- def create(options)
78
- Image.new @host, options
79
- end
80
- end
81
-
82
- class Image
83
- attr_reader :host_volumes
84
-
85
- def initialize(host, options)
86
- @host = host
87
- @label = options[:label]
88
- @base_image = options[:base_image]
89
- @ports = options[:ports].to_a
90
- @volumes = options[:volumes].to_a
91
- @host_volumes = options[:host_volumes]
92
- @setup_commands = options[:setup_commands].to_a
93
- @daemon_command = options[:daemon_command]
94
- @environment = options[:environment]
95
- @files = options[:files]
96
- end
97
-
98
- def image_fingerprint
99
- Digest::SHA1.hexdigest(dockerfile)[0..11]
100
- end
101
-
102
- def expected_image_name
103
- "#{@label}:#{image_fingerprint}"
104
- end
105
-
106
- def installed_image_name
107
- build unless image_installed?
108
- expected_image_name
109
- end
110
-
111
- def image_installed?
112
- @host.command("history #{expected_image_name}") rescue false
113
- end
114
-
115
- def run(command = "")
116
- unless running_container
117
- Log.info "[docker] Starting #{@label}"
118
- run_options = host_volume_options(@host_volumes)
119
- run_options += port_options(@ports)
120
- command = shell_command command if command != ""
121
- container_id = @host.command("run #{run_options.join ' '} -d #{installed_image_name} #{command}").strip
122
- if(!running_container)
123
- output = @host.command "logs #{container_id}"
124
- raise "Docker: #{@label} daemon exited with: #{output}"
125
- end
126
- end
127
- Log.info "[docker] #{@label} is running at #{running_container.ip_address}"
128
- running_container
129
- end
130
-
131
- def raise_build_errors(build_output)
132
- match = build_output.match(/Error build: The command \[([^\]]*)\] returned a non-zero code:/)
133
- if match
134
- failed_command = match[1]
135
- last_section = build_output.split("--->").last
136
- last_section.gsub!(/Running in [0-9a-f]+/, "")
137
- last_section.gsub!(/Error build: The command.*/m, "")
138
- raise "Docker: build step '#{failed_command}' failed: #{last_section.strip}"
139
- end
140
- end
141
-
142
- def dockerfile
143
- lines = ["FROM #{base_image_name}"]
144
- lines += dockerfile_environment_entries
145
- lines += @setup_commands.map{|c| "RUN #{c}"}
146
- lines << "VOLUME #{@volumes.inspect}" if @volumes.to_a.any?
147
- lines << "ENTRYPOINT #{@daemon_command}" if @daemon_command
148
- lines.join "\n"
149
- end
150
-
151
- def dockerfile_environment_entries
152
- @environment.to_a.map do |k, v|
153
- "ENV #{k} #{v}" if v.to_s != ""
154
- end.compact
155
- end
156
-
157
- def base_image_name
158
- @base_image.respond_to?(:installed_image_name) ? @base_image.installed_image_name : @base_image
159
- end
160
-
161
- def build
162
- destroy_instances
163
- Log.info "[docker] Building #{@label} image"
164
- raise_build_errors(@host.command "build -t #{expected_image_name} -", stdin: dockerfile)
165
- @host.containers.destroy_all_stopped
166
- end
167
-
168
- def command(command, options = {}, &block)
169
- destroy_instances
170
- file_options = options[:files] ? ["-v /files:/files"] : []
171
- file_options += host_volume_options(@host_volumes)
172
- file_options << "-i" if options[:stream_stdin]
173
- @host.command "run #{file_options.join ' '} #{installed_image_name} #{shell_command command}", :stream_stdin => options[:stream_stdin], :files => files_hash(options[:files]), &block
174
- end
175
-
176
- def host_volume_options(host_volumes)
177
- host_volumes.to_a.map do |host_path, container_path|
178
- @host.ensure_host_directory host_path
179
- "-v=#{host_path}:#{container_path}:rw"
180
- end
181
- end
182
-
183
- def port_options(ports)
184
- ports.to_a.map {|port| "-p=#{port}:#{port}" }
185
- end
186
-
187
- def files_hash(files_array)
188
- files_array.to_a.inject({}) do |hash, local_file|
189
- hash.merge local_file => "/files/#{File.basename local_file}"
190
- end
191
- end
192
-
193
- def shell_command(command)
194
- "bash -c '#{@host.shell_escape command}'"
195
- end
196
-
197
- def running_container
198
- @runnning_container ||= @host.containers.find(:image_name => expected_image_name)
199
- end
200
-
201
- def destroy_instances
202
- @host.containers.destroy_all :image_name => @label
203
- end
204
-
205
- def stop
206
- destroy_instances
207
- end
208
- end
209
-
210
- class ContainerSet
211
- attr_accessor :host
212
-
213
- def initialize(options)
214
- self.host = options[:host]
215
- end
216
-
217
- def find(options)
218
- image_name = options[:image_name].clone
219
- image_name << ":" unless image_name.include? ":"
220
- id = host.command("ps | grep #{image_name} ; true").strip.split("\n").first.to_s[0..11]
221
- id = nil if id == ""
222
- Container.new(:host => host, :id => id) if id
223
- end
224
-
225
- def destroy_all_stopped
226
- all_ids = host.command("ps -a -q").split("\n").map(&:strip)
227
- running_ids = host.command("ps -q").split("\n").map(&:strip)
228
- stopped_ids = all_ids - running_ids
229
- host.command "rm #{stopped_ids.join ' '}"
230
- end
231
-
232
- def destroy_all(options)
233
- while container = find(:image_name => options[:image_name]) do
234
- Log.info "[docker] Stopping #{options[:image_name]}"
235
- host.command "stop #{container.id}"
236
- host.command "rm #{container.id}"
237
- end
238
- end
239
- end
240
-
241
- class Container
242
- attr_accessor :id, :host
243
-
244
- def initialize(options)
245
- self.id = options[:id]
246
- self.host = options[:host]
247
- end
248
-
249
- def ip_address
250
- status["NetworkSettings"]["IPAddress"]
251
- end
252
-
253
- def status
254
- require "json"
255
- JSON.parse(host.command "inspect #{id}").first
256
- end
257
- end
258
- end
259
- end
@@ -1,46 +0,0 @@
1
- module Conjure
2
- module Service
3
- class DockerShell
4
- attr_reader :docker_host
5
-
6
- def initialize(options)
7
- @docker_host = options[:docker_host]
8
- @image = options[:image]
9
- end
10
-
11
- def prepare(options)
12
- self.class.new(
13
- :docker_host => @docker_host,
14
- :image => @docker_host.images.create(image_options.merge options),
15
- )
16
- end
17
-
18
- def command(*args, &block)
19
- (@image || default_image).command *args, &block
20
- end
21
-
22
- def run(*args)
23
- (@image || default_image).run *args
24
- end
25
-
26
- def stop(*args)
27
- (@image || default_image).stop *args
28
- end
29
-
30
- def image_options
31
- {
32
- :base_image => (@image || default_image_name),
33
- :host_volumes => (@image.host_volumes if @image),
34
- }
35
- end
36
-
37
- def default_image
38
- @default_image ||= @docker_host.images.create(image_options)
39
- end
40
-
41
- def default_image_name
42
- "ubuntu"
43
- end
44
- end
45
- end
46
- end
@@ -1,25 +0,0 @@
1
- module Conjure
2
- module Service
3
- class ForwardedShell
4
- def initialize(options)
5
- @shell = options[:shell].prepare(
6
- :label => "forwarded",
7
- :setup_commands => [
8
- "apt-get install -y openssh-server",
9
- "mkdir -p /var/run/sshd",
10
- "mkdir -p /root/.ssh; echo '#{options[:public_key]}' > /root/.ssh/authorized_keys",
11
- "chmod 600 /root/.ssh/authorized_keys"
12
- ],
13
- )
14
- end
15
-
16
- def command(c)
17
- container = @shell.run "/usr/sbin/sshd -D -e"
18
- escaped_command = @shell.docker_host.shell_escape c
19
- ssh_command = "ssh -A -o StrictHostKeyChecking=no -o PasswordAuthentication=no #{container.ip_address} '#{escaped_command}'"
20
- result = @shell.docker_host.server.run ssh_command
21
- result.stdout
22
- end
23
- end
24
- end
25
- end
@@ -1,67 +0,0 @@
1
- module Conjure
2
- module Service
3
- class RailsCodebase
4
- def initialize(target, github_url, branch, rails_environment)
5
- @github_url = github_url
6
- @branch = branch
7
- @rails_environment = rails_environment
8
- @target = target
9
- end
10
-
11
- def database_yml
12
- {
13
- @rails_environment => {
14
- "adapter" => database.adapter_name,
15
- "database" => database.name,
16
- "encoding" => "utf8",
17
- "host" => database.ip_address,
18
- "username" => "root",
19
- "template" => "template0",
20
- }
21
- }.to_yaml
22
- end
23
-
24
- def branch
25
- @branch ||= repository_link.branch
26
- end
27
-
28
- def install
29
- repository_link.update
30
- configure_database
31
- configure_logs
32
- end
33
-
34
- def repository_link
35
- @repository_link ||= RepositoryLink.new(
36
- :volume => volume,
37
- :branch => @branch,
38
- :origin_url => @github_url,
39
- :public_key => Conjure.identity.public_key_data.gsub("\n", "\\n"),
40
- )
41
- end
42
-
43
- def volume
44
- @volume ||= Volume.new(:target => @target, :host_path => "/rails_app", :container_path => "/application_root")
45
- end
46
-
47
- def configure_database
48
- Log.info "[ repo] Generating database.yml"
49
- volume.write "config/database.yml", database_yml
50
- end
51
-
52
- def configure_logs
53
- Log.info "[ repo] Configuring application logger"
54
- setup = 'Rails.logger = Logger.new "#{Rails.root}/log/#{Rails.env}.log"'
55
- volume.write "config/initializers/z_conjure_logger.rb", setup
56
- end
57
-
58
- def gem_names
59
- volume.read("Gemfile").scan(/gem ['"]([^'"]+)['"]/).flatten
60
- end
61
-
62
- def database
63
- @database ||= Database.new :target => @target, :codebase => self
64
- end
65
- end
66
- end
67
- end
@@ -1,10 +0,0 @@
1
- module Conjure
2
- module Service
3
- class RailsConsole
4
- def initialize(options, &block)
5
- shell = options[:shell]
6
- shell.command("cd application_root; bundle exec rails console", :stream_stdin => true, &block)
7
- end
8
- end
9
- end
10
- end
@@ -1,14 +0,0 @@
1
- module Conjure
2
- module Service
3
- class RailsLogView
4
- def initialize(options, &block)
5
- arguments = []
6
- arguments << "-n #{options[:lines]}" if options[:lines]
7
- arguments << "-f" if options[:tail]
8
- arguments << "application_root/log/#{options[:rails_env]}.log"
9
- options[:shell].command("tail #{arguments.join ' '}", &block)
10
- rescue Interrupt
11
- end
12
- end
13
- end
14
- end
@@ -1,91 +0,0 @@
1
- module Conjure
2
- module Service
3
- class RailsServer
4
- def initialize(target, rails_environment)
5
- @target = target
6
- @rails_environment = rails_environment
7
- end
8
-
9
- def base_image
10
- @base_image ||= @target.shell.prepare(
11
- label: "rails_base",
12
- setup_commands: [
13
- "apt-get install -y curl git",
14
- "curl -L https://get.rvm.io | bash -s stable",
15
- "/usr/local/rvm/bin/rvm install #{ruby_version}",
16
- "ln -s /usr/local/rvm/rubies/* /usr/local/rvm/default-ruby",
17
- "bash -c 'source /usr/local/rvm/scripts/rvm; rvm use #{ruby_version}@global --default'",
18
- "ln -s /usr/local/rvm/rubies/*/lib/ruby/gems/* /usr/local/rvm/gems/default",
19
- "apt-get install -y #{apt_packages_required_for_gems.join ' '}",
20
- "echo 'deb http://us.archive.ubuntu.com/ubuntu/ precise universe' >>/etc/apt/sources.list",
21
- "apt-get install -y python-software-properties software-properties-common",
22
- "add-apt-repository -y ppa:chris-lea/node.js-legacy",
23
- "apt-get update",
24
- "apt-get install -y nodejs",
25
-
26
- ],
27
- environment: {
28
- PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/default-ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
29
- RAILS_ENV: @rails_environment,
30
- GITHUB_TOKEN: ENV["GITHUB_TOKEN"],
31
- FRECKLE_SUBDOMAIN: "neomind",
32
- },
33
- host_volumes: {"/rails_app" => "/application_root"},
34
- )
35
- end
36
-
37
- def server_image
38
- @server_image ||= base_image.prepare(
39
- label: "rails_server",
40
- ports: [80],
41
- environment: {
42
- PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/default-ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
43
- },
44
- )
45
- end
46
-
47
- def run
48
- install_gems
49
- update_database
50
- restart_server
51
- end
52
-
53
- def install_gems
54
- Log.info "[ rails] Installing gems"
55
- base_image.command "cd application_root; bundle --deployment"
56
- end
57
-
58
- def update_database
59
- database_exists ? migrate_database : initialize_database
60
- end
61
-
62
- def database_exists
63
- Log.info "[ rails] Checking the database status"
64
- base_image.command("cd application_root; bundle exec rake db:version; true").include? "Current version:"
65
- end
66
-
67
- def migrate_database
68
- Log.info "[ rails] Migrating the database"
69
- base_image.command "cd application_root; bundle exec rake db:migrate"
70
- end
71
-
72
- def initialize_database
73
- Log.info "[ rails] Setting up the database"
74
- base_image.command "cd application_root; bundle exec rake db:setup"
75
- end
76
-
77
- def restart_server
78
- server_image.stop
79
- server_image.run "cd application_root; rm -f tmp/pids/server.pid; bundle exec rails server -p 80"
80
- end
81
-
82
- def ruby_version
83
- Conjure.config.file_contents("../.ruby-version").strip
84
- end
85
-
86
- def apt_packages_required_for_gems
87
- ["libpq-dev", "libmysqlclient-dev"]
88
- end
89
- end
90
- end
91
- end