cloudscale 0.0.6 → 0.0.7
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 +4 -4
- data/lib/cloudscale.rb +37 -25
- data/lib/cloudscale/monitor/agent/{init.rb → agent.rb} +42 -1
- data/lib/cloudscale/monitor/plugin/settings_db.rb +60 -0
- data/lib/cloudscale/monitor/{agent/preops → preops}/general_preop.rb +0 -0
- data/lib/cloudscale/monitor/preops/preop.rb +62 -0
- data/lib/cloudscale/plugins/mongo/mongo_db_status.rb +24 -19
- data/lib/cloudscale/plugins/mongo/mongo_replica_status.rb +48 -75
- data/lib/cloudscale/plugins/mongo/mongo_server_status.rb +112 -135
- data/lib/cloudscale/plugins/mongo/preops/mongodb_preop.rb +113 -0
- data/lib/cloudscale/plugins/os/preops/{plugin_preop.rb → os_preop.rb} +7 -4
- data/lib/cloudscale/plugins/os/sigar_cpu_perc.rb +3 -3
- data/lib/cloudscale/plugins/os/sigar_disk_iops.rb +4 -4
- data/lib/cloudscale/plugins/os/sigar_disk_space.rb +3 -3
- data/lib/cloudscale/plugins/os/sigar_net_byte_information.rb +4 -5
- data/lib/cloudscale/plugins/os/sigar_packet_information.rb +4 -4
- data/lib/cloudscale/plugins/os/sigar_ram_usage.rb +4 -4
- data/lib/cloudscale/plugins/os/sigar_swap_usage.rb +3 -3
- data/lib/cloudscale/plugins/plugin.rb +2 -50
- data/lib/cloudscale/plugins/postgres/postgres_server_status.rb +60 -101
- data/lib/cloudscale/plugins/postgres/preops/postgres_preop.rb +80 -0
- data/lib/cloudscale/plugins/preops/plugin_preop.rb +30 -0
- data/lib/cloudscale/registry.rb +1 -0
- data/lib/cloudscale/store/plugin/host +1 -0
- data/lib/cloudscale/store/plugin/port +1 -0
- data/lib/cloudscale/store/plugin/token +1 -0
- data/lib/cloudscale/version.rb +1 -1
- metadata +41 -10
- data/lib/cloudscale/monitor/agent/init_charts.rb +0 -50
- data/lib/cloudscale/monitor/agent/init_menus.rb +0 -44
- data/lib/cloudscale/monitor/agent/preops/preop.rb +0 -76
- data/lib/cloudscale/plugins/preops/plugin_mongodb_preop.rb +0 -105
- data/lib/cloudscale/plugins/preops/plugin_postgres_preop.rb +0 -70
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,13 +11,13 @@ module Cloudscale
|
|
11
11
|
class SigarDiskIops < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
16
|
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -31,7 +31,7 @@ module Cloudscale
|
|
31
31
|
dir_name = fs.dir_name
|
32
32
|
begin
|
33
33
|
usage = @sigar.file_system_usage(dir_name)
|
34
|
-
dir = dir_name.gsub(/[^0-9A-Za-z]/, '')
|
34
|
+
dir = dir_name.gsub(/[^0-9A-Za-z]/, '')
|
35
35
|
registry.metrics["os.disk.iops.read." + dir] = metrics.gauge :iops_read do
|
36
36
|
{ :value => usage.disk_reads }
|
37
37
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,13 +11,13 @@ module Cloudscale
|
|
11
11
|
class SigarDiskSpace < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
16
|
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,15 +11,14 @@ module Cloudscale
|
|
11
11
|
class SigarNetByteInformation < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
|
-
|
23
22
|
end
|
24
23
|
|
25
24
|
def collect(agentInstanceId)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,13 +11,13 @@ module Cloudscale
|
|
11
11
|
class SigarNetPacketInformation < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,13 +11,13 @@ module Cloudscale
|
|
11
11
|
class SigarRamUsage < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/preops/
|
1
|
+
require "#{File.dirname(__FILE__)}/preops/os_preop"
|
2
2
|
require "#{File.dirname(__FILE__)}/../plugin"
|
3
3
|
|
4
4
|
##
|
@@ -11,13 +11,13 @@ module Cloudscale
|
|
11
11
|
class SigarSwapUsage < Plugins::Plugin
|
12
12
|
|
13
13
|
def is_enabled
|
14
|
-
|
14
|
+
Preops::OsPreop.instance.is_enabled
|
15
15
|
end
|
16
16
|
|
17
17
|
def initialize
|
18
18
|
super
|
19
19
|
if is_enabled
|
20
|
-
@sigar =
|
20
|
+
@sigar = Preops::OsPreop.instance.sigar
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,9 +1,6 @@
|
|
1
|
-
require "fsdb"
|
2
|
-
require "yaml/store"
|
3
1
|
require "logger"
|
4
2
|
require "ruby-metrics"
|
5
|
-
require "#{File.dirname(__FILE__)}/../
|
6
|
-
require "#{File.dirname(__FILE__)}/../monitor/agent/init_menus"
|
3
|
+
require "#{File.dirname(__FILE__)}/../registry"
|
7
4
|
require "#{File.dirname(__FILE__)}/../monitor/model/constants/agent_instance_store"
|
8
5
|
require "#{File.dirname(__FILE__)}/../rest/rest_client"
|
9
6
|
|
@@ -15,7 +12,7 @@ require "#{File.dirname(__FILE__)}/../rest/rest_client"
|
|
15
12
|
module Cloudscale
|
16
13
|
module Plugins
|
17
14
|
class Plugin
|
18
|
-
attr_accessor :log, :plugins
|
15
|
+
attr_accessor :log, :plugins
|
19
16
|
|
20
17
|
@plugins = Set.new
|
21
18
|
|
@@ -23,51 +20,6 @@ module Cloudscale
|
|
23
20
|
@log = Logger.new(STDOUT)
|
24
21
|
end
|
25
22
|
|
26
|
-
def initialize()
|
27
|
-
@rest_client = RestClientWrapper.instance
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.reset(agentInstanceId)
|
31
|
-
resetRestEndpoint('coredatas', agentInstanceId, 'Coredata')
|
32
|
-
resetRestEndpoint('tables', agentInstanceId, 'Table')
|
33
|
-
resetRestEndpoint('charts', agentInstanceId, 'Chart')
|
34
|
-
|
35
|
-
remove_agenInstance(agentInstanceId)
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.remove(agentInstanceId)
|
39
|
-
reset(agentInstanceId)
|
40
|
-
|
41
|
-
Constants::AgentInstance.remove()
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.resetRestEndpoint(entityRel, agentInstanceId, entityName)
|
45
|
-
rest_client = RestClientWrapper.instance
|
46
|
-
entities = rest_client.searchAny(entityRel,"findByAgentInstanceId",
|
47
|
-
{ :agentInstanceId => agentInstanceId })
|
48
|
-
|
49
|
-
puts "Found #{entityName} elements for Agent (#{agentInstanceId}): #{entities["content"].length.to_s}"
|
50
|
-
puts " Starting to delete all elements..."
|
51
|
-
|
52
|
-
entities["content"].each do | entity |
|
53
|
-
rest_client.delete(entityRel, RestClientWrapper.load_entity_id(entity))
|
54
|
-
end
|
55
|
-
|
56
|
-
puts " Deleting all elements was successful \n\n"
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.remove_agenInstance(agentInstanceId)
|
60
|
-
rest_client = RestClientWrapper.instance
|
61
|
-
puts "Removing AgentInstance completely:\n\n"
|
62
|
-
|
63
|
-
agent_instance = rest_client.searchOne('agentInstances',
|
64
|
-
'findByAgentInstanceId', { :id => agentInstanceId })
|
65
|
-
|
66
|
-
rest_client.delete('agentInstances', RestClientWrapper.load_entity_id(agent_instance))
|
67
|
-
|
68
|
-
puts " Deleting AgentInstance was successful \n\n"
|
69
|
-
end
|
70
|
-
|
71
23
|
def self.plugins
|
72
24
|
@plugins
|
73
25
|
end
|
@@ -9,55 +9,27 @@ require "#{File.dirname(__FILE__)}/../plugin"
|
|
9
9
|
module Cloudscale
|
10
10
|
module Plugins
|
11
11
|
class PostgresServerStatus < Plugins::Plugin
|
12
|
-
attr_reader :
|
13
|
-
|
14
|
-
:generalInformation, :rowsSelectIdx, :rowsSelectScan, :rowInserts, :rowUpdated, :rowDeleted, :rowTotal
|
15
|
-
def log
|
16
|
-
@log = Logger.new(STDOUT)
|
17
|
-
end
|
18
|
-
|
12
|
+
attr_reader :connection
|
13
|
+
|
19
14
|
def is_enabled
|
20
|
-
|
15
|
+
Preops::PostgresPreop.instance.is_enabled
|
21
16
|
end
|
22
|
-
|
17
|
+
|
23
18
|
def initialize
|
24
19
|
super
|
25
20
|
if is_enabled
|
26
|
-
|
27
|
-
@menu_generalInformation = load_menu(menus["pgDatabaseStats"], "generalInformation")
|
28
|
-
@menu_numBackends = load_menu(menus["pgDatabaseStats"], "numBackends")
|
29
|
-
@menu_transactionInformation = load_menu(menus["pgDatabaseStats"], "transactionInformation")
|
30
|
-
@menu_bulkOps = load_menu(menus["pgDatabaseStats"], "bulkOps")
|
31
|
-
@menu_rowStats = load_menu(menus["pgTableStats"], "rowStats")
|
32
|
-
|
33
|
-
@connection = Plugins::PostgresDbWrapper.instance.connection
|
34
|
-
components = Plugins::PluginComponents.load_hash()
|
35
|
-
@numBackends = load_metric(components["pgDatabaseStats"], "numBackends")
|
36
|
-
@xactCommit = load_metric(components["pgDatabaseStats"], "xactCommit")
|
37
|
-
@xactRollback = load_metric(components["pgDatabaseStats"], "xactRollback")
|
38
|
-
@xactTotal = load_metric(components["pgDatabaseStats"], "xactTotal")
|
39
|
-
@blksRead = load_metric(components["pgDatabaseStats"], "blksRead")
|
40
|
-
@blksHit = load_metric(components["pgDatabaseStats"], "blksHit")
|
41
|
-
|
42
|
-
@generalInformation = load_metric(components["pgDatabaseStats"], "generalInformation")
|
43
|
-
|
44
|
-
@rowsSelectIdx = load_metric(components["pgTableStats"], "rowsSelectIdx")
|
45
|
-
@rowsSelectScan = load_metric(components["pgTableStats"], "rowsSelectScan")
|
46
|
-
@rowInserts = load_metric(components["pgTableStats"], "rowInserts")
|
47
|
-
@rowUpdated = load_metric(components["pgTableStats"], "rowUpdated")
|
48
|
-
@rowDeleted = load_metric(components["rowDeleted"], "rowDeleted")
|
49
|
-
@rowTotal = load_metric(components["rowTotal"], "rowTotal")
|
50
|
-
|
21
|
+
@connection = Preops::PostgresPreop.instance.connection
|
51
22
|
end
|
52
23
|
end
|
53
|
-
|
24
|
+
|
54
25
|
def collect(agentInstanceId)
|
26
|
+
registry = Monitor::Registry.instance
|
27
|
+
metrics = Metrics::Agent.new
|
55
28
|
log.info("Calling Collect on MongoServerStatus")
|
56
|
-
|
57
|
-
|
58
|
-
report_table_stats(agentInstanceId)
|
29
|
+
report_database_stats(registry, metrics)
|
30
|
+
report_table_stats(registry, metrics)
|
59
31
|
end
|
60
|
-
|
32
|
+
|
61
33
|
def report_database_stats(agentInstanceId)
|
62
34
|
result = @connection.exec('SELECT sum(idx_tup_fetch) AS "rows_select_idx",
|
63
35
|
sum(seq_tup_read) AS "rows_select_scan",
|
@@ -65,28 +37,34 @@ module Cloudscale
|
|
65
37
|
sum(n_tup_upd) AS "rows_update",
|
66
38
|
sum(n_tup_del) AS "rows_delete",
|
67
39
|
(sum(idx_tup_fetch) + sum(seq_tup_read) + sum(n_tup_ins) + sum(n_tup_upd) + sum(n_tup_del)) AS "rows_total"
|
68
|
-
FROM pg_stat_all_tables;')
|
40
|
+
FROM pg_stat_all_tables;')
|
69
41
|
row = result[0]
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
42
|
+
|
43
|
+
registry.metrics["postgres.rows.select.index"] = metrics.gauge :rows_select_idx do
|
44
|
+
{ :value => row['rows_select_idx'] }
|
45
|
+
end
|
46
|
+
|
47
|
+
registry.metrics["postgres.rows.select.scan"] = metrics.gauge :rows_select_scan do
|
48
|
+
{ :value => row['rows_select_scan'] }
|
49
|
+
end
|
50
|
+
|
51
|
+
registry.metrics["postgres.rows.inserts"] = metrics.gauge :rows_insert do
|
52
|
+
{ :value => row['rows_insert'] }
|
53
|
+
end
|
54
|
+
|
55
|
+
registry.metrics["postgres.rows.updates"] = metrics.gauge :rows_update do
|
56
|
+
{ :value => row['rows_update'] }
|
57
|
+
end
|
58
|
+
|
59
|
+
registry.metrics["postgres.rows.select.delete"] = metrics.gauge :rows_delete do
|
60
|
+
{ :value => row['rows_delete'] }
|
61
|
+
end
|
62
|
+
|
63
|
+
registry.metrics["postgres.rows.select.total"] = metrics.gauge :rows_total do
|
64
|
+
{ :value => row['rows_total'] }
|
65
|
+
end
|
88
66
|
end
|
89
|
-
|
67
|
+
|
90
68
|
def report_table_stats(agentInstanceId)
|
91
69
|
result = @connection.exec('SELECT sum(numbackends) AS "numbackends",
|
92
70
|
sum(xact_commit) AS "xact_commit",
|
@@ -96,48 +74,29 @@ module Cloudscale
|
|
96
74
|
sum(blks_hit) AS "blks_hit"
|
97
75
|
FROM pg_stat_database;')
|
98
76
|
row = result[0]
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
client_port, backend_start, state, waiting
|
121
|
-
FROM pg_stat_activity;')
|
122
|
-
row = result[0]
|
123
|
-
|
124
|
-
body = Array.new
|
125
|
-
body.push(["DatId", row['datid']])
|
126
|
-
body.push(["Datname", row['datname']])
|
127
|
-
body.push(["Pid", row['pid']])
|
128
|
-
body.push(["Use Sysid", row['usesysid']])
|
129
|
-
body.push(["usename", row['usename']])
|
130
|
-
body.push(["client_addr", row['client_addr']])
|
131
|
-
body.push(["client_hostname", row['client_hostname']])
|
132
|
-
body.push(["client_port", row['client_port']])
|
133
|
-
body.push(["backend_start", row['backend_start']])
|
134
|
-
body.push(["state", row['state']])
|
135
|
-
body.push(["waiting", row['waiting']])
|
136
|
-
mongo_general_inf_table = Monitor::Table.new("generalInformationPostgres", "Postgres General Information", nil, body, "compact")
|
137
|
-
mongo_general_inf_table.caption = "General Information regarding your Postgres Instance"
|
138
|
-
|
139
|
-
persist_table(mongo_general_inf_table, agentInstanceId, menu_generalInformation)
|
77
|
+
|
78
|
+
registry.metrics["postgres.transactions.commit"] = metrics.gauge :xact_commit do
|
79
|
+
{ :value => row['xact_commit'] }
|
80
|
+
end
|
81
|
+
|
82
|
+
registry.metrics["postgres.transactions.rollback"] = metrics.gauge :xact_rollback do
|
83
|
+
{ :value => row['xact_rollback'] }
|
84
|
+
end
|
85
|
+
|
86
|
+
registry.metrics["postgres.transactions.total"] = metrics.gauge :xact_total do
|
87
|
+
{ :value => row['xact_total'] }
|
88
|
+
end
|
89
|
+
|
90
|
+
registry.metrics["postgres.bulk.reads"] = metrics.gauge :blks_read do
|
91
|
+
{ :value => row['blks_read'] }
|
92
|
+
end
|
93
|
+
|
94
|
+
registry.metrics["postgres.bulk.hits"] = metrics.gauge :blks_hit do
|
95
|
+
{ :value => row['blks_hit'] }
|
96
|
+
end
|
97
|
+
|
140
98
|
end
|
99
|
+
|
141
100
|
end
|
142
101
|
end
|
143
|
-
end
|
102
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "logger"
|
2
|
+
begin
|
3
|
+
require "pg"
|
4
|
+
rescue LoadError
|
5
|
+
puts "WARNING: Load error PG needs to be installed via bundler"
|
6
|
+
end
|
7
|
+
require "singleton"
|
8
|
+
require "#{File.dirname(__FILE__)}/../../preops/plugin_preop"
|
9
|
+
|
10
|
+
##
|
11
|
+
#
|
12
|
+
# @author Johannes Hiemer.
|
13
|
+
#
|
14
|
+
##
|
15
|
+
module Cloudscale
|
16
|
+
module Preops
|
17
|
+
class PostgresPreop < Preops::PluginPreop
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
def is_enabled
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
@@options = {
|
25
|
+
:"postgres-host" => {
|
26
|
+
:argument => "--postgres-host",
|
27
|
+
:description => "Host for your Postgres Instance (e.g. host.instance.com)",
|
28
|
+
:required => true,
|
29
|
+
:value => nil
|
30
|
+
},
|
31
|
+
:"postgres-port" => {
|
32
|
+
:argument => "--postgres-port",
|
33
|
+
:description => "Port for your Postgres Instance (Standard 5432)",
|
34
|
+
:required => false,
|
35
|
+
:value => 5432
|
36
|
+
},
|
37
|
+
:"postgres-db" => {
|
38
|
+
:argument => "--postgres-db",
|
39
|
+
:description => "Database of your Postgres instance",
|
40
|
+
:required => true,
|
41
|
+
:value => nil
|
42
|
+
},
|
43
|
+
:"postgres-username" => {
|
44
|
+
:argument => "--postgres-username",
|
45
|
+
:description => "Username for your Postgres instance",
|
46
|
+
:required => false,
|
47
|
+
:value => nil
|
48
|
+
},
|
49
|
+
:"postgres-password" => {
|
50
|
+
:argument => "--postgres-password",
|
51
|
+
:description => "Password for your Postgres instance",
|
52
|
+
:required => false,
|
53
|
+
:value => nil
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
def options
|
58
|
+
@@options
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize
|
62
|
+
self.init
|
63
|
+
if defined? PG
|
64
|
+
begin
|
65
|
+
@connection = PG.connect(:host => options[:host][:value], :user => options[:username][:value],
|
66
|
+
:password => options[:password][:value],
|
67
|
+
:port => options[:port][:value].to_i, :dbname => options[:db][:value])
|
68
|
+
rescue PGError => e
|
69
|
+
puts e.message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def connection
|
75
|
+
@connection
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|