conjure 0.2.10 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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