Coverage for /Users/Dave/git_repos/_packages_/python/fundamentals/fundamentals/mysql/database.py: 25%

# Coverage for /Users/Dave/git_repos/_packages_/python/fundamentals/fundamentals/mysql/database.py : 25%

## 71 statements 18 run 53 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1#!/usr/local/bin/python

2# encoding: utf-8

3"""

4*a database object that can setup up a ssh tunnel (optional) and a database connection*

5

6:Author:

7 David Young

8

9:Date Created:

10 November 22, 2017

11"""

12################# GLOBAL IMPORTS ####################

13 from builtins import object

14 import sys

15 import os

16 os.environ['TERM'] = 'vt100'

17 import readline

18 import glob

19 import pickle

20 import time

21 from subprocess import Popen, PIPE, STDOUT

22 import pymysql as ms

23 from docopt import docopt

24 from fundamentals.mysql import readquery

25

26

27 class database(object):

28 """

29 *a database object that can setup up a ssh tunnel (optional) and a database connection*

30

31 **Key Arguments:**

32 - ``log`` -- logger

33 - ``dbSettings`` -- a dictionary of database settings

34

35 **Return:**

36 - ``dbConns`` -- a database connection

37

38 **Usage:**

39

40 Given a python dictionary that looks like this:

41

42 .. code-block:: python

43

44 dbSettings = {

45 'host': '127.0.0.1',

46 'loginPath': 'atlasMovers',

47 'user': 'monster',

48 'tunnel': {

49 'remote ip': 'psweb.mp.qub.ac.uk',

50 'remote datbase host': 'dormammu',

51 'remote user': 'monster',

52 'port': 9006

53 },

54 'password': 'myPass',

55 'db': 'atlas_moving_objects'

56 }

57

58 ``loginPath`` and ``tunnel`` are optional, to setup the a database connection, run the following:

59

60 .. code-block:: python

61

62 # SETUP ALL DATABASE CONNECTIONS

63 from fundamentals.mysql import database

64 dbConn = database(

65 log=log,

66 dbSettings=dbSettings

67 ).connect()

68 """

69 # INITIALISATION

70

71 def __init__(

72 self,

73 log,

74 dbSettings=False,

75 autocommit=True

76

77 ):

78 self.log = log

79 log.debug("instansiating a new '_database' object")

80 self.dbSettings = dbSettings

81 self.autocommit = autocommit

82

83 return None

84

85 def connect(self):

86 """connect to the database

87

88 **Return:**

89 - ``dbConn`` -- the database connection

90

91 See the class docstring for usage

92 """

93 self.log.debug('starting the ``connect`` method')

94

95 dbSettings = self.dbSettings

96

97 port = False

98 if "tunnel" in dbSettings and dbSettings["tunnel"]:

99 port = self._setup_tunnel(

100 tunnelParameters=dbSettings["tunnel"]

101 )

102

103 # SETUP A DATABASE CONNECTION

104 host = dbSettings["host"]

105 user = dbSettings["user"]

106 passwd = dbSettings["password"]

107 dbName = dbSettings["db"]

108 dbConn = ms.connect(

109 host=host,

110 user=user,

111 passwd=passwd,

112 db=dbName,

113 port=port,

114 use_unicode=True,

115 charset='utf8mb4',

116 local_infile=1,

117 client_flag=ms.constants.CLIENT.MULTI_STATEMENTS,

118 connect_timeout=36000,

119 max_allowed_packet=51200000

120 )

121 if self.autocommit:

122 dbConn.autocommit(True)

123

124 self.log.debug('completed the ``connect`` method')

125 return dbConn

126

127 def _setup_tunnel(

128 self,

129 tunnelParameters):

130 """

131 *setup a ssh tunnel for a database connection to port through*

132

133 **Key Arguments:**

134 - ``tunnelParameters`` -- the tunnel parameters found associated with the database settings

135

136 **Return:**

137 - ``sshPort`` -- the port the ssh tunnel is connected via

138 """

139 self.log.debug('starting the ``_setup_tunnel`` method')

140

141 # TEST TUNNEL DOES NOT ALREADY EXIST

142 sshPort = tunnelParameters["port"]

143 connected = self._checkServer(

144 "127.0.0.1", sshPort)

145 if connected:

146 self.log.debug('ssh tunnel already exists - moving on')

147 else:

148 # GRAB TUNNEL SETTINGS FROM SETTINGS FILE

149 ru = tunnelParameters["remote user"]

150 rip = tunnelParameters["remote ip"]

151 rh = tunnelParameters["remote datbase host"]

152

153 cmd = "ssh -fnN %(ru)s@%(rip)s -L %(sshPort)s:%(rh)s:3306" % locals()

154 p = Popen(cmd, shell=True, close_fds=True)

155 output = p.communicate()[0]

156 self.log.debug('output: %(output)s' % locals())

157

158 # TEST CONNECTION - QUIT AFTER SO MANY TRIES

159 connected = False

160 count = 0

161 while not connected:

162 connected = self._checkServer(

163 "127.0.0.1", sshPort)

164 time.sleep(1)

165 count += 1

166 if count == 5:

167 self.log.error(

168 'cound not setup tunnel to remote datbase' % locals())

169 sys.exit(0)

170 return sshPort

171

172 def _checkServer(self, address, port):

173 """Check that the TCP Port we've decided to use for tunnelling is available

174 """

175 self.log.debug('starting the ``_checkServer`` method')

176

177 # CREATE A TCP SOCKET

178 import socket

179 s = socket.socket()

180 self.log.debug(

181 """Attempting to connect to `%(address)s` on port `%(port)s`""" % locals())

182 try:

183 s.connect((address, port))

184 self.log.debug(

185 """Connected to `%(address)s` on port `%(port)s`""" % locals())

186 return True

187 except socket.error as e:

188 self.log.warning(

189 """Connection to `%(address)s` on port `%(port)s` failed - try again: %(e)s""" % locals())

190 return False

191

192 return None

193

194 # xt-class-method