mailshears 0.0.1
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.
- checksums.yaml +7 -0
- data/Rakefile +32 -0
- data/bin/install-fixtures.sh +27 -0
- data/bin/mailshears +124 -0
- data/doc/LICENSE +661 -0
- data/doc/TODO +16 -0
- data/doc/mailshears.example.conf.yml +37 -0
- data/doc/man1/mailshears.1 +184 -0
- data/lib/common/agendav_plugin.rb +54 -0
- data/lib/common/configuration.rb +116 -0
- data/lib/common/davical_plugin.rb +104 -0
- data/lib/common/domain.rb +64 -0
- data/lib/common/dovecot_plugin.rb +130 -0
- data/lib/common/errors.rb +15 -0
- data/lib/common/exit_codes.rb +9 -0
- data/lib/common/filesystem.rb +43 -0
- data/lib/common/plugin.rb +238 -0
- data/lib/common/postfixadmin_plugin.rb +180 -0
- data/lib/common/roundcube_plugin.rb +96 -0
- data/lib/common/runner.rb +73 -0
- data/lib/common/user.rb +120 -0
- data/lib/common/user_interface.rb +53 -0
- data/lib/mailshears.rb +7 -0
- data/lib/mv/mv_dummy_runner.rb +45 -0
- data/lib/mv/mv_plugin.rb +40 -0
- data/lib/mv/mv_runner.rb +56 -0
- data/lib/mv/plugins/agendav.rb +46 -0
- data/lib/mv/plugins/davical.rb +43 -0
- data/lib/mv/plugins/dovecot.rb +64 -0
- data/lib/mv/plugins/postfixadmin.rb +70 -0
- data/lib/mv/plugins/roundcube.rb +44 -0
- data/lib/prune/plugins/agendav.rb +13 -0
- data/lib/prune/plugins/davical.rb +13 -0
- data/lib/prune/plugins/dovecot.rb +11 -0
- data/lib/prune/plugins/postfixadmin.rb +13 -0
- data/lib/prune/plugins/roundcube.rb +14 -0
- data/lib/prune/prune_dummy_runner.rb +44 -0
- data/lib/prune/prune_plugin.rb +66 -0
- data/lib/prune/prune_runner.rb +34 -0
- data/lib/rm/plugins/agendav.rb +38 -0
- data/lib/rm/plugins/davical.rb +38 -0
- data/lib/rm/plugins/dovecot.rb +48 -0
- data/lib/rm/plugins/postfixadmin.rb +114 -0
- data/lib/rm/plugins/roundcube.rb +42 -0
- data/lib/rm/rm_dummy_runner.rb +39 -0
- data/lib/rm/rm_plugin.rb +77 -0
- data/lib/rm/rm_runner.rb +51 -0
- data/mailshears.gemspec +39 -0
- data/test/mailshears.test.conf.yml +36 -0
- data/test/mailshears_test.rb +250 -0
- data/test/sql/agendav-fixtures.sql +9 -0
- data/test/sql/agendav.sql +157 -0
- data/test/sql/davical-fixtures.sql +23 -0
- data/test/sql/davical.sql +4371 -0
- data/test/sql/postfixadmin-fixtures.sql +48 -0
- data/test/sql/postfixadmin.sql +737 -0
- data/test/sql/roundcube-fixtures.sql +4 -0
- data/test/sql/roundcube.sql +608 -0
- data/test/test_mv.rb +174 -0
- data/test/test_prune.rb +121 -0
- data/test/test_rm.rb +154 -0
- metadata +133 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'prune/prune_plugin'
|
4
|
+
require 'rm/plugins/agendav'
|
5
|
+
|
6
|
+
# Handle the pruning of Agendav users from its database. This class
|
7
|
+
# doesn't need to do anything; by inheriting from {AgendavRm}, we get
|
8
|
+
# its {AgendavRm#remove_user} method and that's all we need to prune.
|
9
|
+
#
|
10
|
+
class AgendavPrune < AgendavRm
|
11
|
+
# Needed for the magic includers <tt>run()</tt> method.
|
12
|
+
include PrunePlugin
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'prune/prune_plugin'
|
4
|
+
require 'rm/plugins/davical'
|
5
|
+
|
6
|
+
# Handle the pruning of DAViCal users from its database. This class
|
7
|
+
# doesn't need to do anything; by inheriting from {DavicalRm}, we get
|
8
|
+
# its {DavicalRm#remove_user} method and that's all we need to prune.
|
9
|
+
#
|
10
|
+
class DavicalPrune < DavicalRm
|
11
|
+
# Needed for the magic includers <tt>run()</tt> method.
|
12
|
+
include PrunePlugin
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'prune/prune_plugin'
|
2
|
+
require 'rm/plugins/dovecot'
|
3
|
+
|
4
|
+
# Handle the pruning of Dovecot users from its database. This class
|
5
|
+
# doesn't need to do anything; by inheriting from {DovecotRm}, we get
|
6
|
+
# its {DovecotRm#remove_user} method and that's all we need to prune.
|
7
|
+
#
|
8
|
+
class DovecotPrune < DovecotRm
|
9
|
+
# Needed for the magic includers <tt>run()</tt> method.
|
10
|
+
include PrunePlugin
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'prune/prune_plugin'
|
2
|
+
require 'rm/plugins/postfixadmin'
|
3
|
+
|
4
|
+
# This class does absolutely nothing except allow us to blindly
|
5
|
+
# instantiate classes based on the mode name and configured plugins.
|
6
|
+
#
|
7
|
+
# We don't need the ability to remove "left over" Postfixadmin users
|
8
|
+
# or domains, since "left over" is with respect to what's in
|
9
|
+
# Postfixadmin itself. The other pruning plugins check themselves
|
10
|
+
# against Postfixadmin -- it doesn't make sense to check Postfixadmin
|
11
|
+
# against itself.
|
12
|
+
#
|
13
|
+
class PostfixadminPrune < PostfixadminRm; end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'prune/prune_plugin'
|
4
|
+
require 'rm/plugins/roundcube'
|
5
|
+
|
6
|
+
|
7
|
+
# Handle the pruning of Roundcube users from its database. This class
|
8
|
+
# doesn't need to do anything; by inheriting from {RoundcubeRm}, we get
|
9
|
+
# its {RoundcubeRm#remove_user} method and that's all we need to prune.
|
10
|
+
#
|
11
|
+
class RoundcubePrune < RoundcubeRm
|
12
|
+
# Needed for the magic includers <tt>run()</tt> method.
|
13
|
+
include PrunePlugin
|
14
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'common/runner'
|
2
|
+
require 'prune/plugins/postfixadmin'
|
3
|
+
require 'rm/rm_dummy_runner'
|
4
|
+
|
5
|
+
# Dummy implementation of a {PruneRunner}. Its <tt>run()</tt> method will
|
6
|
+
# tell you what would have been pruned, but will not actually perform
|
7
|
+
# the operation.
|
8
|
+
#
|
9
|
+
class PruneDummyRunner
|
10
|
+
include Runner
|
11
|
+
|
12
|
+
|
13
|
+
# Pretend to prune unused domains and users. Some "what if"
|
14
|
+
# information will be output to stdout.
|
15
|
+
#
|
16
|
+
# The prune mode is the main application of the "dummy" runners,
|
17
|
+
# since it performs some computation outside of the plugins
|
18
|
+
# themselves. This lets the user know which users and domains would
|
19
|
+
# be removed and can help prevent mistakes or even find bugs in the
|
20
|
+
# prune code, if it looks like something will be removed that
|
21
|
+
# shouldn't be!
|
22
|
+
#
|
23
|
+
# @param cfg [Configuration] the configuration options to pass to
|
24
|
+
# the *plugin* we're runnning.
|
25
|
+
#
|
26
|
+
# @param plugin [Class] plugin class that will do the pruning.
|
27
|
+
#
|
28
|
+
def run(cfg, plugin)
|
29
|
+
# We don't want to check the PostfixAdmin database against itself.
|
30
|
+
return if plugin.class == PostfixadminPrune
|
31
|
+
|
32
|
+
pfa = PostfixadminPrune.new(cfg)
|
33
|
+
|
34
|
+
db_users = pfa.list_users()
|
35
|
+
db_domains = pfa.list_domains()
|
36
|
+
|
37
|
+
leftovers = plugin.get_leftover_users(db_users)
|
38
|
+
leftovers += plugin.get_leftover_domains(db_domains)
|
39
|
+
|
40
|
+
rm_dummy_runner = RmDummyRunner.new()
|
41
|
+
rm_dummy_runner.run(cfg, plugin, *leftovers)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'common/plugin.rb'
|
2
|
+
|
3
|
+
# Plugins for pruning users. By "pruning," we mean the removal of
|
4
|
+
# leftover non-PostfixAdmin users after the associated user has been
|
5
|
+
# removed from the Postfixadmin database.
|
6
|
+
#
|
7
|
+
module PrunePlugin
|
8
|
+
|
9
|
+
# Absorb the subclass run() magic from the Plugin::Run module.
|
10
|
+
extend Plugin::Run
|
11
|
+
|
12
|
+
# The runner class associated with pruning plugins.
|
13
|
+
#
|
14
|
+
# @return [Class] the {PruneRunner} class.
|
15
|
+
#
|
16
|
+
def self.runner()
|
17
|
+
return PruneRunner
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# The "dummy" runner class associated with pruning plugins.
|
22
|
+
#
|
23
|
+
# @return [Class] the {PruneDummyRunner} class.
|
24
|
+
#
|
25
|
+
def self.dummy_runner
|
26
|
+
return PruneDummyRunner
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# Determine which domains are "left over" for this plugin. A domain
|
31
|
+
# is considered "left over" if it has been removed from Postfixadmin
|
32
|
+
# but not some other plugin.
|
33
|
+
#
|
34
|
+
# The leftovers are determined with respect to the list *db_domains*
|
35
|
+
# of domains that Postfixadmin knows about.
|
36
|
+
#
|
37
|
+
# @param db_domains [Array<Domain>] a list of domains that are present
|
38
|
+
# in the Postfixadmin database.
|
39
|
+
#
|
40
|
+
# @return [Array<Domain>] a list of domains known to this plugin but
|
41
|
+
# not to Postfixadmin.
|
42
|
+
#
|
43
|
+
def get_leftover_domains(db_domains)
|
44
|
+
# WARNING! Array difference doesn't work for some reason.
|
45
|
+
return list_domains().select{ |d| !db_domains.include?(d) }
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Determine which users are "left over" for this plugin. A user
|
50
|
+
# is considered "left over" if it has been removed from Postfixadmin
|
51
|
+
# but not some other plugin.
|
52
|
+
#
|
53
|
+
# The leftovers are determined with respect to the list *db_users*
|
54
|
+
# of users that Postfixadmin knows about.
|
55
|
+
#
|
56
|
+
# @param db_users [Array<User>] a list of users that are present
|
57
|
+
# in the Postfixadmin database.
|
58
|
+
#
|
59
|
+
# @return [Array<User>] a list of users known to this plugin but
|
60
|
+
# not to Postfixadmin.
|
61
|
+
#
|
62
|
+
def get_leftover_users(db_users)
|
63
|
+
# WARNING! Array difference doesn't work for some reason.
|
64
|
+
return list_users().select{ |u| !db_users.include?(u) }
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'common/runner'
|
2
|
+
require 'prune/plugins/postfixadmin'
|
3
|
+
require 'rm/rm_runner'
|
4
|
+
|
5
|
+
# Perform the pruning of users/domains using {PrunePlugin}s.
|
6
|
+
#
|
7
|
+
class PruneRunner
|
8
|
+
include Runner
|
9
|
+
|
10
|
+
# Run *plugin* to prune leftover users and directories.
|
11
|
+
#
|
12
|
+
# @param cfg [Configuration] configuration options passed to
|
13
|
+
# {PostfixadminPrune}.
|
14
|
+
#
|
15
|
+
# @param plugin [Class] plugin class that will perform the pruning.
|
16
|
+
#
|
17
|
+
def run(cfg, plugin)
|
18
|
+
# We don't want to check the PostfixAdmin database against itself.
|
19
|
+
return if plugin.class == PostfixadminPrune
|
20
|
+
|
21
|
+
pfa = PostfixadminPrune.new(cfg)
|
22
|
+
|
23
|
+
db_users = pfa.list_users()
|
24
|
+
db_domains = pfa.list_domains()
|
25
|
+
|
26
|
+
leftovers = plugin.get_leftover_users(db_users)
|
27
|
+
leftovers += plugin.get_leftover_domains(db_domains)
|
28
|
+
|
29
|
+
# We're counting on our PrunePlugin also being an RmPlugin here.
|
30
|
+
rm_runner = RmRunner.new()
|
31
|
+
rm_runner.run(cfg, plugin, *leftovers)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'common/agendav_plugin'
|
4
|
+
require 'rm/rm_plugin'
|
5
|
+
|
6
|
+
|
7
|
+
# Handle the removal of Agendav users from its database. Agendav has
|
8
|
+
# no concept of domains.
|
9
|
+
#
|
10
|
+
class AgendavRm
|
11
|
+
|
12
|
+
include AgendavPlugin
|
13
|
+
include RmPlugin
|
14
|
+
|
15
|
+
|
16
|
+
# Remove *user* from the Agendav database. This should remove him
|
17
|
+
# from _every_ table in which he is referenced.
|
18
|
+
#
|
19
|
+
# @param user [User] the user to remove.
|
20
|
+
#
|
21
|
+
def remove_user(user)
|
22
|
+
raise NonexistentUserError.new(user.to_s()) if not user_exists(user)
|
23
|
+
|
24
|
+
sql_queries = ['DELETE FROM prefs WHERE username = $1;']
|
25
|
+
sql_queries << 'DELETE FROM shared WHERE user_from = $1;'
|
26
|
+
|
27
|
+
connection = PG::Connection.new(@db_hash)
|
28
|
+
begin
|
29
|
+
sql_queries.each do |sql_query|
|
30
|
+
connection.query(sql_query, [user.to_s()])
|
31
|
+
end
|
32
|
+
ensure
|
33
|
+
# Make sure the connection gets closed even if a query explodes.
|
34
|
+
connection.close()
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'common/davical_plugin'
|
4
|
+
require 'rm/rm_plugin'
|
5
|
+
|
6
|
+
# Handle the removal of DAViCal users from its database. DAViCal has
|
7
|
+
# no concept of domains.
|
8
|
+
#
|
9
|
+
class DavicalRm
|
10
|
+
|
11
|
+
include DavicalPlugin
|
12
|
+
include RmPlugin
|
13
|
+
|
14
|
+
|
15
|
+
# Remove *user* from the DAViCal database. This should remove him
|
16
|
+
# from _every_ table in which he is referenced. Fortunately, DAViCal
|
17
|
+
# uses foreign keys properly (and only supports postgres, where they
|
18
|
+
# work!), so we can let the ON DELETE CASCADE trigger handle most of
|
19
|
+
# the work.
|
20
|
+
#
|
21
|
+
# @param user [User] the user to remove.
|
22
|
+
#
|
23
|
+
def remove_user(user)
|
24
|
+
raise NonexistentUserError.new(user.to_s()) if not user_exists(user)
|
25
|
+
|
26
|
+
sql_query = 'DELETE FROM usr WHERE username = $1;'
|
27
|
+
|
28
|
+
connection = PG::Connection.new(@db_hash)
|
29
|
+
begin
|
30
|
+
connection.query(sql_query, [user.to_s()])
|
31
|
+
ensure
|
32
|
+
# Make sure the connection gets closed even if the query explodes.
|
33
|
+
connection.close()
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'common/dovecot_plugin'
|
4
|
+
require 'rm/rm_plugin'
|
5
|
+
|
6
|
+
|
7
|
+
# Handle the removal of users and domains from the Dovecot mailstore
|
8
|
+
# (the filesystem).
|
9
|
+
#
|
10
|
+
class DovecotRm
|
11
|
+
|
12
|
+
include DovecotPlugin
|
13
|
+
include RmPlugin
|
14
|
+
|
15
|
+
|
16
|
+
# Remove *domain* from the Dovecot mailstore. This just runs "rm -r"
|
17
|
+
# on the domain directory if it exists.
|
18
|
+
#
|
19
|
+
# @param domain [Domain] the domain to remove.
|
20
|
+
#
|
21
|
+
def remove_domain(domain)
|
22
|
+
domain_path = self.get_domain_path(domain)
|
23
|
+
|
24
|
+
if not File.directory?(domain_path)
|
25
|
+
raise NonexistentDomainError.new(domain.to_s())
|
26
|
+
end
|
27
|
+
|
28
|
+
FileUtils.rm_r(domain_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Remove *user* from the Dovecot mailstore. This just runs "rm -r"
|
33
|
+
# on the *user*'s mailbox directory, if it exists.
|
34
|
+
#
|
35
|
+
# @param user [User] the user whose mailbox directory we want to
|
36
|
+
# remove.
|
37
|
+
#
|
38
|
+
def remove_user(user)
|
39
|
+
user_path = self.get_user_path(user)
|
40
|
+
|
41
|
+
if not File.directory?(user_path)
|
42
|
+
raise NonexistentUserError.new(user.to_s())
|
43
|
+
end
|
44
|
+
|
45
|
+
FileUtils.rm_r(user_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
require 'common/postfixadmin_plugin'
|
4
|
+
require 'rm/rm_plugin'
|
5
|
+
|
6
|
+
|
7
|
+
# Handle the removal of users and domains from the Postfixadmin database.
|
8
|
+
#
|
9
|
+
class PostfixadminRm
|
10
|
+
|
11
|
+
include PostfixadminPlugin
|
12
|
+
include RmPlugin
|
13
|
+
|
14
|
+
|
15
|
+
# Remove *user* from the Postfixadmin database. This should remove
|
16
|
+
# him from _every_ table in which he is referenced. Unfortunately,
|
17
|
+
# Postfixadmin does not use foreign keys or ON DELETE CASCADE
|
18
|
+
# triggers so we need to delete the associated child table records
|
19
|
+
# ourselves.
|
20
|
+
#
|
21
|
+
# @param user [User] the user to remove.
|
22
|
+
#
|
23
|
+
def remove_user(user)
|
24
|
+
raise NonexistentUserError.new(user.to_s()) if not user_exists(user)
|
25
|
+
|
26
|
+
# Remove aliases FROM our user to some other address.
|
27
|
+
sql_queries = ['DELETE FROM alias WHERE address = $1;']
|
28
|
+
|
29
|
+
# Also delete aliases that point SOLELY TO our user.
|
30
|
+
sql_queries << "DELETE FROM alias WHERE goto = $1;"
|
31
|
+
|
32
|
+
# But aliases don't need to point to a single user! If our user
|
33
|
+
# was part of a multi-recipient alias, we want to remove our user
|
34
|
+
# from the alias and leave the other recipients.
|
35
|
+
#
|
36
|
+
# We want to delete the comma that precedes/follows the address,
|
37
|
+
# too. Since the address to be replaced can appear at either the
|
38
|
+
# beginning or the end of the list (as well as in the middle), we
|
39
|
+
# have to try to fix both cases: comma before, and comma after.
|
40
|
+
comma_before = "CONCAT(',', $1)"
|
41
|
+
comma_after = "CONCAT($1, ',')"
|
42
|
+
sql_queries << "UPDATE alias SET goto=REPLACE(goto, #{comma_before}, '');"
|
43
|
+
sql_queries << "UPDATE alias SET goto=REPLACE(goto, #{comma_after}, '');"
|
44
|
+
|
45
|
+
sql_queries << 'DELETE FROM mailbox WHERE username = $1;'
|
46
|
+
sql_queries << 'DELETE FROM quota WHERE username = $1;'
|
47
|
+
sql_queries << 'DELETE FROM quota2 WHERE username = $1;'
|
48
|
+
sql_queries << 'DELETE FROM vacation WHERE email = $1;'
|
49
|
+
|
50
|
+
# Should be handled by a trigger, according to PostfixAdmin code.
|
51
|
+
sql_queries << 'DELETE FROM vacation_notification WHERE on_vacation = $1;'
|
52
|
+
|
53
|
+
connection = PG::Connection.new(@db_hash)
|
54
|
+
|
55
|
+
begin
|
56
|
+
sql_queries.each do |sql_query|
|
57
|
+
varchar = 1043 # from pg_type.h
|
58
|
+
params = [{:value => user.to_s(), :type => varchar}]
|
59
|
+
connection.query(sql_query, params)
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
# Make sure the connection gets closed even if a query explodes.
|
63
|
+
connection.close()
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Remove *domain* from the Postfixadmin database. This should remove
|
69
|
+
# the domain from _every_ table in which it is referenced. It should
|
70
|
+
# also remove every user that belongs to the doomed domain
|
71
|
+
# Postfixadmin has some experimental support for triggers, but they
|
72
|
+
# don't do a very good job of cleaning up. Therefore we remove all
|
73
|
+
# users in the domain manually before removing the domain itself.
|
74
|
+
#
|
75
|
+
# Log entries (from the "log" table) are not removed since they may
|
76
|
+
# still contain valuable information (although they won't mention
|
77
|
+
# this removal).
|
78
|
+
#
|
79
|
+
# @param domain [Domain] the domain to remove.
|
80
|
+
#
|
81
|
+
def remove_domain(domain)
|
82
|
+
raise NonexistentDomainError.new(domain.to_s()) if not domain_exists(domain)
|
83
|
+
|
84
|
+
# First remove all users belonging to the domain. This will handle
|
85
|
+
# alias updates and all the sensitive crap we need to do when
|
86
|
+
# removing a user.
|
87
|
+
users = list_domains_users([domain])
|
88
|
+
users.each { |u| remove_user(u) }
|
89
|
+
|
90
|
+
# The domain_admins table contains one record per domain
|
91
|
+
# (repeating the user as necessary), so this really is sufficient.
|
92
|
+
sql_queries = ['DELETE FROM domain_admins WHERE domain = $1;']
|
93
|
+
|
94
|
+
# Some of the following queries should be redundant now that we've
|
95
|
+
# removed all users in the domain.
|
96
|
+
sql_queries << 'DELETE FROM alias WHERE domain = $1;'
|
97
|
+
sql_queries << 'DELETE FROM mailbox WHERE domain = $1;'
|
98
|
+
sql_queries << 'DELETE FROM alias_domain WHERE alias_domain = $1;'
|
99
|
+
sql_queries << 'DELETE FROM vacation WHERE domain = $1;'
|
100
|
+
sql_queries << 'DELETE FROM domain WHERE domain = $1;'
|
101
|
+
|
102
|
+
connection = PG::Connection.new(@db_hash)
|
103
|
+
|
104
|
+
begin
|
105
|
+
sql_queries.each do |sql_query|
|
106
|
+
connection.query(sql_query, [domain.to_s()])
|
107
|
+
end
|
108
|
+
ensure
|
109
|
+
# Make sure the connection gets closed even if a query explodes.
|
110
|
+
connection.close()
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|