Class: Ping::TNS

Inherits:
TCP
  • Object
show all
Defined in:
lib/net/tnsping.rb

Overview

The Ping::TNS class encapsulates the information and behavior of tns ping.

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =

The version of the net-tnsping library.

'1.3.3'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(database, driver = 'OCI8', host = nil, port = 1521, timeout = 5) {|_self| ... } ⇒ TNS

Creates and returns a new Ping::TNS object. If the db specified cannot be found in the tnsnames.ora file, then a Ping::TNS::Error is raised.

Yields:

  • (_self)

Yield Parameters:

  • _self (Ping::TNS)

    the object that the method was called on



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/net/tnsping.rb', line 49

def initialize(database, driver='OCI8', host=nil, port=1521, timeout=5)
  @database  = database
  @dsn       = "dbi:#{driver}:" << database
  @host      = host
  @timeout   = timeout
  @port      = port
  @driver    = driver
  @ports     = []  # There can be more than one host/port
  @hosts     = []  # for each dsn.  Try them in order.
  @sid       = nil

  @tns_admin = ENV['TNS_ADMIN']
  @ora_home  = ENV['ORACLE_HOME'] || ENV['ORA_HOME']

  if @tns_admin
    @tns_file = File.join(@tns_admin, 'tnsnames.ora')
  elsif @ora_home
    @tns_file = File.join(@ora_home, 'network', 'admin', 'tnsnames.ora')
  else
    home = ENV['HOME'] || ENV['USERPROFILE']
    @tns_file = File.join(home, 'tnsnames.ora')
  end

  yield self if block_given?

  # If the host is not specified, look for it in the tnsnames.ora file
  if host.nil?
    err_msg = "tnsnames.ora file could not be found"
    raise Error, err_msg unless File.exists?(@tns_file)
    parse_tns_file
  else
    @hosts.push(host)
    @ports.push(port)
  end
end

Instance Attribute Details

#databaseObject Also known as: db

Database name.



17
18
19
# File 'lib/net/tnsping.rb', line 17

def database
  @database
end

#driverObject

The name of the oracle driver to use for connections. Defaults to OCI8.



35
36
37
# File 'lib/net/tnsping.rb', line 35

def driver
  @driver
end

#dsnObject Also known as: database_source_name

Database source name.



20
21
22
# File 'lib/net/tnsping.rb', line 20

def dsn
  @dsn
end

#hostObject

The name of the host the database sits on.



26
27
28
# File 'lib/net/tnsping.rb', line 26

def host
  @host
end

#hostsObject (readonly)

A list of hosts for the given database name.



38
39
40
# File 'lib/net/tnsping.rb', line 38

def hosts
  @hosts
end

#ora_homeObject Also known as: oracle_home

The value of your ORACLE_HOME or ORA_HOME environment variable.



32
33
34
# File 'lib/net/tnsping.rb', line 32

def ora_home
  @ora_home
end

#portObject

The port used when attempting a connection. The default is 1521.



44
45
46
# File 'lib/net/tnsping.rb', line 44

def port
  @port
end

#portsObject (readonly)

A list of ports for the given database name



41
42
43
# File 'lib/net/tnsping.rb', line 41

def ports
  @ports
end

#tns_adminObject

The toplevel tns admin path.



29
30
31
# File 'lib/net/tnsping.rb', line 29

def tns_admin
  @tns_admin
end

#tns_fileObject

The full path to the tnsnames.ora file.



23
24
25
# File 'lib/net/tnsping.rb', line 23

def tns_file
  @tns_file
end

Instance Method Details

#ping?Boolean Also known as: ping_listener?

Performs a TCP ping on the listener. The host and port are determined from your tnsnames.ora file. If more than one host and/or port are found in the tnsnames.ora file, then each will be tried. So long as at least one of them connects successfully, true is returned.

If you specify a host and port in the constructor, then the attempt will only be made against that host on the given port.

Remember, this only pings the listener. If you want to ping the listener and the database, use the ping_all? method. – Try each host/port listed for a given entry. Return a true result if any one of them succeeds and break out of the loop.

Returns:

  • (Boolean)


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/net/tnsping.rb', line 108

def ping?
  if @hosts.empty?
    raise Error, "No hosts found"
  end

  # Use 1521 if no ports were found in the tnsnames.ora file.
  if @ports.empty?
    @ports.push(@port)
  end

  # If the host is provided, only ping that host
  if @host
    0.upto(@ports.length-1){ |n|
      @port = @ports[n]
      return super
    }
  else
    0.upto(@ports.length-1){ |n|
      @port = @ports[n]
      @host = @hosts[n]
      return super
    }
  end
end

#ping_all?Boolean

Simple wrapper for ping_listener? + ping_database?

Returns:

  • (Boolean)


176
177
178
179
180
# File 'lib/net/tnsping.rb', line 176

def ping_all?
  return false unless self.ping_listener?
  return false unless self.ping_database?
  true
end

#ping_database?(dsn = @dsn, timeout = @timeout, user = @sid, passwd = Time.now.to_s) ⇒ Boolean

Attempts to make a connection using a bogus login and password via the DBI class. If an ORA-01017 Oracle error is returned, that means the database is up and running and true is returned.

Note that each of the arguments for this method use the defaults passed to the constructor (or have a default otherwise set). You generally should not pass any arguments to this method. In the event that this method fails, false is returned and the error can be viewed via Ping::TNS#exception. – I have intentionally set the user and password to something random in order to avoid the possibility of accidentally guessing them. In case of cosmic coincidence, set them yourself.

Returns:

  • (Boolean)


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/net/tnsping.rb', line 147

def ping_database?(dsn=@dsn, timeout=@timeout, user=@sid, passwd=Time.now.to_s)
  re   = /ORA-01017/
  dbh  = nil
  user ||= Time.now.to_s
  rv = false

  begin
    Timeout.timeout(timeout){
      dbh = DBI.connect(dsn,user,passwd)
    }
  rescue DBI::DatabaseError => e
    if re.match(e.to_s)
      rv = true
    else
      @exception = e
    end
  rescue Timeout::Error, StandardError => e
    @exception = e
  ensure
    if dbh
      dbh.disconnect if dbh.connected?
    end
  end

  rv
end