breeze 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +89 -1
- data/lib/breeze.rb +1 -1
- data/lib/breeze/tasks.rb +1 -1
- data/lib/breeze/tasks/app.rb +42 -9
- data/lib/breeze/tasks/{list.rb → describe.rb} +5 -3
- data/lib/breeze/tasks/server.rb +1 -1
- data/lib/breeze/tasks/server/image.rb +10 -5
- data/lib/templates/Thorfile +13 -10
- data/lib/templates/profiles/rails_and_image_magick/configs/database.yml +1 -1
- data/lib/templates/profiles/rails_and_image_magick/configs/nginx/nginx.conf +5 -9
- data/lib/templates/profiles/rails_and_image_magick/scripts/install_conf.sh +1 -1
- data/lib/templates/profiles/rails_and_image_magick/scripts/install_cust.sh +1 -1
- data/lib/templates/shared/scripts/deploy.sh +3 -3
- metadata +4 -4
data/README.md
CHANGED
@@ -1,4 +1,92 @@
|
|
1
1
|
# breeze
|
2
2
|
|
3
3
|
Breeze provides some [Thor](https://github.com/wycats/thor) tasks and example scripts for managing cloud computing resources
|
4
|
-
on [Amazon's AWS cloud](http://aws.amazon.com/).
|
4
|
+
and deployments on [Amazon's AWS cloud](http://aws.amazon.com/). It uses [fog](https://github.com/geemus/fog) for the hard
|
5
|
+
work so it should be fairly easy to add support for other cloud computing providers that are supported by fog.
|
6
|
+
|
7
|
+
Breeze implements zero downtime deployments by moving an elastic ip from one server to another. Db migrations have to be
|
8
|
+
compatible with the previous version.
|
9
|
+
|
10
|
+
## install
|
11
|
+
|
12
|
+
gem install breeze
|
13
|
+
cd your-project
|
14
|
+
breeze init
|
15
|
+
|
16
|
+
Then edit Thorfile and the stuff that got copied to config/breeze.
|
17
|
+
|
18
|
+
Management of configuration files is almost compatible with [rubber](https://github.com/wr0ngway/rubber)
|
19
|
+
but breeze does not support roles and additives. See [the rubber wiki](https://github.com/wr0ngway/rubber/wiki/Configuration)
|
20
|
+
for more information.
|
21
|
+
|
22
|
+
## create a server image
|
23
|
+
|
24
|
+
thor server:image:create
|
25
|
+
|
26
|
+
The default install.sh compiles ruby, passenger, nginx and image magick. It takes a long time
|
27
|
+
(maybe half an hour on a small instance). It will prompt for the image name when completed.
|
28
|
+
|
29
|
+
## use it
|
30
|
+
|
31
|
+
thor describe # List all cloud resources that the current account can control with breeze
|
32
|
+
|
33
|
+
thor staging:deploy # Deploy a new version by replacing old servers with new ones
|
34
|
+
thor staging:disable # Copy maintenance.html to public/system/ on active web servers
|
35
|
+
thor staging:enable # Remove system/maintenance.html from active web servers
|
36
|
+
thor staging:rollback # Rollback the previous deploy
|
37
|
+
thor staging:start # Start web server and db for staging
|
38
|
+
thor staging:stop # Stop staging and destroy server and db
|
39
|
+
|
40
|
+
Define your staging and production in the Thorfile and the same tasks become available for both name spaces.
|
41
|
+
These tasks call app tasks with fixed parameters.
|
42
|
+
|
43
|
+
## plumbing commands
|
44
|
+
|
45
|
+
app
|
46
|
+
---
|
47
|
+
thor app:deploy PUBLIC_SERVER_NAME DB_SERVER_NAME BRANCH # Deploy a new version by replacing old servers with new ones
|
48
|
+
thor app:disable PUBLIC_SERVER_NAME # Upload system/maintenance.html to web servers
|
49
|
+
thor app:enable PUBLIC_SERVER_NAME # Remove system/maintenance.html from web servers
|
50
|
+
thor app:rollback PUBLIC_SERVER_NAME # Rollback a deploy
|
51
|
+
thor app:start PUBLIC_SERVER_NAME [DB_SERVER_NAME] [DB_NAME] # Start a new app with web server and db
|
52
|
+
thor app:stop PUBLIC_SERVER_NAME # Destroy web server and db
|
53
|
+
|
54
|
+
configuration
|
55
|
+
-------------
|
56
|
+
thor configuration:deploy_to_localhost # Transform and deploy server configuration files to the local file system based on...
|
57
|
+
|
58
|
+
db
|
59
|
+
--
|
60
|
+
thor db:clone OLD_DB NEW_DB # Create a new db server using the latest backup of OLD_DB.
|
61
|
+
thor db:create SERVER_NAME [DB_NAME] # Create a new database server
|
62
|
+
thor db:destroy NAME # Destroy a database server
|
63
|
+
|
64
|
+
dns
|
65
|
+
---
|
66
|
+
thor dns:record:create ZONE_ID NAME TYPE IP [TTL] # Create a new DNS record
|
67
|
+
thor dns:record:destroy ZONE_ID NAME [TYPE] # Destroy a DNS record
|
68
|
+
thor dns:zone:create DOMAIN # Create a new DNS zone
|
69
|
+
thor dns:zone:destroy ZONE_ID # Destroy a DNS zone
|
70
|
+
thor dns:zone:import ZONE_ID FILE # Creates dns records specified in FILE
|
71
|
+
|
72
|
+
describe
|
73
|
+
--------
|
74
|
+
thor describe:addresses # List allocated ip addresses
|
75
|
+
thor describe:cloud_resources # List all cloud resources that the current account can control with breeze
|
76
|
+
thor describe:db_servers # List database servers
|
77
|
+
thor describe:dns_records ZONE_ID # List all DNS records for the given zone
|
78
|
+
thor describe:dns_zones # Describe DNS zones
|
79
|
+
thor describe:images # Describe machine images owned by Breeze::CONFIGURATION[:image_owner]
|
80
|
+
thor describe:servers # Describe server instances
|
81
|
+
thor describe:volumes # Describe block store volumes (EBS)
|
82
|
+
|
83
|
+
server
|
84
|
+
------
|
85
|
+
thor server:address:associate IP NEW_SERVER_ID # Associate an existing IP with a new server
|
86
|
+
thor server:address:create SERVER_ID # Create and associate a new elastic ip
|
87
|
+
thor server:address:release IP # Release the ip address
|
88
|
+
thor server:create # Launch a new server instance
|
89
|
+
thor server:destroy INSTANCE_ID # Terminate a running (or stopped) server instance
|
90
|
+
thor server:image:create # Launch a server with the base image, wait for it to boot, invoke...
|
91
|
+
thor server:tag:create SERVER_ID KEY VALUE # Create or update a tag
|
92
|
+
thor server:tag:destroy SERVER_ID KEY # Delete a tag
|
data/lib/breeze.rb
CHANGED
data/lib/breeze/tasks.rb
CHANGED
data/lib/breeze/tasks/app.rb
CHANGED
@@ -57,24 +57,34 @@ module Breeze
|
|
57
57
|
deploy_command([new_server], public_server_name, db_server_name, branch)
|
58
58
|
puts("The new server should soon be available at #{ip(new_server)}.")
|
59
59
|
if ask("Ready to continue and move the elastic_ip for #{public_server_name} to the new server? [YES/rollback] >") =~ /r|n/i
|
60
|
-
|
60
|
+
new_server.destroy
|
61
|
+
else
|
62
|
+
remote("sudo shutdown -h +#{CONFIGURATION[:rollback_window]} &", :host => ip(old_server))
|
61
63
|
old_server.spare_for_rollback!
|
62
64
|
move_addresses(old_server, new_server)
|
63
|
-
else
|
64
|
-
new_server.destroy
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
68
|
desc 'rollback PUBLIC_SERVER_NAME', 'Rollback a deploy'
|
69
69
|
def rollback(public_server_name)
|
70
70
|
old_server = spare_servers(public_server_name).first
|
71
|
+
raise "no running spare server found for #{public_server_name}" unless old_server
|
72
|
+
if ip(old_server)
|
73
|
+
temp_ip = nil
|
74
|
+
else
|
75
|
+
puts("Old server does not have a public ip. Allocating a temporary address:")
|
76
|
+
thor("server:address:create #{old_server.id}")
|
77
|
+
old_server.reload until old_server.addresses.first
|
78
|
+
temp_ip = ip(old_server)
|
79
|
+
end
|
71
80
|
remote('sudo shutdown -c', :host => ip(old_server))
|
72
81
|
new_server = active_servers(public_server_name).first
|
73
82
|
remote(disable_app_command, :host => ip(new_server))
|
83
|
+
thor("server:address:release #{temp_ip}") if temp_ip
|
74
84
|
move_addresses(new_server, old_server)
|
75
85
|
old_server.breeze_state('reactivated')
|
76
86
|
new_server.breeze_state('abandoned_due_to_rollback')
|
77
|
-
if accept?('
|
87
|
+
if accept?('Ready to destroy the abandoned server now?')
|
78
88
|
new_server.destroy
|
79
89
|
end
|
80
90
|
end
|
@@ -87,16 +97,16 @@ module Breeze
|
|
87
97
|
end
|
88
98
|
end
|
89
99
|
|
90
|
-
def
|
91
|
-
fog.servers.select{ |s| s.name == public_server_name }
|
100
|
+
def running_servers(public_server_name)
|
101
|
+
fog.servers.select{ |s| s.ready? and s.name == public_server_name }
|
92
102
|
end
|
93
103
|
|
94
104
|
def spare_servers(public_server_name)
|
95
|
-
|
105
|
+
running_servers(public_server_name).select{ |s| s.spare_for_rollback? }
|
96
106
|
end
|
97
107
|
|
98
108
|
def active_servers(public_server_name)
|
99
|
-
|
109
|
+
running_servers(public_server_name).select{ |s| not s.spare_for_rollback? }
|
100
110
|
end
|
101
111
|
|
102
112
|
def on_each_server(command, public_server_name)
|
@@ -106,7 +116,7 @@ module Breeze
|
|
106
116
|
end
|
107
117
|
|
108
118
|
def disable_app_command
|
109
|
-
"cd #{CONFIGURATION[:app_path]} && cp config/breeze/maintenance.html public/system/"
|
119
|
+
"cd #{CONFIGURATION[:app_path]} && mkdir -p public/system && cp config/breeze/maintenance.html public/system/"
|
110
120
|
end
|
111
121
|
|
112
122
|
def enable_app_command
|
@@ -141,5 +151,28 @@ module Breeze
|
|
141
151
|
super(task + (options[:force] ? ' --force' : ''))
|
142
152
|
end
|
143
153
|
|
154
|
+
# Don't know how to include or inherit thor tasks and descriptions.
|
155
|
+
# These may be included in Staging and Production.
|
156
|
+
def self.inherited(c)
|
157
|
+
c.class_eval <<-END_TASKS
|
158
|
+
desc 'deploy', 'Deploy a new version by replacing old servers with new ones'
|
159
|
+
def deploy
|
160
|
+
thor("app:deploy \#{PUBLIC_SERVER_NAME} \#{DB_SERVER_NAME} \#{BRANCH}")
|
161
|
+
end
|
162
|
+
desc 'rollback', 'Rollback the previous deploy'
|
163
|
+
def rollback
|
164
|
+
thor("app:rollback \#{PUBLIC_SERVER_NAME}")
|
165
|
+
end
|
166
|
+
desc 'disable', 'Copy maintenance.html to public/system/ on active web servers'
|
167
|
+
def disable
|
168
|
+
thor("app:disable \#{PUBLIC_SERVER_NAME}")
|
169
|
+
end
|
170
|
+
desc 'enable', 'Remove system/maintenance.html from active web servers'
|
171
|
+
def enable
|
172
|
+
thor("app:enable \#{PUBLIC_SERVER_NAME}")
|
173
|
+
end
|
174
|
+
END_TASKS
|
175
|
+
end
|
176
|
+
|
144
177
|
end
|
145
178
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Breeze
|
2
2
|
|
3
|
-
class
|
3
|
+
class Describe < Veur
|
4
|
+
|
5
|
+
default_task :cloud_resources
|
4
6
|
|
5
7
|
desc :cloud_resources, 'List all cloud resources that the current account can control with breeze'
|
6
8
|
def cloud_resources
|
@@ -24,9 +26,9 @@ module Breeze
|
|
24
26
|
desc :servers, 'Describe server instances'
|
25
27
|
def servers
|
26
28
|
report "SERVER INSTANCES",
|
27
|
-
['Name', 'Instance ID', 'IP Address', 'Image ID', '
|
29
|
+
['Name', 'Instance ID', 'IP Address', 'Image ID', 'Type', 'Zone', 'State', 'Info'],
|
28
30
|
fog.servers.map { |i|
|
29
|
-
[i.name, i.id, i.public_ip_address, i.image_id, i.flavor_id, i.availability_zone, i.state]
|
31
|
+
[i.name, i.id, i.public_ip_address, i.image_id, i.flavor_id, i.availability_zone, i.state, i.breeze_state]
|
30
32
|
}
|
31
33
|
end
|
32
34
|
|
data/lib/breeze/tasks/server.rb
CHANGED
@@ -8,19 +8,24 @@ module Breeze
|
|
8
8
|
'stop the server, create a new machine image as a snapshot of the root device, and destroy the server.'
|
9
9
|
method_options CONFIGURATION[:default_server_options].merge(CONFIGURATION[:create_image_options])
|
10
10
|
def create
|
11
|
-
|
11
|
+
# The commented lines used to work before fog 0.7.0.
|
12
|
+
# options[:block_device_mapping] = [{:device_name => '/dev/sda1', :ebs_volume_size => options.delete(:root_device_size)}]
|
13
|
+
options[:block_device_mapping] = [{'DeviceName' => '/dev/sda1', 'Ebs.VolumeSize' => options.delete(:root_device_size)}]
|
12
14
|
server = create_server(options)
|
13
15
|
prepare_private_image(server.public_ip_address)
|
14
16
|
print('Stopping the server before saving a snapshot')
|
15
17
|
server.stop
|
16
18
|
wait_until('stopped!') { server.stopped? }
|
17
|
-
thor('
|
18
|
-
|
19
|
+
thor('describe:images')
|
20
|
+
puts('===== Old server images are listed above. Give a name to the new image. =====')
|
21
|
+
# image = fog.images.create(:name => ask('Image name >'), :instance_id => server.id)
|
22
|
+
fog.create_image(server.id, ask('Image name >'), '')
|
19
23
|
server.destroy
|
20
24
|
puts
|
21
|
-
puts("===> Created image #{image.id} and terminated temporary server #{server.id}.")
|
25
|
+
# puts("===> Created image #{image.id} and terminated temporary server #{server.id}.")
|
26
|
+
puts("===> Created a new server image and terminated temporary server #{server.id}.")
|
22
27
|
puts
|
23
|
-
puts("NOTICE: it may take a while before the new image shows up in
|
28
|
+
puts("NOTICE: it may take a while before the new image shows up in describe:images")
|
24
29
|
end
|
25
30
|
|
26
31
|
end
|
data/lib/templates/Thorfile
CHANGED
@@ -16,6 +16,7 @@ Breeze::CONFIGURATION = {
|
|
16
16
|
# Remote and upload commands are required in order to create a server image or deploy
|
17
17
|
# an application. Arguments marked with %{} are automatically replaced when the
|
18
18
|
# commands are used. Use "ssh -i /path/to/key" if not using your default ssh key.
|
19
|
+
:remote_available? => 'ssh -q ubuntu@%{host} exit',
|
19
20
|
:remote_command => "ssh ubuntu@%{host} '%{command}'",
|
20
21
|
:upload_command => 'rsync -v %{file_pattern} ubuntu@%{host}:%{remote_path}',
|
21
22
|
|
@@ -38,7 +39,7 @@ Breeze::CONFIGURATION = {
|
|
38
39
|
:root_device_size => 15 # in GB
|
39
40
|
},
|
40
41
|
|
41
|
-
# machine images owned by this account are included in
|
42
|
+
# machine images owned by this account are included in describe:images (provided that you have access to them)
|
42
43
|
:image_owner => 'YOUR-ACCOUNT-ID-WITHOUT-DASHES', # canonical: '099720109477'
|
43
44
|
|
44
45
|
# db configuration is required in order to use Amazon RDS
|
@@ -66,10 +67,10 @@ Breeze::CONFIGURATION = {
|
|
66
67
|
# with the "thor help" command.
|
67
68
|
require 'breeze/tasks'
|
68
69
|
|
70
|
+
# prepare_private_image is called from server:image:create. Modify this and/or the scripts
|
71
|
+
# that are uploaded in order to create your own private machine image.
|
69
72
|
class Breeze::Server::Image
|
70
73
|
private
|
71
|
-
# This method is called from server:image:create. Modify this and/or the scripts that
|
72
|
-
# are uploaded in order to create your own private machine image.
|
73
74
|
def prepare_private_image(ip_address)
|
74
75
|
wait_until_host_is_available(ip_address)
|
75
76
|
puts("Uploading scripts...")
|
@@ -78,8 +79,7 @@ class Breeze::Server::Image
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
#
|
82
|
-
|
82
|
+
# deploy_command is called from app:start and app:deploy.
|
83
83
|
class Breeze::App
|
84
84
|
private
|
85
85
|
def deploy_command(servers, public_server_name, db_server_name, branch)
|
@@ -90,15 +90,18 @@ class Breeze::App
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
#
|
93
|
+
# Define staging:start etc. below. The constants are also needed by
|
94
|
+
# inherited tasks: deploy, rollback, enable and disable.
|
95
|
+
|
94
96
|
class Staging < Breeze::App
|
95
97
|
|
96
98
|
PUBLIC_SERVER_NAME = 'staging.example.com'
|
97
99
|
DB_SERVER_NAME = 'staging-db'
|
100
|
+
BRANCH = 'master'
|
98
101
|
|
99
102
|
desc 'start', 'Start web server and db for staging'
|
100
103
|
def start
|
101
|
-
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} --db-to-clone=#{Production::DB_SERVER_NAME} --deploy-branch
|
104
|
+
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} --db-to-clone=#{Production::DB_SERVER_NAME} --deploy-branch=#{BRANCH}")
|
102
105
|
end
|
103
106
|
|
104
107
|
desc 'stop', 'Stop staging and destroy server and db'
|
@@ -108,15 +111,15 @@ class Staging < Breeze::App
|
|
108
111
|
|
109
112
|
end
|
110
113
|
|
111
|
-
# thor production:start
|
112
114
|
class Production < Breeze::App
|
113
115
|
|
114
|
-
PUBLIC_SERVER_NAME = '
|
116
|
+
PUBLIC_SERVER_NAME = 'www.example.com'
|
115
117
|
DB_SERVER_NAME = 'production-db'
|
118
|
+
BRANCH = 'stable'
|
116
119
|
|
117
120
|
desc 'start', 'Start web server and db for production'
|
118
121
|
def start
|
119
|
-
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME}
|
122
|
+
thor("app:start #{PUBLIC_SERVER_NAME} #{DB_SERVER_NAME} db_name --dns-ttl=300 --deploy-branch=#{BRANCH}")
|
120
123
|
end
|
121
124
|
|
122
125
|
end
|
@@ -5,9 +5,9 @@
|
|
5
5
|
system("mkdir -p #{dir} && chown www-data #{dir}") unless File.directory?(dir)
|
6
6
|
end
|
7
7
|
|
8
|
-
passenger_version = "3.0.
|
8
|
+
passenger_version = "3.0.5"
|
9
9
|
server_name = ENV['PUBLIC_SERVER_NAME']
|
10
|
-
server_root = "/
|
10
|
+
server_root = "#{CONFIGURATION[:app_path]}/public"
|
11
11
|
|
12
12
|
shared_server_conf = <<-END_SHARED_SERVER_CONF
|
13
13
|
|
@@ -22,14 +22,10 @@
|
|
22
22
|
# let browsers cache static assets
|
23
23
|
location ~ ^/(images|javascripts|stylesheets)/ { expires 1y; }
|
24
24
|
|
25
|
-
#
|
26
|
-
|
27
|
-
if (-f $document_root/system/maintenance.html) {
|
28
|
-
rewrite ^(.*)$ /system/maintenance.html last;
|
29
|
-
break;
|
30
|
-
}
|
25
|
+
# static files, page caching and maintenance.html
|
26
|
+
try_files $uri $uri/index.html $uri.html /system/maintenance.html @passenger;
|
31
27
|
|
32
|
-
location
|
28
|
+
location @passenger {
|
33
29
|
passenger_enabled on;
|
34
30
|
}
|
35
31
|
|
@@ -17,7 +17,7 @@ PACKAGES="$SYSTEM_PACKAGES $DB_CLIENT_PACKAGES $RUBY_BUILD_DEPENDENCIES $NGINX_A
|
|
17
17
|
|
18
18
|
# the rest is used by install_cust.sh
|
19
19
|
RUBY_PACKAGE=ruby-1.9.2-p180
|
20
|
-
IMAGE_MAGICK_PACKAGE=ImageMagick-6.6.
|
20
|
+
IMAGE_MAGICK_PACKAGE=ImageMagick-6.6.8-6
|
21
21
|
IMAGE_MAGICK_OPTIONS='--disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8'
|
22
22
|
NGINX_OPTIONS="\
|
23
23
|
--conf-path=/etc/nginx/nginx.conf \
|
@@ -5,7 +5,7 @@
|
|
5
5
|
download ftp://ftp.ruby-lang.org//pub/ruby/1.9/$RUBY_PACKAGE.tar.gz
|
6
6
|
extract_and_install $RUBY_PACKAGE
|
7
7
|
sudo gem update --system
|
8
|
-
sudo gem install --no-ri --no-rdoc bundler passenger
|
8
|
+
sudo gem install --no-ri --no-rdoc bundler passenger breeze
|
9
9
|
|
10
10
|
# install nginx and passenger
|
11
11
|
sudo passenger-install-nginx-module --auto --auto-download --prefix=/usr --extra-configure-flags="$NGINX_OPTIONS"
|
@@ -34,10 +34,10 @@ sudo usermod --groups rails ubuntu
|
|
34
34
|
|
35
35
|
wget -q --no-check-certificate --directory-prefix=$HOME --output-document=tarball.tar.gz $DOWNLOAD_URL
|
36
36
|
tar --directory $HOME -xzf tarball.tar.gz
|
37
|
-
|
38
37
|
sudo mv $HOME/*$APP_NAME* $DEPLOY_PATH
|
39
|
-
|
38
|
+
|
40
39
|
cd $DEPLOY_PATH
|
41
|
-
|
40
|
+
bundle install --deployment --without=test development
|
41
|
+
sudo chown -R rails:rails $DEPLOY_PATH
|
42
42
|
sudo PUBLIC_SERVER_NAME=$PUBLIC_SERVER_NAME DB_SERVER=$DB_SERVER thor configuration:deploy_to_localhost
|
43
43
|
sudo /etc/init.d/monit start
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Markus Bengts
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-03-
|
17
|
+
date: 2011-03-22 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -73,8 +73,8 @@ files:
|
|
73
73
|
- lib/breeze/tasks/app.rb
|
74
74
|
- lib/breeze/tasks/configuration.rb
|
75
75
|
- lib/breeze/tasks/db.rb
|
76
|
+
- lib/breeze/tasks/describe.rb
|
76
77
|
- lib/breeze/tasks/dns.rb
|
77
|
-
- lib/breeze/tasks/list.rb
|
78
78
|
- lib/breeze/tasks/server.rb
|
79
79
|
- lib/breeze/tasks/server/address.rb
|
80
80
|
- lib/breeze/tasks/server/image.rb
|