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,158 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :server do
|
3
|
+
task(:default) { list }
|
4
|
+
import_pack(:connect, self, "database server")
|
5
|
+
|
6
|
+
desc <<-DESC
|
7
|
+
List all database servers.
|
8
|
+
DESC
|
9
|
+
task :list do
|
10
|
+
puts_title "Database servers"
|
11
|
+
puts_list DbServer.all do |t|
|
12
|
+
t.col("Host") { |s| s.vps.hostname }
|
13
|
+
t.col("Port", :port)
|
14
|
+
t.col("Running as", :user)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc <<-DESC
|
19
|
+
Set up a new MySQL database server on a certain VPS.
|
20
|
+
|
21
|
+
Environment variables:
|
22
|
+
(optional) $ON: the ID or hostname of the VPS to set up the server
|
23
|
+
onto.
|
24
|
+
Default: the newest VPS.
|
25
|
+
DESC
|
26
|
+
task :setup do
|
27
|
+
vps = fetch_vps
|
28
|
+
|
29
|
+
db_server = vps.db_servers.build
|
30
|
+
try_save db_server do
|
31
|
+
puts_title "Request sent"
|
32
|
+
puts "Database server successfully scheduled for setup on #{q vps}."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc <<-DESC
|
37
|
+
Display the root credentials. One can only connect as root to 127.0.0.1
|
38
|
+
so commands that require root privilege must be executed directly on the
|
39
|
+
database server VPS, not any another one.
|
40
|
+
|
41
|
+
For example:
|
42
|
+
$ #{command 'db:server:root'}
|
43
|
+
$ #{command 'db:server:enter'}
|
44
|
+
> env HISTFILE= mysql -h 127.0.0.1 -u root-1a28 -p'f6561b' foo -e 'SHOW TABLES'
|
45
|
+
|
46
|
+
The above is actually equivalent to:
|
47
|
+
$ #{command 'db:server:run'} DB=foo Q='SHOW TABLES'
|
48
|
+
|
49
|
+
Environment variables:
|
50
|
+
(optional) $ID: the ID of the server to display the root credentials of.
|
51
|
+
Default: the last server set up.
|
52
|
+
DESC
|
53
|
+
task :root do
|
54
|
+
server = fetch_current
|
55
|
+
root = server.root
|
56
|
+
puts_long <<-EOS
|
57
|
+
* Host: 127.0.0.1
|
58
|
+
* Login: #{root.login}
|
59
|
+
* Password: #{root.password}
|
60
|
+
|
61
|
+
Query execution:
|
62
|
+
$ #{root.command_for_display '<database>', '<command>'}
|
63
|
+
EOS
|
64
|
+
end
|
65
|
+
|
66
|
+
desc <<-DESC
|
67
|
+
Quick way to run a query as root on a database server.
|
68
|
+
|
69
|
+
Example usage:
|
70
|
+
$ #{command "db:server:run"} Q="SHOW DATABASES"
|
71
|
+
|
72
|
+
Environment variables:
|
73
|
+
(optional) $ID: the ID of the server to run the query in.
|
74
|
+
Default: the last server set up.
|
75
|
+
DESC
|
76
|
+
task :run do
|
77
|
+
server = fetch_current
|
78
|
+
|
79
|
+
queries = ENV["Q"] || (!$stdin.tty? and $stdin.read) or error! <<-MSG
|
80
|
+
Specify the query(ies) to execute either in the $Q environment
|
81
|
+
variable or through STDIN.
|
82
|
+
MSG
|
83
|
+
db = ENV["DB"]
|
84
|
+
|
85
|
+
root = server.root
|
86
|
+
command = root.command(db, queries)
|
87
|
+
|
88
|
+
server.vps.ssh_details.as(server.user).run(command)
|
89
|
+
end
|
90
|
+
|
91
|
+
desc <<-DESC
|
92
|
+
List all the databases hosted on a certain server.
|
93
|
+
|
94
|
+
Environment variables:
|
95
|
+
(optional) $ID: the ID of the server to list the databases from.
|
96
|
+
Default: the last server set up.
|
97
|
+
DESC
|
98
|
+
task :databases do
|
99
|
+
ENV["Q"] = "SHOW DATABASES"
|
100
|
+
run
|
101
|
+
end
|
102
|
+
|
103
|
+
desc <<-DESC
|
104
|
+
Remove a database server. So is done by stopping the daemon and
|
105
|
+
soft-clearing all of the related files.
|
106
|
+
|
107
|
+
That is, for a database server run as a UNIX account named `mysql', the
|
108
|
+
`mysql' account is removed, but the files are kept in /home/_mysql.
|
109
|
+
|
110
|
+
Environment variables:
|
111
|
+
(optional) $ID: the ID of the server to remove.
|
112
|
+
Default: the last server set up.
|
113
|
+
DESC
|
114
|
+
task :remove do
|
115
|
+
server = fetch_current
|
116
|
+
server.destroy
|
117
|
+
puts_long <<-MSG
|
118
|
+
Database server #{q server} successfully scheduled for removal.
|
119
|
+
MSG
|
120
|
+
end
|
121
|
+
|
122
|
+
def fetch_current
|
123
|
+
(id = ENV["ID"]) ? DbServer.find(id) : DbServer.last
|
124
|
+
end
|
125
|
+
|
126
|
+
def fetch_vps
|
127
|
+
(id = ENV["ON"]) ? VPS.find(id) : VPS.last
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
desc <<-DESC
|
132
|
+
Create a new database on a certain server. Once created, you will receive
|
133
|
+
the credentials via e-mail.
|
134
|
+
|
135
|
+
Example usage:
|
136
|
+
$ #{command "db:create"} NAME=foo
|
137
|
+
|
138
|
+
Environment variables:
|
139
|
+
(optional) $ID: the ID of the database server to create the database on.
|
140
|
+
Default: the server last set up.
|
141
|
+
DESC
|
142
|
+
task :create do
|
143
|
+
name = ENV["NAME"] or error! <<-MSG
|
144
|
+
The name of the database to create must be specified in the $NAME
|
145
|
+
environment variable.
|
146
|
+
MSG
|
147
|
+
server = (id = ENV["ID"]) ? DbServer.find(id) : DbServer.last
|
148
|
+
db = server.databases.build :name => name
|
149
|
+
|
150
|
+
try_save db do
|
151
|
+
puts_title "Request sent"
|
152
|
+
puts_long <<-MSG
|
153
|
+
Database #{q db} successfully created on #{q server}. Check your
|
154
|
+
e-mails for the connection details, including the credentials.
|
155
|
+
MSG
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
namespace :mail do
|
2
|
+
namespace :server do
|
3
|
+
task(:default) { list }
|
4
|
+
|
5
|
+
desc <<-DESC
|
6
|
+
List all VPS's acting as outgoing mail servers.
|
7
|
+
DESC
|
8
|
+
task :list do
|
9
|
+
puts_title "Mail servers"
|
10
|
+
puts_list MailServer.all, :id => false, :table => true do |t|
|
11
|
+
t.col("Host", :host)
|
12
|
+
t.col("Port", :port)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc <<-DESC
|
17
|
+
Set up an outgoing (SMTP) mail server on a VPS.
|
18
|
+
|
19
|
+
ATTENTION: Outgoing mail servers, like their name suggests, can only
|
20
|
+
send e-mails out and cannot receive any. As a consequence,
|
21
|
+
that they cannot be used as public Internet MX hosts (yet).
|
22
|
+
|
23
|
+
After the setup has completed, you will be able to send out e-mails from
|
24
|
+
the mail server VPS in addition to any VPS configured as mail client of
|
25
|
+
that mail server (see #{qcommand "mail:client:setup"}). From these
|
26
|
+
VPS's, e-mails can be sent with for example:
|
27
|
+
|
28
|
+
* Out-of-the-box:
|
29
|
+
- PHP's mail() function,
|
30
|
+
- Rails mailers (ActionMailer subclasses),
|
31
|
+
- the #{q "sendmail"} command,
|
32
|
+
- any other way that eventually relies on sendmail.
|
33
|
+
|
34
|
+
* Any method that relies on SMTP, after configuring SMTP connection
|
35
|
+
details based on the output of #{qcommand 'mail:server:list'}.
|
36
|
+
|
37
|
+
Environment variables:
|
38
|
+
(optional) $ON: the hostname of the VPS to set up the mail server on.
|
39
|
+
Default: the newest VPS.
|
40
|
+
DESC
|
41
|
+
task :setup do
|
42
|
+
confirm <<-WARN
|
43
|
+
Any previously installed MTA (Mail Transfer Agent) will be removed
|
44
|
+
prior to configuring the new mail server.
|
45
|
+
WARN
|
46
|
+
|
47
|
+
vps = mail.fetch_target_vps
|
48
|
+
mail_server = vps.build_mail_server
|
49
|
+
|
50
|
+
try_save mail_server do
|
51
|
+
puts_title "Request sent"
|
52
|
+
puts "Mail server has been scheduled for setup on VPS #{q vps}."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
namespace :client do
|
58
|
+
desc <<-DESC
|
59
|
+
Configure a mail client on a VPS. This will enable e-mail sending via
|
60
|
+
a previously configured mail server on another VPS (see #{qcommand \
|
61
|
+
'mail:server:setup'}.
|
62
|
+
|
63
|
+
For example, given a VPS `foo' and a VPS `bar':
|
64
|
+
$ #{command 'mail:server:setup'} ON=foo
|
65
|
+
$ #{command 'mail:client:setup'} ON=bar
|
66
|
+
|
67
|
+
Environment variables:
|
68
|
+
(optional) $ON: the ID or hostname of the VPS to configure the mail
|
69
|
+
client on.
|
70
|
+
Default: the newest VPS.
|
71
|
+
|
72
|
+
(optional) $OF or $SERVER: the ID or hostname of the mail server VPS
|
73
|
+
that the client is to send e-mails
|
74
|
+
through.
|
75
|
+
Default: the mail server last set up.
|
76
|
+
DESC
|
77
|
+
task :setup do
|
78
|
+
id = ENV["SERVER"] || ENV["OF"]
|
79
|
+
unless server = id ? MailServer.find(id) : MailServer.last
|
80
|
+
error! <<-MSG
|
81
|
+
There is no mail server set up yet. To remedy this situation,
|
82
|
+
execute the following command:
|
83
|
+
$ #{command 'mail:server:setup'}
|
84
|
+
MSG
|
85
|
+
end
|
86
|
+
|
87
|
+
server = server.vps
|
88
|
+
client = mail.fetch_target_vps
|
89
|
+
|
90
|
+
mail_client = client.build_mail_client(:server => server)
|
91
|
+
|
92
|
+
try_save mail_client do
|
93
|
+
puts_title "Request sent"
|
94
|
+
puts_long <<-MSG
|
95
|
+
Mail client of #{q server} successfully scheduled for setup on #{q client}.
|
96
|
+
MSG
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def fetch_target_vps
|
102
|
+
ENV["ON"] ? VPS.find(ENV["ON"]) : VPS.last
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
desc <<-DESC
|
2
|
+
Show a progress-bar for in-progress operations. Blocks until 100% is
|
3
|
+
reached.
|
4
|
+
|
5
|
+
When you create, alter or delete an entity, resulting in operations
|
6
|
+
necessary for the changes to take effect, like software installation and/or
|
7
|
+
configuration -- be it on one or several of your VPS's, and/or in our
|
8
|
+
registries -- these operations are started processing in the background on
|
9
|
+
our end.
|
10
|
+
|
11
|
+
This task lets you know how much of these are left to do (roughly), and when
|
12
|
+
they are all done (accurately).
|
13
|
+
DESC
|
14
|
+
task :progress do
|
15
|
+
key, bar = nil, Utilities::ProgressBar.new("Progress", 100, $stdout)
|
16
|
+
loop do
|
17
|
+
progress = Progress.first(:key => key)
|
18
|
+
bar.set(progress.percent)
|
19
|
+
break if progress.percent >= 100
|
20
|
+
key = progress.key
|
21
|
+
sleep 2
|
22
|
+
end
|
23
|
+
bar.finish
|
24
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
namespace :sshkey do
|
2
|
+
class PublicKeyPathNotFound < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
task(:default) { list }
|
6
|
+
|
7
|
+
desc <<-DESC
|
8
|
+
List all registered SSH keys.
|
9
|
+
DESC
|
10
|
+
task :list do
|
11
|
+
puts_title "Registered SSH keys"
|
12
|
+
puts_list SshKey.all, :table => true do |t|
|
13
|
+
t.col("Public key") { |k| k.public_key.to_s[0, 50] + '...' }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
registration_env_vars = <<-DESC
|
18
|
+
Environment variables:
|
19
|
+
(optional) $FILE: path/to/id_{rsa,dsa}.pub
|
20
|
+
Default: your public key is searched
|
21
|
+
for at the usual locations.
|
22
|
+
|
23
|
+
(optional) STDIN: the public key can be fed through STDIN instead of by
|
24
|
+
path. Example:
|
25
|
+
$ #{command "sshkey:register"} < path/to/the/key.pub
|
26
|
+
DESC
|
27
|
+
|
28
|
+
desc <<-DESC
|
29
|
+
Register your public SSH key. You can register more than one. Doing so
|
30
|
+
grants you password-less SSH/SFTP/SCP access to all UNIX accounts created
|
31
|
+
either automatically or manually via #{qcommand "vps:user:add"}.
|
32
|
+
|
33
|
+
Upon registration, the new key will be granted access all UNIX accounts of
|
34
|
+
all your VPS's (actually, only the ones that have a home folder). It will
|
35
|
+
also automatically be granted access to UNIX accounts created later.
|
36
|
+
|
37
|
+
#{registration_env_vars}
|
38
|
+
DESC
|
39
|
+
task :register do
|
40
|
+
current_key = local_key!
|
41
|
+
|
42
|
+
puts_title "Registering SSH key"
|
43
|
+
puts "Public key at: #{current_key}"
|
44
|
+
|
45
|
+
key = SshKey.new :public_key => current_key.read
|
46
|
+
try_save key do
|
47
|
+
puts_title "SSH key registered"
|
48
|
+
puts(key.public_key)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc <<-DESC
|
53
|
+
Make sure that your public key is registered; register it otherwise. If
|
54
|
+
you don't have a pair of keys (private and public) yet, one is attempted
|
55
|
+
to be generated for you at ~/.ssh.
|
56
|
+
|
57
|
+
If even the generation failed, all UNIX accounts are switched to password
|
58
|
+
mode. In this mode, each time an account is created, a password is
|
59
|
+
generated for you to log in with. At creation time, an e-mail is sent to
|
60
|
+
you containing SSH connection details, including the generated password.
|
61
|
+
|
62
|
+
#{registration_env_vars}
|
63
|
+
DESC
|
64
|
+
task :ensure_registered do
|
65
|
+
begin
|
66
|
+
current_key = local_key
|
67
|
+
rescue PublicKeyPathNotFound
|
68
|
+
if system("which ssh-keygen")
|
69
|
+
sh %{echo | ssh-keygen -t dsa -P ''}
|
70
|
+
register
|
71
|
+
else
|
72
|
+
Account.put(:password_auth)
|
73
|
+
error! <<-MSG
|
74
|
+
You do not appear to already have an SSH key pair present at the
|
75
|
+
regular location. One has been attempted to be generated for you but
|
76
|
+
the #{q "ssh-keygen"} was missing.
|
77
|
+
|
78
|
+
As a consequence, password-authentication have been enabled so that
|
79
|
+
you can connect to each account on your VPS's using passwords
|
80
|
+
instead of a public key.
|
81
|
+
|
82
|
+
Also, whenever the #{q "ssh"} is supposed to be executed, you will
|
83
|
+
be presented with connections details for use in a graphical client
|
84
|
+
application such as PuTTy and WinSCP (for Windows).
|
85
|
+
MSG
|
86
|
+
end
|
87
|
+
else
|
88
|
+
puts_title "Status of your public key"
|
89
|
+
begin
|
90
|
+
SshKey.create :public_key => current_key.read
|
91
|
+
rescue WebService::ResourceInvalid
|
92
|
+
puts "The public key of the current user (#{ENV['USER']}) is registered."
|
93
|
+
else
|
94
|
+
puts "The public key of the current user (#{ENV['USER']}) has been registered successfully."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
desc <<-DESC
|
100
|
+
Unregister a key. It will be revoked access from all UNIX accounts it is
|
101
|
+
currently granted access to, and won't be automatically granted access to
|
102
|
+
the UNIX account of new website backends anymore.
|
103
|
+
|
104
|
+
Environment variables:
|
105
|
+
$ID: the ID of the key to unregister (get the list with #{qcommand "sshkey:list"}).
|
106
|
+
DESC
|
107
|
+
task :unregister do
|
108
|
+
id = require_id!
|
109
|
+
|
110
|
+
SshKey.delete(id)
|
111
|
+
puts_title "Request sent"
|
112
|
+
puts "SSH key successfully scheduled for unregistration."
|
113
|
+
end
|
114
|
+
|
115
|
+
def require_id!
|
116
|
+
ENV["ID"] or
|
117
|
+
error! <<-MSG
|
118
|
+
The ID of the key to deal with must be specified by setting the ID
|
119
|
+
environment variable. To list all registered SSH keys, run
|
120
|
+
#{qcommand "sshkey:list"}.
|
121
|
+
MSG
|
122
|
+
end
|
123
|
+
|
124
|
+
def local_key!
|
125
|
+
local_key
|
126
|
+
rescue PublicKeyPathNotFound
|
127
|
+
error! $!.message
|
128
|
+
end
|
129
|
+
|
130
|
+
def local_key
|
131
|
+
if !$stdin.tty?
|
132
|
+
file = STDINWrapper.new
|
133
|
+
elsif path = ENV["FILE"]
|
134
|
+
file = Pathname(path)
|
135
|
+
raise PublicKeyPathNotFound, "No such file: #{path}." unless file.file?
|
136
|
+
else
|
137
|
+
file = Pathname.glob("{.,#{ENV['HOME']}/.{ssh,ssh2}}/id_{dsa,rsa}.pub{,.txt}").first
|
138
|
+
end
|
139
|
+
file or raise PublicKeyPathNotFound, "Could not guess the path of your public SSH key."
|
140
|
+
end
|
141
|
+
|
142
|
+
class STDINWrapper
|
143
|
+
def to_s
|
144
|
+
"STDIN"
|
145
|
+
end
|
146
|
+
|
147
|
+
def read
|
148
|
+
$stdin.gets
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|