ruby_yacht 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +27 -0
- data/.gitignore +4 -0
- data/.rdoc_options +29 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +44 -0
- data/LICENSE +8 -0
- data/README.md +216 -0
- data/doc/CONTRIBUTING.md +12 -0
- data/doc/TODO.md +28 -0
- data/doc/configuration_sample.rb +87 -0
- data/lib/ruby_yacht/dsl/app.rb +59 -0
- data/lib/ruby_yacht/dsl/configuration.rb +55 -0
- data/lib/ruby_yacht/dsl/database.rb +57 -0
- data/lib/ruby_yacht/dsl/dns_server.rb +38 -0
- data/lib/ruby_yacht/dsl/dsl.rb +252 -0
- data/lib/ruby_yacht/dsl/project.rb +140 -0
- data/lib/ruby_yacht/dsl.rb +6 -0
- data/lib/ruby_yacht/images/app/Dockerfile.erb +32 -0
- data/lib/ruby_yacht/images/app/checkout.rb +7 -0
- data/lib/ruby_yacht/images/app/startup.rb +17 -0
- data/lib/ruby_yacht/images/app/update_database_config.rb +45 -0
- data/lib/ruby_yacht/images/app-dependencies/Dockerfile.erb +23 -0
- data/lib/ruby_yacht/images/app-dependencies/install_gems.rb +12 -0
- data/lib/ruby_yacht/images/database/Dockerfile.erb +26 -0
- data/lib/ruby_yacht/images/database/load_seeds.rb +42 -0
- data/lib/ruby_yacht/images/database/setup.rb +19 -0
- data/lib/ruby_yacht/images/database/setup_database.sql.erb +12 -0
- data/lib/ruby_yacht/images/deploy/Dockerfile.erb +2 -0
- data/lib/ruby_yacht/images/web/Dockerfile.erb +25 -0
- data/lib/ruby_yacht/images/web/add_app.rb +12 -0
- data/lib/ruby_yacht/images/web/add_project.rb +14 -0
- data/lib/ruby_yacht/images/web/app_config.erb +11 -0
- data/lib/ruby_yacht/images/web/index.html.erb +10 -0
- data/lib/ruby_yacht/images/web/index_config.erb +12 -0
- data/lib/ruby_yacht/images/web/setup.rb +22 -0
- data/lib/ruby_yacht/runner/build.rb +21 -0
- data/lib/ruby_yacht/runner/build_images.rb +82 -0
- data/lib/ruby_yacht/runner/checkout.rb +68 -0
- data/lib/ruby_yacht/runner/command.rb +161 -0
- data/lib/ruby_yacht/runner/help.rb +55 -0
- data/lib/ruby_yacht/runner/implode.rb +33 -0
- data/lib/ruby_yacht/runner/run_containers.rb +105 -0
- data/lib/ruby_yacht/runner/runner.rb +42 -0
- data/lib/ruby_yacht/runner/services.rb +79 -0
- data/lib/ruby_yacht/runner/shell.rb +66 -0
- data/lib/ruby_yacht/runner/update_hosts.rb +72 -0
- data/lib/ruby_yacht/runner.rb +18 -0
- data/lib/ruby_yacht.rb +6 -0
- data/ruby_yacht.gemspec +18 -0
- data/spec/docker/Dockerfile +5 -0
- data/spec/docker/build.bash +10 -0
- data/spec/dsl/app_spec.rb +47 -0
- data/spec/dsl/configuration_spec.rb +64 -0
- data/spec/dsl/database_spec.rb +75 -0
- data/spec/dsl/dns_server_spec.rb +25 -0
- data/spec/dsl/dsl_spec.rb +298 -0
- data/spec/dsl/project_spec.rb +266 -0
- data/spec/fixtures/app-dependencies-dockerfile +25 -0
- data/spec/fixtures/database-dockerfile +31 -0
- data/spec/fixtures/deploy-dockerfile +2 -0
- data/spec/fixtures/mars-dockerfile +32 -0
- data/spec/fixtures/multi-project-web-dockerfile +35 -0
- data/spec/fixtures/web-dockerfile +27 -0
- data/spec/runner/build_images_spec.rb +164 -0
- data/spec/runner/build_spec.rb +86 -0
- data/spec/runner/checkout_spec.rb +128 -0
- data/spec/runner/command_spec.rb +94 -0
- data/spec/runner/help_spec.rb +73 -0
- data/spec/runner/implode_spec.rb +62 -0
- data/spec/runner/run_containers_spec.rb +141 -0
- data/spec/runner/runner_spec.rb +117 -0
- data/spec/runner/services_spec.rb +135 -0
- data/spec/runner/shell_spec.rb +123 -0
- data/spec/runner/update_hosts_spec.rb +163 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/docker_stubbing.rb +93 -0
- data/spec/support/test_project.rb +56 -0
- metadata +193 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
#! /usr/local/bin/ruby
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
@project = ARGV.shift
|
5
|
+
@domain = ARGV.shift
|
6
|
+
@app = ARGV.shift
|
7
|
+
@port = ARGV.shift
|
8
|
+
@container_name = "#{@project}-#{@app}"
|
9
|
+
|
10
|
+
File.open(File.join("/etc/nginx/conf.d/#{@container_name}.conf"), 'w') do |file|
|
11
|
+
file.write(ERB.new(File.read('/var/docker/app_config.erb')).result(binding))
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#! /usr/local/bin/ruby
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
@project = ARGV.shift
|
5
|
+
@domain = ARGV.shift
|
6
|
+
@app_names = ARGV.shift.split(',')
|
7
|
+
|
8
|
+
File.open(File.join("/usr/share/nginx/html/#{@project}.html"), 'w') do |file|
|
9
|
+
file.write(ERB.new(File.read('/var/docker/index.html.erb')).result(binding))
|
10
|
+
end
|
11
|
+
|
12
|
+
File.open(File.join("/etc/nginx/conf.d/#{@project}-index.conf"), 'w') do |file|
|
13
|
+
file.write(ERB.new(File.read('/var/docker/index_config.erb')).result(binding))
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
server {
|
2
|
+
listen 80;
|
3
|
+
server_name <%= @app %>.<%= @domain %>;
|
4
|
+
|
5
|
+
location / {
|
6
|
+
proxy_pass http://<%= @container_name %>:<%= @port %>;
|
7
|
+
proxy_redirect off;
|
8
|
+
proxy_set_header Host $host;
|
9
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
10
|
+
}
|
11
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#! /usr/local/bin/ruby
|
2
|
+
require 'erb'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
@project = ARGV.shift
|
6
|
+
@domain = ARGV.shift
|
7
|
+
@app_names = ARGV.shift.split(',')
|
8
|
+
@app_ports = ARGV.shift.split(',')
|
9
|
+
|
10
|
+
File.open(File.join("/usr/share/nginx/html/#{@project}.html"), 'w') do |file|
|
11
|
+
file.write(ERB.new(File.read('/var/docker/index.html.erb')).result(binding))
|
12
|
+
end
|
13
|
+
|
14
|
+
File.open(File.join("/etc/nginx/conf.d/#{@project}.conf"), 'w') do |file|
|
15
|
+
file.write(ERB.new(File.read('/var/docker/index_config.erb')).result(binding))
|
16
|
+
@app_names.each_with_index do |app, port|
|
17
|
+
@app = app
|
18
|
+
@app_port = port
|
19
|
+
@container_name = @project + '-' + @app
|
20
|
+
file.write(ERB.new(File.read('/var/docker/app_config.erb')).result(binding))
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This class provides a command for building the system.
|
3
|
+
#
|
4
|
+
# It will build the images, run the containers, and update the hosts file.
|
5
|
+
class Build < Command
|
6
|
+
# The identifier for the command.
|
7
|
+
def self.command; 'build'; end
|
8
|
+
|
9
|
+
# The description for the command.
|
10
|
+
def self.description
|
11
|
+
"Build images and run containers"
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method runs the logic for this command.
|
15
|
+
def run
|
16
|
+
return BuildImages.new.run &&
|
17
|
+
RunContainers.new.run &&
|
18
|
+
UpdateHosts.new.run
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module RubyYacht::Runner
|
4
|
+
# This command builds the images for the system.
|
5
|
+
class BuildImages < Command
|
6
|
+
# The identifier for the command.
|
7
|
+
def self.command; 'build_images'; end
|
8
|
+
|
9
|
+
# The description for the command.
|
10
|
+
def self.description
|
11
|
+
"Build images for your environment"
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method runs the logic for the command.
|
15
|
+
def run
|
16
|
+
FileUtils.mkdir_p 'tmp'
|
17
|
+
|
18
|
+
default_system_prefix = projects.first.system_prefix
|
19
|
+
docker "network create #{default_system_prefix} 2> /dev/null"
|
20
|
+
|
21
|
+
projects.each do |project|
|
22
|
+
log "Building images for #{project.name}"
|
23
|
+
@project = project
|
24
|
+
|
25
|
+
id_path = File.join(ENV['HOME'], '.ssh', 'id_rsa')
|
26
|
+
tmp_id_path = File.join('tmp', 'id_rsa')
|
27
|
+
if File.exist?(id_path)
|
28
|
+
FileUtils.cp(id_path, tmp_id_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
build_image 'app-dependencies'
|
32
|
+
build_image 'database' if project.database.local?
|
33
|
+
|
34
|
+
@project.apps.each do |app|
|
35
|
+
@app = app
|
36
|
+
build_image 'app', "#{@project.system_prefix}-#{app.name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if @project.create_deploy_container
|
40
|
+
build_image 'deploy'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
@projects = projects
|
45
|
+
build_image 'web', "#{default_system_prefix}-web"
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
# This method builds an image.
|
51
|
+
#
|
52
|
+
# This will copy a Dockerfile template from a folder underneath the `images`
|
53
|
+
# folder, as well as any other files in that folder, into the tmp folder.
|
54
|
+
# It will then evaluate the Dockerfile.erb file, using the binding from the
|
55
|
+
# current context, and write it to the Dockerfile in the tmp folder. It will
|
56
|
+
# then build the image, and clear out the tmp folder.
|
57
|
+
#
|
58
|
+
# ### Parameters
|
59
|
+
#
|
60
|
+
# * **folder_name: String** The name of the folder containing the
|
61
|
+
# Dockerfile and related files.
|
62
|
+
# * **image_name: String** The name for the new image. If this is not
|
63
|
+
# provided, the image name will be the
|
64
|
+
# current project's prefix, followed by a
|
65
|
+
# dash, followed by the folder name.
|
66
|
+
def build_image(folder_name, image_name = nil)
|
67
|
+
Dir[File.join(File.dirname(File.dirname(__FILE__)), 'images', folder_name, '*')].each do |path|
|
68
|
+
FileUtils.cp(path, 'tmp')
|
69
|
+
end
|
70
|
+
|
71
|
+
File.open(File.join('tmp', 'Dockerfile'), 'w') do |file|
|
72
|
+
contents = ERB.new(File.read(File.join('tmp', 'Dockerfile.erb'))).result(binding)
|
73
|
+
file.write(contents)
|
74
|
+
end
|
75
|
+
|
76
|
+
image_name ||= "#{@project.system_prefix}-#{folder_name}"
|
77
|
+
docker "build -t #{image_name} tmp"
|
78
|
+
|
79
|
+
FileUtils.rm(Dir[File.join("tmp", "*")])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This class provides a command for checking out a new branch for an app.
|
3
|
+
class Checkout < Command
|
4
|
+
# The name of the command.
|
5
|
+
def self.command; 'checkout'; end
|
6
|
+
|
7
|
+
# The short description for the command.
|
8
|
+
def self.description
|
9
|
+
"Check out a new branch for an app"
|
10
|
+
end
|
11
|
+
|
12
|
+
# The name of the project that the app is in.
|
13
|
+
attr_accessor :project_name
|
14
|
+
|
15
|
+
# The name of the app.
|
16
|
+
attr_accessor :app
|
17
|
+
|
18
|
+
# The branch that we are checking out.
|
19
|
+
attr_accessor :branch
|
20
|
+
|
21
|
+
# This OptionParser for parsing command-line flags.
|
22
|
+
#
|
23
|
+
# This command accepts the project name as an optional flag.
|
24
|
+
def option_parser
|
25
|
+
OptionParser.new do |options|
|
26
|
+
options.banner = "Usage: #{Command.short_script_name} checkout [options] [APP] [BRANCH]"
|
27
|
+
options.separator "Options:"
|
28
|
+
|
29
|
+
options.on('-p', '--project PROJECT', "The project with the app we are checking out the branch in. Default: #{default_project.name}") do |name|
|
30
|
+
self.project_name = name.to_sym
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# This method extracts the positional arguments from the command line.
|
36
|
+
#
|
37
|
+
# This will take the app name and branch from the command line.
|
38
|
+
def parse_positional_arguments(arguments)
|
39
|
+
self.app = arguments.shift
|
40
|
+
self.branch = arguments.shift
|
41
|
+
end
|
42
|
+
|
43
|
+
# This method runs the logic for the command.
|
44
|
+
def run
|
45
|
+
if app.nil?
|
46
|
+
log "You must provide an app name"
|
47
|
+
log "Run #{Command.short_script_name} help checkout for more information"
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
if branch.nil?
|
51
|
+
log "You must provide a branch"
|
52
|
+
log "Run #{Command.short_script_name} help checkout for more information"
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
project = self.project_named(self.project_name)
|
57
|
+
return false unless project
|
58
|
+
|
59
|
+
container_name = "#{project.system_prefix}-#{app}"
|
60
|
+
|
61
|
+
docker "exec #{container_name} bash -c 'cd /var/code; git fetch; git checkout .; git checkout #{branch}; git pull'"
|
62
|
+
docker "exec #{container_name} bash -c '/var/docker/update_database_config.rb; rake db:migrate'"
|
63
|
+
docker "restart #{container_name}"
|
64
|
+
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module RubyYacht::Runner
|
4
|
+
# This class is the base class for the commands that users can run for
|
5
|
+
# managing their system.
|
6
|
+
class Command
|
7
|
+
# Command information
|
8
|
+
|
9
|
+
# The name of the command that users run to trigger this command.
|
10
|
+
# This implementation raises an error. Subclasses must implement it to
|
11
|
+
# provide the command name.
|
12
|
+
def self.command
|
13
|
+
raise "Command not defined for #{self}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# This class gets a short description of the command.
|
17
|
+
# This implementation raises an error. Subclasses must implement it to
|
18
|
+
# provide the command description.
|
19
|
+
def self.description
|
20
|
+
raise "Description not defined for #{self}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# This method gets the command-line options for invoking this script.
|
24
|
+
#
|
25
|
+
# This must return an OptionParser.
|
26
|
+
#
|
27
|
+
# The default implementation returns an OptionParser with the command name
|
28
|
+
# and description. Subclasses should implement this if they want to accept
|
29
|
+
# other command-line options.
|
30
|
+
def option_parser
|
31
|
+
OptionParser.new do |options|
|
32
|
+
options.banner = "Usage: #{Command.short_script_name} #{self.class.command}\n\n#{self.class.description}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method extracts the positional arguments from the command line.
|
37
|
+
#
|
38
|
+
# This will be called after all the flags have been consumed by the
|
39
|
+
# OptionParser.
|
40
|
+
#
|
41
|
+
# The default implementation does nothing. Subclasses should implement this
|
42
|
+
# if they want to extract arguments from the command line.
|
43
|
+
#
|
44
|
+
# ### Parameters
|
45
|
+
#
|
46
|
+
# * **arguments: Array** The remaining arguments from the command line.
|
47
|
+
def parse_positional_arguments(arguments)
|
48
|
+
end
|
49
|
+
|
50
|
+
# This method runs the logic for the command.
|
51
|
+
#
|
52
|
+
# The default implementation raises an exception. Subclasses must implement
|
53
|
+
# this with their command-specific logic.
|
54
|
+
#
|
55
|
+
# ### Returns
|
56
|
+
#
|
57
|
+
# This must return a Boolean indicating whether the command succeeded or
|
58
|
+
# not.
|
59
|
+
def run
|
60
|
+
raise "Run method not defined for #{self}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Helpers
|
64
|
+
|
65
|
+
# This method gets the name of the script that was invoked to run the
|
66
|
+
# commands.
|
67
|
+
#
|
68
|
+
# This will just be the filename of the script.
|
69
|
+
def self.short_script_name
|
70
|
+
return File.basename($0)
|
71
|
+
end
|
72
|
+
|
73
|
+
# This method gets the projects that have been configured.
|
74
|
+
def projects
|
75
|
+
RubyYacht.configuration.projects
|
76
|
+
end
|
77
|
+
|
78
|
+
# The project that we will use if they do not provide one from the command
|
79
|
+
# line.
|
80
|
+
def default_project
|
81
|
+
projects.first
|
82
|
+
end
|
83
|
+
|
84
|
+
# This method finds a project by name.
|
85
|
+
#
|
86
|
+
# If the name is nil, this will use the default project. If the name is
|
87
|
+
# provided, but does not match any project, this will log an error and
|
88
|
+
# return nil.
|
89
|
+
#
|
90
|
+
# ### Parameters
|
91
|
+
#
|
92
|
+
# * **name: Symbol** The name of the project.
|
93
|
+
def project_named(name)
|
94
|
+
if self.project_name
|
95
|
+
project = projects.find { |p| p.name == name }
|
96
|
+
unless project
|
97
|
+
log "There is no project named #{name}"
|
98
|
+
end
|
99
|
+
project
|
100
|
+
else
|
101
|
+
self.default_project
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# This method gets a property from the default docker machine.
|
106
|
+
#
|
107
|
+
# ### Parameters
|
108
|
+
#
|
109
|
+
# * **property: String** The docker machine property to fetch.
|
110
|
+
#
|
111
|
+
# ### Returns
|
112
|
+
# The response from docker-machine.
|
113
|
+
def get_machine_info(property)
|
114
|
+
backtick("docker-machine inspect default -f {{#{property}}}").strip
|
115
|
+
end
|
116
|
+
|
117
|
+
# Stubbing
|
118
|
+
|
119
|
+
# This method logs a message to standard out. It allows us to stub out and
|
120
|
+
# test the logging behavior of the commands.
|
121
|
+
def log(message)
|
122
|
+
$stdout.puts message
|
123
|
+
end
|
124
|
+
|
125
|
+
# This method sends a command to docker.
|
126
|
+
#
|
127
|
+
# This should start with exec, run, build, etc.
|
128
|
+
#
|
129
|
+
# This allows us to stub out and test the docker commands that get sent.
|
130
|
+
#
|
131
|
+
# ### Parameters
|
132
|
+
# * **command: String** The command to execute.
|
133
|
+
def docker(command)
|
134
|
+
system "docker #{command}"
|
135
|
+
end
|
136
|
+
|
137
|
+
# This method sends a command to the system.
|
138
|
+
#
|
139
|
+
# This is a proxy for Kernel.system that allows us to stub out and test the
|
140
|
+
# system interaction.
|
141
|
+
#
|
142
|
+
# ### Parameters
|
143
|
+
# * **command: String** The command to execute.
|
144
|
+
def system(command)
|
145
|
+
Kernel.system(command)
|
146
|
+
end
|
147
|
+
|
148
|
+
# This method runs a command using the backtick operator.
|
149
|
+
#
|
150
|
+
# This allows us to stub and and test the system interaction.
|
151
|
+
#
|
152
|
+
# ### Parameters
|
153
|
+
# * **command: String** The command to execute.
|
154
|
+
#
|
155
|
+
# ### Returns
|
156
|
+
# This returns the output from the command.
|
157
|
+
def backtick(command)
|
158
|
+
`#{command}`
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This command provides help information about other commands.
|
3
|
+
class Help < Command
|
4
|
+
# The name of the command.
|
5
|
+
def self.command; 'help'; end
|
6
|
+
|
7
|
+
# The short description of the command.
|
8
|
+
def self.description
|
9
|
+
"Get information on available commands"
|
10
|
+
end
|
11
|
+
|
12
|
+
# The command that we are getting help in.
|
13
|
+
attr_accessor :command
|
14
|
+
|
15
|
+
# This method gets the command-line options for the command.
|
16
|
+
def option_parser
|
17
|
+
OptionParser.new do |options|
|
18
|
+
options.banner = "Usage: #{Command.short_script_name} help [command]\n\n#{self.class.description}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This method extracts arguments from the command line.
|
23
|
+
#
|
24
|
+
# ### Parameters
|
25
|
+
#
|
26
|
+
# * **arguments: Array** The command line arguments.
|
27
|
+
def parse_positional_arguments(arguments)
|
28
|
+
self.command = arguments.shift
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method runs the logic for the command.
|
32
|
+
def run
|
33
|
+
if self.command
|
34
|
+
RubyYacht::Runner.commands.each do |command|
|
35
|
+
if command.command == self.command
|
36
|
+
log command.new.option_parser.to_s
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
log "Command not available: #{self.command}"
|
42
|
+
log "Run #{Command.short_script_name} help for more options"
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
|
46
|
+
log "Available commands: \n\n"
|
47
|
+
RubyYacht::Runner.commands.each do |command|
|
48
|
+
log "#{command.name}: #{command.description}"
|
49
|
+
end
|
50
|
+
|
51
|
+
log "\nRun #{Command.short_script_name} help [command] for more information on a command"
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This class provides a command for destroying the local docker environment.
|
3
|
+
class Implode < Command
|
4
|
+
# The name of the command.
|
5
|
+
def self.command; 'implode'; end
|
6
|
+
|
7
|
+
# The description of the command.
|
8
|
+
def self.description
|
9
|
+
"Destroy your local environment"
|
10
|
+
end
|
11
|
+
|
12
|
+
# This method runs the logic of the command.
|
13
|
+
def run
|
14
|
+
projects.each do |project|
|
15
|
+
system_prefix = project.system_prefix
|
16
|
+
|
17
|
+
machines = backtick("docker ps -a | grep #{system_prefix}").split("\n").map { |line| line.split(/\s+/)[0] }
|
18
|
+
machines.each do |machine|
|
19
|
+
docker "rm -f #{machine}"
|
20
|
+
end
|
21
|
+
|
22
|
+
images = backtick("docker images | grep #{system_prefix}").split("\n").map { |line| line.split(/\s+/)[0] }
|
23
|
+
images.each do |image|
|
24
|
+
docker "rmi #{image}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
backtick("docker images -q --filter dangling=true").split("\n").each do |image|
|
29
|
+
docker "rmi #{image}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This class provides a command for running all the images in new containers.
|
3
|
+
#
|
4
|
+
# It will also remove any existing containers with conflicting names.
|
5
|
+
class RunContainers < Command
|
6
|
+
# THe name of the command.
|
7
|
+
def self.command; 'run_containers'; end
|
8
|
+
|
9
|
+
# The short description of the command.
|
10
|
+
def self.description; 'Runs containers for all the apps'; end
|
11
|
+
|
12
|
+
# This method runs the logic of the command.
|
13
|
+
def run
|
14
|
+
@network = projects.first.system_prefix
|
15
|
+
|
16
|
+
projects.each do |project|
|
17
|
+
@project = project
|
18
|
+
if @project.check_out_locally
|
19
|
+
FileUtils.mkdir_p File.join(ENV["PWD"], '..', 'code')
|
20
|
+
end
|
21
|
+
|
22
|
+
if project.database.local?
|
23
|
+
run_container :database
|
24
|
+
end
|
25
|
+
|
26
|
+
project.apps.each do |app|
|
27
|
+
run_container app.name
|
28
|
+
end
|
29
|
+
|
30
|
+
if @project.create_deploy_container
|
31
|
+
run_container :deploy
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
@project = projects.first
|
36
|
+
|
37
|
+
run_container :web
|
38
|
+
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
# This method gets the flags for defining DNS server config when running
|
43
|
+
# a container.
|
44
|
+
def dns_server_flags
|
45
|
+
flags = []
|
46
|
+
if @project.dns_server
|
47
|
+
flags += @project.dns_server.servers.map { |server| "--dns=#{server}" }
|
48
|
+
flags += @project.dns_server.search_domains.map { |domain| "--dns-search=#{domain}" }
|
49
|
+
end
|
50
|
+
flags
|
51
|
+
end
|
52
|
+
|
53
|
+
# This method gets the flags for mapping the code volume to a local path for
|
54
|
+
# a container.
|
55
|
+
#
|
56
|
+
# ### Parameters
|
57
|
+
#
|
58
|
+
# * **container_name: Symbol** The name of the container, not including
|
59
|
+
# the system prefix.
|
60
|
+
def volume_flags(container_name)
|
61
|
+
if @project.check_out_locally && ![:database, :web].include?(container_name)
|
62
|
+
if container_name == :deploy
|
63
|
+
return ["-v $PWD/../code:/var/code"]
|
64
|
+
else
|
65
|
+
return ["-v $PWD/../code/#{container_name}:/var/code"]
|
66
|
+
end
|
67
|
+
else
|
68
|
+
return []
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# This method runs a container.
|
73
|
+
#
|
74
|
+
# It will also remove any existing containers with conflicting names.
|
75
|
+
#
|
76
|
+
# ### Parameters
|
77
|
+
#
|
78
|
+
# * **name: Symbol** The name of the container, not including the system
|
79
|
+
# prefix.
|
80
|
+
def run_container(name)
|
81
|
+
container_name = "#{@project.system_prefix}-#{name}"
|
82
|
+
remove_container container_name
|
83
|
+
|
84
|
+
flags = ["-d"]
|
85
|
+
flags += dns_server_flags
|
86
|
+
flags += volume_flags(name)
|
87
|
+
flags << "-it" if name == :deploy
|
88
|
+
flags << "-p 80:80" if name == :web
|
89
|
+
flags << "--net=#{@network}"
|
90
|
+
flags << "--net-alias=#{container_name}"
|
91
|
+
|
92
|
+
flag_text = flags.join(' ')
|
93
|
+
docker "run #{flag_text} --name=#{container_name} #{container_name}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# This method removes a container.
|
97
|
+
#
|
98
|
+
# ### Parameters
|
99
|
+
#
|
100
|
+
# * **container_name: String** The full name of the container.
|
101
|
+
def remove_container(container_name)
|
102
|
+
IO.popen("docker rm -f #{container_name}", err: :close) {}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RubyYacht::Runner
|
2
|
+
# This method provides the commands that we can run.
|
3
|
+
def self.commands
|
4
|
+
[Help, Build, BuildImages, RunContainers, Services, Checkout, Shell, UpdateHosts, Implode]
|
5
|
+
end
|
6
|
+
|
7
|
+
# This method gets the arguments for the current command.
|
8
|
+
def self.arguments
|
9
|
+
ARGV
|
10
|
+
end
|
11
|
+
|
12
|
+
# This method runs a command based on the command line arguments.
|
13
|
+
def self.run
|
14
|
+
arg = arguments[0]
|
15
|
+
|
16
|
+
if arg == '' || arg == nil
|
17
|
+
puts "You must provide a command to run"
|
18
|
+
puts "Run `#{$0} help` for more information"
|
19
|
+
exit(1)
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
command = self.commands.find { |c| c.command == arg }
|
24
|
+
if command
|
25
|
+
command_arguments = arguments
|
26
|
+
command_arguments.shift
|
27
|
+
|
28
|
+
instance = command.new
|
29
|
+
instance.option_parser.parse! command_arguments
|
30
|
+
instance.parse_positional_arguments command_arguments
|
31
|
+
|
32
|
+
success = instance.run
|
33
|
+
unless success
|
34
|
+
exit(1)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
puts "Command not recognized: #{arg}"
|
38
|
+
puts "Run `#{$0} help` for more information"
|
39
|
+
exit(1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|