This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
/
rdbms_googleapi.py
257 lines (188 loc) · 7.5 KB
/
rdbms_googleapi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Speckle connection module for Google API."""
import logging
import os
import google
try:
import apiclient
except ImportError:
try:
import google_sql
google_sql.fix_sys_path(google_sql.GOOGLE_SQL_EXTRA_PATHS)
except ImportError:
logging.warning(
'Attempt to automatically load Google Cloud SQL dependencies failed! '
'Ensure that the App Engine SDK directory has been added to your '
'PYTHONPATH when using this backend.')
from apiclient import errors
from apiclient import http
from apiclient import model
import httplib2
from oauth2client import client
from oauth2client import file as oauth_file
from google.storage.speckle.proto import sql_pb2
from google.storage.speckle.python.api import rdbms
__path__ = rdbms.__path__
CLIENT_ID = '877927577750.apps.googleusercontent.com'
CLIENT_SECRET = '7nBqns87ugMSNBrOM1FdHMK6'
USER_AGENT = 'Google SQL Service/1.0'
def GetFlow(state=None):
"""Get a client.OAuth2WebServerFlow for performing OAuth 2.0 authentication.
Args:
state: Value to use for the OAuth 2.0 state parameter.
Returns:
A client.OAuth2WebServerFlow instance populated with default values for
getting access to the SQL Service over Google API.
"""
return client.OAuth2WebServerFlow(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope='https://www.googleapis.com/auth/sqlservice',
user_agent=USER_AGENT,
state=state)
class RdbmsGoogleApiClient(object):
"""A Google API client for rdbms."""
def __init__(self, api_url='https://www.googleapis.com/sql/v1/',
oauth_credentials_path=None, oauth_storage=None,
developer_key=None):
"""Constructs an RdbmsGoogleApiClient.
Args:
api_url: The base of the URL for the rdbms Google API.
oauth_credentials_path: The filesystem path to use for OAuth 2.0
credentials storage.
oauth_storage: A client.Storage instance to use for OAuth 2.0 credential
storage instead of the default file based storage.
developer_key: A Google APIs developer key to use when connecting to the
SQL service.
"""
self._api_url = api_url
self._developer_key = developer_key
if oauth_storage is None:
if oauth_credentials_path is None:
oauth_credentials_path = os.path.expanduser(
rdbms.OAUTH_CREDENTIALS_PATH)
oauth_storage = oauth_file.Storage(oauth_credentials_path)
credentials = oauth_storage.get()
if credentials is None or credentials.invalid:
from oauth2client import tools
credentials = tools.run(GetFlow(), oauth_storage)
self._transport = credentials.authorize(httplib2.Http())
def OpenConnection(self, request):
return self._MakeRequest(
'jdbc/openConnection', request, sql_pb2.OpenConnectionResponse)
def CloseConnection(self, request):
return self._MakeRequest(
'jdbc/closeConnection', request, sql_pb2.CloseConnectionResponse)
def Exec(self, request):
return self._MakeRequest('jdbc/exec', request, sql_pb2.ExecResponse)
def ExecOp(self, request):
return self._MakeRequest('jdbc/execOp', request, sql_pb2.ExecOpResponse)
def GetMetadata(self, request):
return self._MakeRequest(
'jdbc/getMetadata', request, sql_pb2.MetadataResponse)
def _MakeRequest(self, method, request, response_class):
"""Executes a request to the Google API server.
Args:
method: The method to invoke.
request: The request protocol buffer from sql_pb2.
response_class: The response protocol buffer class from sql_pb2.
Returns:
A protocol buffer instance of the given response_class type.
"""
pb_model = model.ProtocolBufferModel(response_class)
query_params = {}
if self._developer_key:
query_params['key'] = self._developer_key
headers, unused_params, query, body = pb_model.request(
{}, {}, query_params, request)
request = http.HttpRequest(
self._transport, pb_model.response, self._api_url + method + query,
method='POST', body=body, headers=headers)
return request.execute()
class GoogleApiConnection(rdbms.Connection):
"""Google API specific rdbms connection."""
def __init__(self, *args, **kwargs):
"""Constructs a GoogleApiConnection.
In addition to all of the arguments taken by rdbms.Connection.__init__, this
also accepts the following optional keyword arguments:
oauth_credentials_path: The filesystem path to the file used for OAuth 2.0
credential storage.
oauth_storage: A client.Storage instance to use for OAuth 2.0 credential
storage instead of the default file based storage.
developer_key: A Google APIs developer key to use when connecting to the SQL
service.
Args:
args: Positional arguments to pass to parent method.
kwargs: Keyword arguments to pass to parent method.
"""
self._oauth_credentials_path = kwargs.pop('oauth_credentials_path', None)
self._oauth_storage = kwargs.pop('oauth_storage', None)
self._developer_key = kwargs.pop('developer_key', None)
super(GoogleApiConnection, self).__init__(*args, **kwargs)
def SetupClient(self):
"""Opens a Google API connection to rdbms."""
kwargs = {'developer_key': self._developer_key,
'oauth_storage': self._oauth_storage}
if self._dsn:
kwargs['api_url'] = self._dsn
if self._oauth_credentials_path:
kwargs['oauth_credentials_path'] = self._oauth_credentials_path
self._client = RdbmsGoogleApiClient(**kwargs)
def MakeRequestImpl(self, stub_method, request):
"""Makes a Google API request, and possibly raises an appropriate exception.
Args:
stub_method: A string, the name of the method to call.
request: A protobuf; 'instance' and 'connection_id' will be set
when available.
Returns:
A protobuf.
Raises:
OperationalError: httplib2 transport failure, or non 2xx http response.
"""
try:
response = getattr(self._client, stub_method)(request)
except (errors.Error, client.Error, httplib2.HttpLib2Error), e:
raise OperationalError('could not connect: ' + str(e))
return response
apilevel = rdbms.apilevel
threadsafety = rdbms.threadsafety
paramstyle = rdbms.paramstyle
version_info = rdbms.version_info
Binary = rdbms.Binary
Date = rdbms.Date
Time = rdbms.Time
Timestamp = rdbms.Timestamp
DateFromTicks = rdbms.DateFromTicks
TimeFromTicks = rdbms.TimeFromTicks
TimestampFromTicks = rdbms.TimestampFromTicks
STRING = rdbms.STRING
BINARY = rdbms.BINARY
NUMBER = rdbms.NUMBER
DATETIME = rdbms.DATETIME
ROWID = rdbms.ROWID
Warning = rdbms.Warning
Error = rdbms.Error
InterfaceError = rdbms.InterfaceError
DatabaseError = rdbms.DatabaseError
DataError = rdbms.DataError
OperationalError = rdbms.OperationalError
IntegrityError = rdbms.IntegrityError
InternalError = rdbms.InternalError
ProgrammingError = rdbms.ProgrammingError
NotSupportedError = rdbms.NotSupportedError
connect = GoogleApiConnection