Flucti-flucti-cli 0.1.16
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.
- 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
|