Flucti-flucti-cli 0.1.16
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -0
- data/README.mdown +24 -0
- data/Rakefile +56 -0
- data/TODO.txt +19 -0
- data/bin/flucti +4 -0
- data/flucti-cli.gemspec +46 -0
- data/lib/flucti.rb +20 -0
- data/lib/flucti/api_access.rb +56 -0
- data/lib/flucti/cli.rb +107 -0
- data/lib/flucti/parameters.rb +37 -0
- data/lib/flucti/resources.rb +41 -0
- data/lib/flucti/resources/account.rb +7 -0
- data/lib/flucti/resources/app_type.rb +18 -0
- data/lib/flucti/resources/backend.rb +28 -0
- data/lib/flucti/resources/basic_resource.rb +16 -0
- data/lib/flucti/resources/container.rb +15 -0
- data/lib/flucti/resources/db_server.rb +38 -0
- data/lib/flucti/resources/domain.rb +8 -0
- data/lib/flucti/resources/general.rb +14 -0
- data/lib/flucti/resources/mail_client.rb +7 -0
- data/lib/flucti/resources/mail_server.rb +7 -0
- data/lib/flucti/resources/port_forwarding.rb +15 -0
- data/lib/flucti/resources/port_forwarding/services +13921 -0
- data/lib/flucti/resources/ssh_details.rb +96 -0
- data/lib/flucti/resources/webserver.rb +9 -0
- data/lib/flucti/resources/website.rb +9 -0
- data/lib/flucti/tasks.rb +3 -0
- data/lib/flucti/tasks/apikey_tasks.rb +57 -0
- data/lib/flucti/tasks/apptype_tasks.rb +264 -0
- data/lib/flucti/tasks/connect_pack.rb +161 -0
- data/lib/flucti/tasks/db_tasks.rb +158 -0
- data/lib/flucti/tasks/mail_tasks.rb +104 -0
- data/lib/flucti/tasks/miscellaneous_tasks.rb +6 -0
- data/lib/flucti/tasks/progress_tasks.rb +24 -0
- data/lib/flucti/tasks/sshkey_tasks.rb +151 -0
- data/lib/flucti/tasks/vps/firewall_tasks.rb +84 -0
- data/lib/flucti/tasks/vps_tasks.rb +37 -0
- data/lib/flucti/tasks/webserver_tasks.rb +154 -0
- data/lib/flucti/tasks/website/apptype_tasks.rb +42 -0
- data/lib/flucti/tasks/website/backends/instances_tasks.rb +37 -0
- data/lib/flucti/tasks/website/backends_tasks.rb +254 -0
- data/lib/flucti/tasks/website/capfile_tasks.rb +41 -0
- data/lib/flucti/tasks/website/domains_tasks.rb +107 -0
- data/lib/flucti/tasks/website_tasks.rb +221 -0
- data/lib/flucti/utilities.rb +20 -0
- data/lib/flucti/utilities/connection_error_handling.rb +50 -0
- data/lib/flucti/utilities/core_ext.rb +35 -0
- data/lib/flucti/utilities/list_displayer.rb +57 -0
- data/lib/flucti/utilities/miscellaneous.rb +65 -0
- data/lib/flucti/utilities/progress_bar.rb +17 -0
- data/lib/flucti/utilities/table.rb +25 -0
- data/lib/flucti/utilities/task_packing.rb +10 -0
- data/lib/flucti/utilities/user_interface.rb +117 -0
- data/lib/vendor/ruby-progressbar-0.9/lib/ChangeLog +113 -0
- data/lib/vendor/ruby-progressbar-0.9/lib/progressbar.en.rd +103 -0
- data/lib/vendor/ruby-progressbar-0.9/lib/progressbar.ja.rd +100 -0
- data/lib/vendor/ruby-progressbar-0.9/lib/progressbar.rb +236 -0
- data/lib/vendor/ruby-progressbar-0.9/lib/test.rb +105 -0
- data/test/flucti/resources_test.rb +32 -0
- data/test/flucti/tasks_test.rb +28 -0
- data/test/flucti/utilities/miscellaneous_test.rb +54 -0
- data/test/flucti/utilities/table_test.rb +28 -0
- data/test/flucti/utilities/user_interface_test.rb +161 -0
- data/test/test_helper.rb +5 -0
- metadata +221 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
namespace :vps do
|
2
|
+
namespace :firewall do
|
3
|
+
# Allow for defining task named `open':
|
4
|
+
class << self
|
5
|
+
undef_method :open if private_method_defined? :open
|
6
|
+
end
|
7
|
+
|
8
|
+
task(:default) { rules }
|
9
|
+
|
10
|
+
desc <<-DESC
|
11
|
+
Open a port from the Internet to a VPS. For example, if you choose to
|
12
|
+
open port 443 of a VPS foo, it will be accessible from the Internet on a
|
13
|
+
port greater than or equal to 1025, like 1047. As a result, packets
|
14
|
+
would arrive like this:
|
15
|
+
|
16
|
+
Internet <=> (Firewall:1047) <=> VPS:443
|
17
|
+
|
18
|
+
Following on this example:
|
19
|
+
$ #{command 'vps:firewall:open'} PORT=443
|
20
|
+
|
21
|
+
As 443 is the default HTTP SSL port number, you can a host site over SSL
|
22
|
+
and it will be accessible from the Internet on port 1047, for example at
|
23
|
+
https://www.example.com:1047.
|
24
|
+
|
25
|
+
By default, a port is open from the Internet. But you can restrict the
|
26
|
+
access to only one or several of your VPS's by specifying the $FROM
|
27
|
+
variable.
|
28
|
+
|
29
|
+
For example, to open port 3306 (MySQL) of VPS #{q 'trever'} to another
|
30
|
+
VPS #{q 'christina'}:
|
31
|
+
$ #{command 'vps:firewall:open'} FROM=christina ID=trever PORT=3306
|
32
|
+
|
33
|
+
Environment variables:
|
34
|
+
(mandatory) $PORT: the destination port number on the VPS, in the form
|
35
|
+
of <port>[:<protocol>], where <protocol> is optional
|
36
|
+
and is one of TCP or UDP, TCP being the default if
|
37
|
+
none is specified. For example:
|
38
|
+
$ #{command 'vps:firewall:open'} PORT=443
|
39
|
+
Is equivalent to:
|
40
|
+
$ #{command 'vps:firewall:open'} PORT=443:TCP
|
41
|
+
|
42
|
+
(optional) $FROM: the origin to grant access to. It can be either a
|
43
|
+
VPS identified by its hostname, or the Internet,
|
44
|
+
identified by #{q 'internet'}. Valid values
|
45
|
+
include:
|
46
|
+
FROM=internet # default
|
47
|
+
Or:
|
48
|
+
FROM=foo # VPS whose hostname is `foo'
|
49
|
+
|
50
|
+
(optional) $ID: the ID or hostname of the destination VPS.
|
51
|
+
Default: the newest VPS.
|
52
|
+
DESC
|
53
|
+
task :open do
|
54
|
+
vps = top.vps.fetch_current
|
55
|
+
port = ENV["PORT"] or error! <<-MSG
|
56
|
+
The destination port must be specified in the $PORT environment
|
57
|
+
variable, in the form of <port>[:<protocol>].
|
58
|
+
Examples: PORT=443, PORT=443:TCP, PORT=53:UDP
|
59
|
+
MSG
|
60
|
+
sources = (ENV['FROM'] || 'internet').split(',')
|
61
|
+
number, protocol = port.to_s.split(':')
|
62
|
+
protocol ||= 'TCP'
|
63
|
+
fwd = vps.port_forwardings.build :sources => sources, :to => number, :protocol => protocol
|
64
|
+
try_save fwd do
|
65
|
+
puts_title "Request sent"
|
66
|
+
puts "#{fwd.protocol.to_s.upcase} port #{fwd.to} has been scheduled for opening on VPS #{vps}."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
desc <<-DESC
|
71
|
+
List all firewall rules defined for a given VPS.
|
72
|
+
DESC
|
73
|
+
task :rules do
|
74
|
+
vps = top.vps.fetch_current
|
75
|
+
|
76
|
+
puts_title "Firewall rules for VPS #{q vps}"
|
77
|
+
puts_list vps.port_forwardings.all, :table => true do |t|
|
78
|
+
t.col("Service") { |f| f.service_name || "(#{f.protocol})" }
|
79
|
+
t.col("Sources") { |f| "{#{f.simplified_sources * ', '}}:#{f.from}" }
|
80
|
+
t.col("Destination") { |f| "#{f.target}:#{f.to}" }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
namespace :vps do
|
2
|
+
task(:default) { list }
|
3
|
+
import_pack(:connect, self, "VPS")
|
4
|
+
|
5
|
+
desc <<-DESC
|
6
|
+
Display a list of all your VPS's.
|
7
|
+
DESC
|
8
|
+
task :list do
|
9
|
+
puts_title "All VPS's"
|
10
|
+
puts_list VPS.all do |t|
|
11
|
+
t.col("Hostname", :hostname)
|
12
|
+
t.col("Memory capacity") { |s| "#{s.memory_capacity} MB" }
|
13
|
+
t.col("Disk capacity") { |s| "#{s.disk_capacity} GB" }
|
14
|
+
t.col("Status") { |s| s.status.to_s.capitalize }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc <<-DESC
|
19
|
+
Display a list of hostsnames of all your VPS's. Useful for refering to
|
20
|
+
these programmatically.
|
21
|
+
DESC
|
22
|
+
task :hostnames do
|
23
|
+
VPS.all.each { |vps| puts vps.hostname }
|
24
|
+
end
|
25
|
+
|
26
|
+
desc <<-DESC
|
27
|
+
List all users (UNIX accounts) that have a home folder.
|
28
|
+
DESC
|
29
|
+
task :users do
|
30
|
+
ENV['CMD'] = "ls /home | grep -v ^_"
|
31
|
+
run
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_current
|
35
|
+
(id = ENV["ID"] || ENV["ON"]) ? VPS.find(id) : VPS.last
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
namespace :webserver do
|
2
|
+
task(:default) { list }
|
3
|
+
import_pack(:connect, self, "webserver")
|
4
|
+
|
5
|
+
desc <<-DESC
|
6
|
+
List all webservers on either a particular VPS, or all VPS's.
|
7
|
+
|
8
|
+
Environment variables:
|
9
|
+
(optional) $ON: hostname of the VPS to list the webservers of.
|
10
|
+
Default: the newest VPS.
|
11
|
+
DESC
|
12
|
+
task :list do
|
13
|
+
puts_title "All webservers"
|
14
|
+
puts_list particular_set_of_webservers || Webserver.all, :title => :vps do |t|
|
15
|
+
t.col("Running on", :vps)
|
16
|
+
t.col("Running as", :user)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
desc <<-DESC
|
21
|
+
Make sure that at least one webserver is present. Failing that, one is set
|
22
|
+
up automatically on the newest VPS.
|
23
|
+
DESC
|
24
|
+
task :ensure_any do
|
25
|
+
if (count = Webserver.all.size).zero?
|
26
|
+
setup
|
27
|
+
else
|
28
|
+
puts_title "Webserver present"
|
29
|
+
puts "There exists #{count} webservers."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc <<-DESC
|
34
|
+
Set up a new webserver on a given VPS. Automatically installs and
|
35
|
+
configures the necessary software, running as its own UNIX user for
|
36
|
+
security purposes.
|
37
|
+
|
38
|
+
Environment variables:
|
39
|
+
(optional) $ON: hostname of the VPS to set up the webserver onto.
|
40
|
+
Default: the newest VPS.
|
41
|
+
DESC
|
42
|
+
task :setup do
|
43
|
+
vps = particular_vps || VPS.last
|
44
|
+
webserver = vps.webservers.build
|
45
|
+
|
46
|
+
try_save webserver do
|
47
|
+
puts_title "Request sent"
|
48
|
+
puts "Webserver successfully scheduled for setup on VPS #{q vps}."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc <<-DESC
|
53
|
+
Force the setup procedure of a webserver to be re-run. You might want to
|
54
|
+
do that if you think you messed up the automatic configuration, UNIX
|
55
|
+
account or software installations.
|
56
|
+
|
57
|
+
Environment variables:
|
58
|
+
(optional) $ID: the ID of the webserver (get the list with #{qcommand "webserver:list"}).
|
59
|
+
Default: the webserver last set up.
|
60
|
+
DESC
|
61
|
+
task :reprepare do
|
62
|
+
fetch_current.put(:reprepare)
|
63
|
+
puts_title "Request sent"
|
64
|
+
puts "Webserver has been scheduled for re-preparation."
|
65
|
+
end
|
66
|
+
|
67
|
+
desc <<-DESC
|
68
|
+
Force the reconfiguration of a webserver. You might want to do that if you
|
69
|
+
think you messed up the automatic configuration.
|
70
|
+
|
71
|
+
Environment variables:
|
72
|
+
(optional) $ID: the ID of the webserver (get the list with #{qcommand "webserver:list"}).
|
73
|
+
Default: the webserver last set up.
|
74
|
+
DESC
|
75
|
+
task :reconfigure do
|
76
|
+
fetch_current.put(:reconfigure)
|
77
|
+
puts_title "Request sent"
|
78
|
+
puts "Webserver has been scheduled for re-configuration."
|
79
|
+
end
|
80
|
+
|
81
|
+
desc <<-DESC
|
82
|
+
List all websites hosted by a given webserver. That is, websites served
|
83
|
+
via the webserver by having one of their backends running on the same VPS
|
84
|
+
as the webserver.
|
85
|
+
|
86
|
+
Environment variables:
|
87
|
+
$ID: the ID of the webserver (get the list with #{qcommand "webserver:list"}).
|
88
|
+
DESC
|
89
|
+
task :hosted do
|
90
|
+
webserver = fetch_current!
|
91
|
+
|
92
|
+
puts_title "Hosted websites"
|
93
|
+
top.website.backends.show_list(webserver.backends.all)
|
94
|
+
end
|
95
|
+
|
96
|
+
desc <<-DESC
|
97
|
+
Remove a webserver. This is accomplished by stopping all services run as
|
98
|
+
the UNIX user of the webserver, and then suppressing that user.
|
99
|
+
|
100
|
+
No data is lost: as with any automated suppression of a UNIX user, the
|
101
|
+
home folder is backed up at /home/_foo, where "foo" is the name newly
|
102
|
+
suppressed user.
|
103
|
+
|
104
|
+
The removal of a webserver is only allowed once all the backends of the
|
105
|
+
sites it serves have been removed (or switched webservers by way of
|
106
|
+
removal followed by re-creation). Get the list of all these remaining
|
107
|
+
backends with #{qcommand "webserver:hosted"}.
|
108
|
+
|
109
|
+
Environment variables:
|
110
|
+
$ID: the ID of the webserver (get the list with #{qcommand "webserver:list"}).
|
111
|
+
DESC
|
112
|
+
task :remove do
|
113
|
+
webserver = fetch_current!
|
114
|
+
|
115
|
+
begin
|
116
|
+
webserver.destroy
|
117
|
+
rescue WebService::ResourceConflict
|
118
|
+
error! $!.response.data['errors']
|
119
|
+
else
|
120
|
+
puts_title "Request sent"
|
121
|
+
puts "Webserver on VPS #{q webserver.vps} has been scheduled for removal."
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def require_id!
|
126
|
+
ENV["ID"] or
|
127
|
+
error! <<-MSG
|
128
|
+
The ID of the webserver to deal with must be specified by setting the
|
129
|
+
$ID environment variable. To list all webservers, run
|
130
|
+
#{qcommand "webserver:list"}.
|
131
|
+
MSG
|
132
|
+
end
|
133
|
+
|
134
|
+
def fetch_current
|
135
|
+
particular_webserver || Webserver.last
|
136
|
+
end
|
137
|
+
|
138
|
+
def fetch_current!
|
139
|
+
id = require_id!
|
140
|
+
Webserver.find(id)
|
141
|
+
end
|
142
|
+
|
143
|
+
def particular_vps
|
144
|
+
VPS.find(ENV["ON"]) if ENV["ON"]
|
145
|
+
end
|
146
|
+
|
147
|
+
def particular_webserver
|
148
|
+
Webserver.find(ENV["ID"]) if ENV["ID"]
|
149
|
+
end
|
150
|
+
|
151
|
+
def particular_set_of_webservers
|
152
|
+
vps = particular_vps and vps.webservers
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
namespace :website do
|
2
|
+
namespace :apptype do
|
3
|
+
desc <<-DESC
|
4
|
+
Change the application type of the website in the current working
|
5
|
+
directory.
|
6
|
+
|
7
|
+
When declaring a website, a type is (automatically or explicitely)
|
8
|
+
assigned to it. It is possible to change that initial choice with this
|
9
|
+
task:
|
10
|
+
$ cd path/to/foo
|
11
|
+
$ #{command "website:apptype:switch"} ID=custom
|
12
|
+
$ #{command "website:backends:reprepare"}
|
13
|
+
|
14
|
+
Environment variables:
|
15
|
+
$ID: the ID or short name of the application type to switch to.
|
16
|
+
DESC
|
17
|
+
task :switch do
|
18
|
+
website, type_id = fetch_current!, require_id!
|
19
|
+
|
20
|
+
website.app_type = AppType.find(type_id)
|
21
|
+
|
22
|
+
try_save website do
|
23
|
+
puts_title "Application type switched"
|
24
|
+
puts_long <<-MSG
|
25
|
+
* The application type of website #{q website} has been successfully
|
26
|
+
switched to #{q website.app_type}.
|
27
|
+
|
28
|
+
* Remember to re-reprepare all backends with
|
29
|
+
#{qcommand "website:backends:reprepare"}.
|
30
|
+
MSG
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def require_id!
|
35
|
+
ENV["ID"] || ENV["TO"] or
|
36
|
+
error! <<-MSG
|
37
|
+
The ID or short name of the application type to switch to must be
|
38
|
+
specified by setting the $ID environment variable.
|
39
|
+
MSG
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
namespace :website do
|
2
|
+
namespace :backends do
|
3
|
+
namespace :instances do
|
4
|
+
environment_variables = <<-EOS
|
5
|
+
Environment variables:
|
6
|
+
(optional) $ID: the ID of the backend to alter.
|
7
|
+
Default: the backend last added.
|
8
|
+
EOS
|
9
|
+
|
10
|
+
desc <<-DESC
|
11
|
+
Bump up the number of instances a backend. This adds one more process to
|
12
|
+
the backend, allowing for processing more requests per second, but also
|
13
|
+
consuming more memory.
|
14
|
+
|
15
|
+
The default is 1. This tasks increments the current number by 1.
|
16
|
+
|
17
|
+
#{environment_variables}
|
18
|
+
DESC
|
19
|
+
task :more do
|
20
|
+
backend = backends.fetch_current
|
21
|
+
backend.post(:instances)
|
22
|
+
puts "Number of instances of backend #{backend} scheduled for increase."
|
23
|
+
end
|
24
|
+
|
25
|
+
desc <<-DESC
|
26
|
+
Decrease the number of instances of a backend.
|
27
|
+
|
28
|
+
#{environment_variables}
|
29
|
+
DESC
|
30
|
+
task :less do
|
31
|
+
backend = backends.fetch_current
|
32
|
+
backend.delete(:instances)
|
33
|
+
puts "Number of instances of backend #{backend} scheduled for decrease."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
namespace :website do
|
2
|
+
namespace :backends do
|
3
|
+
# Allow for defining tasks named `test' and `try':
|
4
|
+
class << self
|
5
|
+
undef_method :test if private_method_defined? :test
|
6
|
+
undef_method :try if public_method_defined? :try
|
7
|
+
end
|
8
|
+
|
9
|
+
task(:default) { list }
|
10
|
+
import_pack(:connect, self, "backend")
|
11
|
+
|
12
|
+
desc <<-DESC
|
13
|
+
List all the backends currently running the site.
|
14
|
+
DESC
|
15
|
+
task :list do
|
16
|
+
site = website.fetch_current!
|
17
|
+
|
18
|
+
puts_title "Backends of website: #{site}"
|
19
|
+
show_list(site.backends.all)
|
20
|
+
end
|
21
|
+
|
22
|
+
desc <<-DESC
|
23
|
+
Prepare a VPS for hosting the current website. So is done by creating a
|
24
|
+
dedicated UNIX user to run the site as, enclosing processes related to
|
25
|
+
the site in a tight, secure environment. This prevents potential
|
26
|
+
security flaws to have an impact on other services run within the same
|
27
|
+
VPS.
|
28
|
+
|
29
|
+
Environment variables:
|
30
|
+
(optional) $ON: hostname of the VPS. Default: last webserver set up.
|
31
|
+
(optional) $AS: UNIX account to run the services as. Default: the
|
32
|
+
name of the website.
|
33
|
+
DESC
|
34
|
+
task :add do
|
35
|
+
site = website.fetch_current!
|
36
|
+
|
37
|
+
unless webserver = (ENV["ON"] ? (vps = VPS.find(ENV["ON"])).webservers : Webserver).last
|
38
|
+
message = vps ? "No webserver seems to be running on VPS #{q vps}." : "You have no webserver set up yet."
|
39
|
+
message << " Set one up first by running #{qcommand "webserver:setup"}."
|
40
|
+
error! message
|
41
|
+
end
|
42
|
+
|
43
|
+
# Backend: ties together the site to the webserver
|
44
|
+
backend = site.backends.build(:webserver => webserver, :user => ENV["AS"])
|
45
|
+
|
46
|
+
try_save backend do
|
47
|
+
puts_title "Request sent"
|
48
|
+
puts_long <<-INFO
|
49
|
+
* A new backend for website #{q site} has been scheduled for setup
|
50
|
+
on VPS #{q backend.vps}.
|
51
|
+
|
52
|
+
* If you are using an automatically generated Capfile, you should
|
53
|
+
download an updated version with #{qcommand "website:capfile:download"}.
|
54
|
+
|
55
|
+
* Once the new backend is ready (check that #{qcommand "progress"}
|
56
|
+
is at 100%), you should re-deploy to push the site to it. If you
|
57
|
+
are using a Capfile, this is done with #{q "cap deploy:setup"}
|
58
|
+
followed by #{q "cap deploy"}.
|
59
|
+
INFO
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
desc <<-DESC
|
64
|
+
Force a re-configuration of a backend. Checks the UNIX user,
|
65
|
+
re-generates configuration files and reloads the webserver's
|
66
|
+
configuration if necessary.
|
67
|
+
|
68
|
+
Environment variables:
|
69
|
+
(optional) $ID: the ID of a particular backend (get the list with
|
70
|
+
#{qcommand "website:backends:list"}).
|
71
|
+
|
72
|
+
Default: all backends of the current websites are
|
73
|
+
scheduled for reconfiguration.
|
74
|
+
DESC
|
75
|
+
task :reconfigure do
|
76
|
+
backends = fetch_several
|
77
|
+
|
78
|
+
puts_title "Sending requests"
|
79
|
+
backends.each do |backend|
|
80
|
+
backend.put(:reconfigure)
|
81
|
+
puts "Backend #{backend} has been scheduled for reconfiguration."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
desc <<-DESC
|
86
|
+
Force a re-preparation of a backend.
|
87
|
+
|
88
|
+
This re-runs the whole preparation process that was performed at
|
89
|
+
addition time. It's necessary to perform the preparation again when
|
90
|
+
switching application types of a website. For example:
|
91
|
+
$ cd path/to/foo
|
92
|
+
$ #{command "website:apptype:switch"} ID=custom
|
93
|
+
$ #{command "website:backends:reprepare"}
|
94
|
+
DESC
|
95
|
+
task :reprepare do
|
96
|
+
backends = fetch_several
|
97
|
+
|
98
|
+
puts_title "Sending requests"
|
99
|
+
backends.each do |backend|
|
100
|
+
backend.put(:reprepare)
|
101
|
+
puts "Backend #{backend} has been scheduled for re-preparation."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
task :test do
|
106
|
+
backend = fetch_current
|
107
|
+
execute = lambda { |command| top.webserver.connect.ssh_details_for(webserver).execute(command) }
|
108
|
+
|
109
|
+
# Check for errors during installations
|
110
|
+
puts_title "Installations"
|
111
|
+
none, display = true, lambda do |error, script_name|
|
112
|
+
begin
|
113
|
+
error = backend.send(error)
|
114
|
+
puts_subtitle "Error while executing #{q script_name}"
|
115
|
+
puts error.output
|
116
|
+
rescue WebService::ResourceNotFound
|
117
|
+
# ignore
|
118
|
+
else
|
119
|
+
none = false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
display[:root_install_error, 'root_install.sh']
|
123
|
+
display[:install_error, 'install.sh']
|
124
|
+
puts "No error occured during installations." if none
|
125
|
+
|
126
|
+
# Check syntax of webserver configuration file
|
127
|
+
puts_title "Webserver configuration"
|
128
|
+
webserver = backend.webserver
|
129
|
+
command = "/usr/sbin/nginx -c $HOME/webserver/nginx_main.conf -t"
|
130
|
+
top.webserver.connect.ssh_details_for(webserver).execute(command)
|
131
|
+
|
132
|
+
# Fetch the home page locally
|
133
|
+
puts_title "Home page (beginning)"
|
134
|
+
command = "wget -q -O - localhost:#{backend.port} | head -15"
|
135
|
+
top.website.backends.connect.ssh_details_for(backend).execute(command)
|
136
|
+
end
|
137
|
+
|
138
|
+
desc <<-DESC
|
139
|
+
Detect errors on service startup. Try to run the service script
|
140
|
+
(*_start.sh of the app. type) like the service manager would, in order
|
141
|
+
to spot errors output during startup, that would otherwise land in an
|
142
|
+
error log. Eases the task of debugging why an application progress
|
143
|
+
won't start like when forgetting to install a necessary RubyGem.
|
144
|
+
|
145
|
+
Environment variables:
|
146
|
+
(optional) $ID: the ID of the backend to try to start the service within.
|
147
|
+
Default: the backend last added.
|
148
|
+
DESC
|
149
|
+
task :try do
|
150
|
+
backend = fetch_current
|
151
|
+
|
152
|
+
if type = backend.website.app_type
|
153
|
+
type.service_configs.each do |service|
|
154
|
+
run = lambda { |cmd| connect.ssh_details_for(backend).execute(cmd) }
|
155
|
+
|
156
|
+
# Display service status
|
157
|
+
dir = "$HOME/service/#{backend.website.name}-#{service.name}-1"
|
158
|
+
run["sv status #{dir}"]
|
159
|
+
|
160
|
+
# Try to start the service in the foreground to spot errors on startup
|
161
|
+
command = "#{dir}/run"
|
162
|
+
command = "p=$$; ((sleep 2; kill $p) &); #{command}" # timeout
|
163
|
+
run[command]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
desc <<-DESC
|
169
|
+
Stop a backend and clear site-related files in a soft way.
|
170
|
+
|
171
|
+
All the files related to the associated website are not deleted, but
|
172
|
+
instead moved in a backup directory in the home folder of the backends's
|
173
|
+
UNIX account.
|
174
|
+
|
175
|
+
This UNIX account is then soft-cleared in a similar fashion. That is, it
|
176
|
+
is unregistered from the system, and its files are moved to a backup
|
177
|
+
directory under /home.
|
178
|
+
|
179
|
+
Example backup directory for a backend running as "foo":
|
180
|
+
/home/_foo
|
181
|
+
|
182
|
+
Example backup directory for a website named "bar" on this backend:
|
183
|
+
/home/_foo/_bar
|
184
|
+
|
185
|
+
That way, the VPS is kept in a clean state, and your files are still
|
186
|
+
available for you to get them back if you need them. This would most
|
187
|
+
likely be the case if the site accepts uploads stored on the filesystem,
|
188
|
+
in a subdirectory of the site's root, like RAILS_ROOT/public/images/ for
|
189
|
+
a Rails application, or wp-content/ for a WordPress blog.
|
190
|
+
|
191
|
+
Environment variables:
|
192
|
+
$ID: the ID of the backend to remove.
|
193
|
+
DESC
|
194
|
+
task :remove do
|
195
|
+
id = require_id!
|
196
|
+
|
197
|
+
website = top.website.fetch_current!
|
198
|
+
backend = website.backends.find(id)
|
199
|
+
|
200
|
+
if website.backends.all.size <= 1
|
201
|
+
confirm <<-WARN
|
202
|
+
You are about to remove the only backend left for this website. If
|
203
|
+
you do proceed with the removal, the site will become offline until
|
204
|
+
you set up a new one with #{qcommand "website:backends:add"} and
|
205
|
+
re-deploy.
|
206
|
+
WARN
|
207
|
+
end
|
208
|
+
|
209
|
+
backend.destroy
|
210
|
+
|
211
|
+
puts_title "Request sent"
|
212
|
+
puts_long <<-INFO
|
213
|
+
* Backend #{backend} has been scheduled for removal.
|
214
|
+
|
215
|
+
* If you are using the automatically generated Capfile, you should
|
216
|
+
download the updated version with #{qcommand "website:capfile:download"}.
|
217
|
+
INFO
|
218
|
+
end
|
219
|
+
|
220
|
+
def require_id!
|
221
|
+
ENV["ID"] or
|
222
|
+
error! <<-MSG
|
223
|
+
The ID of the backend to deal with must be specified by setting the
|
224
|
+
$ID environment variable. To list all backends of the current
|
225
|
+
website, run #{qcommand "website:backends"}.
|
226
|
+
MSG
|
227
|
+
end
|
228
|
+
|
229
|
+
def fetch_current!
|
230
|
+
id = require_id!
|
231
|
+
website.fetch_current!.backends.find(id)
|
232
|
+
end
|
233
|
+
|
234
|
+
def fetch_current
|
235
|
+
backends = website.fetch_current!.backends
|
236
|
+
(id = ENV["ID"]) ? backends.find(id) : backends.last
|
237
|
+
end
|
238
|
+
|
239
|
+
def fetch_several
|
240
|
+
backends = website.fetch_current!.backends
|
241
|
+
(id = ENV["ID"]) ? [backends.find(id)] : backends.all
|
242
|
+
end
|
243
|
+
|
244
|
+
def show_list(backends)
|
245
|
+
puts_list backends do |t|
|
246
|
+
t.col("Website") { |b| b.website.name }
|
247
|
+
t.col("Running on", :vps)
|
248
|
+
t.col("Running as", :user)
|
249
|
+
t.col("Instances", :num_instances)
|
250
|
+
t.col("Internal web port", :port)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|