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

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*
6:Author:
7 David Young
9:Date Created:
10 November 22, 2017
11"""
12################# GLOBAL IMPORTS ####################
13from builtins import object
14import sys
15import os
16os.environ['TERM'] = 'vt100'
17import readline
18import glob
19import pickle
20import time
21from subprocess import Popen, PIPE, STDOUT
22import pymysql as ms
23from docopt import docopt
24from fundamentals.mysql import readquery
27class database(object):
28 """
29 *a database object that can setup up a ssh tunnel (optional) and a database connection*
31 **Key Arguments:**
32 - ``log`` -- logger
33 - ``dbSettings`` -- a dictionary of database settings
35 **Return:**
36 - ``dbConns`` -- a database connection
38 **Usage:**
40 Given a python dictionary that looks like this:
42 .. code-block:: python
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 }
58 ``loginPath`` and ``tunnel`` are optional, to setup the a database connection, run the following:
60 .. code-block:: python
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
71 def __init__(
72 self,
73 log,
74 dbSettings=False,
75 autocommit=True
77 ):
78 self.log = log
79 log.debug("instansiating a new '_database' object")
80 self.dbSettings = dbSettings
81 self.autocommit = autocommit
83 return None
85 def connect(self):
86 """connect to the database
88 **Return:**
89 - ``dbConn`` -- the database connection
91 See the class docstring for usage
92 """
93 self.log.debug('starting the ``connect`` method')
95 dbSettings = self.dbSettings
97 port = False
98 if "tunnel" in dbSettings and dbSettings["tunnel"]:
99 port = self._setup_tunnel(
100 tunnelParameters=dbSettings["tunnel"]
101 )
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)
124 self.log.debug('completed the ``connect`` method')
125 return dbConn
127 def _setup_tunnel(
128 self,
129 tunnelParameters):
130 """
131 *setup a ssh tunnel for a database connection to port through*
133 **Key Arguments:**
134 - ``tunnelParameters`` -- the tunnel parameters found associated with the database settings
136 **Return:**
137 - ``sshPort`` -- the port the ssh tunnel is connected via
138 """
139 self.log.debug('starting the ``_setup_tunnel`` method')
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"]
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())
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
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')
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
192 return None
194 # xt-class-method