bts_client.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. # Copyright 2014 Baidu, Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  4. # except in compliance with the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the
  9. # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  10. # either express or implied. See the License for the specific language governing permissions
  11. # and limitations under the License.
  12. """
  13. This module provides a client class for BTS.
  14. """
  15. import copy
  16. import json
  17. import logging
  18. from baidubce.auth import bce_v1_signer
  19. from baidubce.bce_base_client import BceBaseClient
  20. from baidubce.exception import BceClientError
  21. from baidubce.http import bce_http_client
  22. from baidubce.http import handler
  23. from baidubce.http import http_content_types
  24. from baidubce.http import http_headers
  25. from baidubce.http import http_methods
  26. from baidubce.services import bts
  27. from baidubce.services.bts import INVALID_ARGS_ERROR
  28. from baidubce.services.bts.model import create_instance_args_2_dict
  29. from baidubce.services.bts.model import CreateInstanceArgs
  30. from baidubce.services.bts.model import Row
  31. from baidubce.services.bts.model import Cell
  32. from baidubce.services.bts.model import QueryCell
  33. from baidubce.services.bts.model import BatchQueryRowArgs
  34. from baidubce.services.bts.model import QueryRowArgs
  35. from baidubce.services.bts.model import ScanArgs
  36. from baidubce.services.bts.model import create_table_args_2_dict
  37. from baidubce.services.bts.model import update_table_args_2_dict
  38. from baidubce.services.bts.util import _decode
  39. from baidubce.services.bts.util import _encode
  40. _logger = logging.getLogger(__name__)
  41. class BtsClient(BceBaseClient):
  42. """
  43. BTS Client
  44. """
  45. def __init__(self, config=None):
  46. BceBaseClient.__init__(self, config)
  47. # ------------- instance operation -----------
  48. def create_instance(self, instance_name, create_instance_args=None, config=None):
  49. """
  50. create instance
  51. :param instance_name: instance name
  52. :type instance_name: string
  53. :param create_instance_args: arguments for create instance
  54. :type create_instance_args: CreateInstanceArgs
  55. :param config: None
  56. :type config: BceClientConfiguration
  57. :return:
  58. :rtype baidubce.bce_response.BceResponse
  59. """
  60. path = bts.URL_PREFIX + b"/" + instance_name
  61. if create_instance_args is None:
  62. create_instance_args = CreateInstanceArgs()
  63. return self._send_request(http_methods.PUT, path=path, config=config,
  64. body=json.dumps(create_instance_args, default=create_instance_args_2_dict),
  65. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  66. def drop_instance(self, instance_name, config=None):
  67. """
  68. drop instance
  69. :param instance_name: instance name
  70. :type instance_name: string
  71. :param config: None
  72. :type config: BceClientConfiguration
  73. :return:
  74. :rtype baidubce.bce_response.BceResponse
  75. """
  76. path = bts.URL_PREFIX + b"/" + instance_name
  77. return self._send_request(http_methods.DELETE, path=path, config=config)
  78. def list_instances(self, config=None):
  79. """
  80. list instances
  81. :param config: None
  82. :type config: BceClientConfiguration
  83. :return:
  84. :rtype baidubce.bce_response.BceResponse
  85. """
  86. path = b"/v1/instances"
  87. return self._send_request(http_methods.GET, path=path, config=config)
  88. def show_instance(self, instance_name, config=None):
  89. """
  90. show instance
  91. :param instance_name: instance name
  92. :type instance_name: string
  93. :param config: None
  94. :type config: BceClientConfiguration
  95. :return:
  96. :rtype baidubce.bce_response.BceResponse
  97. """
  98. path = bts.URL_PREFIX + b"/" + instance_name
  99. return self._send_request(http_methods.GET, path=path, config=config)
  100. # ------------- table operation -----------
  101. def create_table(self, instance_name, table_name, create_table_args, config=None):
  102. """
  103. create table
  104. :param instance_name: instance name
  105. :type instance_name: string
  106. :param table_name: table name
  107. :type table_name: string
  108. :param create_table_args: arguments for create table
  109. :type create_table_args: CreateTableArgs
  110. :param config: None
  111. :type config: BceClientConfiguration
  112. :return:
  113. :rtype baidubce.bce_response.BceResponse
  114. """
  115. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name
  116. return self._send_request(http_methods.PUT, path=path, config=config,
  117. body=json.dumps(create_table_args, default=create_table_args_2_dict),
  118. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  119. def update_table(self, instance_name, table_name, update_table_args, config=None):
  120. """
  121. update table
  122. :param instance_name: instance name
  123. :type instance_name: string
  124. :param table_name: table name
  125. :type table_name: string
  126. :param update_table_args: arguments for update table
  127. :type update_table_args: UpdateTableArgs
  128. :param config: None
  129. :type config: BceClientConfiguration
  130. :return:
  131. :rtype baidubce.bce_response.BceResponse
  132. """
  133. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name
  134. return self._send_request(http_methods.PUT, path=path, config=config,
  135. body=json.dumps(update_table_args, default=update_table_args_2_dict),
  136. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  137. def drop_table(self, instance_name, table_name, config=None):
  138. """
  139. drop table
  140. :param instance_name: instance name
  141. :type instance_name: string
  142. :param table_name: table name
  143. :type table_name: string
  144. :param config: None
  145. :type config: BceClientConfiguration
  146. :return:
  147. :rtype baidubce.bce_response.BceResponse
  148. """
  149. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name
  150. return self._send_request(http_methods.DELETE, path=path, config=config)
  151. def show_table(self, instance_name, table_name, config=None):
  152. """
  153. show table
  154. :param instance_name: instance name
  155. :type instance_name: string
  156. :param table_name: table name
  157. :type table_name: string
  158. :param config: None
  159. :type config: BceClientConfiguration
  160. :return:
  161. :rtype baidubce.bce_response.BceResponse
  162. """
  163. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name
  164. return self._send_request(http_methods.GET, path=path, config=config)
  165. def list_tables(self, instance_name, config=None):
  166. """
  167. list tables
  168. :param instance_name: instance name
  169. :type instance_name: string
  170. :param config: None
  171. :type config: BceClientConfiguration
  172. :return:
  173. :rtype baidubce.bce_response.BceResponse
  174. """
  175. path = bts.URL_PREFIX + b"/" + instance_name + b"/tables"
  176. return self._send_request(http_methods.GET, path=path, config=config)
  177. # ------------- row operation -----------
  178. def put_row(self, instance_name, table_name, put_row_args, config=None):
  179. """
  180. put row
  181. :param instance_name: instance name
  182. :type instance_name: string
  183. :param table_name: table name
  184. :type table_name: string
  185. :param put_row_args: arguments for put row
  186. :type put_row_args: Row
  187. :param config: None
  188. :type config: BceClientConfiguration
  189. :return:
  190. :rtype baidubce.bce_response.BceResponse
  191. """
  192. if put_row_args is None or put_row_args.rowkey == "":
  193. ex = BceClientError(INVALID_ARGS_ERROR)
  194. _logger.debug(ex)
  195. raise ex
  196. row_data = {
  197. 'rowkey': _encode(put_row_args.rowkey),
  198. 'cells': []
  199. }
  200. try:
  201. for cell in put_row_args.cells:
  202. if isinstance(cell, Cell):
  203. cell_dict = cell.to_dict()
  204. cell_dict['value'] = _encode(cell_dict['value'])
  205. row_data['cells'].append(cell_dict)
  206. elif isinstance(cell, dict):
  207. cell['value'] = _encode(cell['value'])
  208. row_data['cells'].append(cell)
  209. else:
  210. raise BceClientError(INVALID_ARGS_ERROR)
  211. except Exception as ex:
  212. raise ex
  213. body = json.dumps(row_data)
  214. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/row"
  215. return self._send_request(http_methods.PUT, path=path, config=config,
  216. body=body,
  217. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  218. def batch_put_row(self, instance_name, table_name, batch_put_row_args, config=None):
  219. """
  220. batch put row
  221. :param instance_name: instance name
  222. :type instance_name: string
  223. :param table_name: table name
  224. :type table_name: string
  225. :param batch_put_row_args: arguments for batch put row
  226. :type batch_put_row_args: BatchPutRowArgs
  227. :param config: None
  228. :type config: BceClientConfiguration
  229. :return:
  230. :rtype baidubce.bce_response.BceResponse
  231. """
  232. if batch_put_row_args is None:
  233. ex = BceClientError(INVALID_ARGS_ERROR)
  234. _logger.debug(ex)
  235. raise ex
  236. rows_data = []
  237. for row in batch_put_row_args.rows:
  238. try:
  239. if isinstance(row, Row):
  240. row_data = row.to_dict()
  241. if row_data["rowkey"] == "":
  242. raise BceClientError(INVALID_ARGS_ERROR)
  243. elif isinstance(row, dict):
  244. row_data = copy.deepcopy(row)
  245. if row_data.get("rowkey") == "":
  246. raise BceClientError(INVALID_ARGS_ERROR)
  247. else:
  248. raise BceClientError(INVALID_ARGS_ERROR)
  249. row_data["rowkey"] = _encode(row_data["rowkey"])
  250. for cell in row_data.get("cells", []):
  251. cell["value"] = _encode(cell["value"])
  252. rows_data.append(row_data)
  253. except Exception as ex:
  254. raise ex
  255. body = json.dumps({'rows': rows_data})
  256. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/rows"
  257. return self._send_request(http_methods.PUT, path=path, config=config,
  258. body=body,
  259. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  260. def delete_row(self, instance_name, table_name, delete_row_args, config=None):
  261. """
  262. delete row
  263. :param instance_name: instance name
  264. :type instance_name: string
  265. :param table_name: table name
  266. :type table_name: string
  267. :param delete_row_args: arguments for delete row
  268. :type delete_row_args: QueryRowArgs
  269. :param config: None
  270. :type config: BceClientConfiguration
  271. :return:
  272. :rtype baidubce.bce_response.BceResponse
  273. """
  274. if delete_row_args is None or not hasattr(delete_row_args, 'rowkey') or delete_row_args.rowkey == "":
  275. ex = BceClientError(INVALID_ARGS_ERROR)
  276. _logger.debug(ex)
  277. raise ex
  278. delete_row_data = {
  279. 'rowkey': _encode(delete_row_args.rowkey),
  280. 'cells': []
  281. }
  282. try:
  283. if hasattr(delete_row_args, 'cells') and delete_row_args.cells:
  284. for cell in delete_row_args.cells:
  285. if isinstance(cell, QueryCell):
  286. delete_row_data['cells'].append(cell.to_dict())
  287. elif isinstance(cell, dict):
  288. delete_row_data['cells'].append(cell)
  289. else:
  290. raise BceClientError(INVALID_ARGS_ERROR)
  291. except Exception as ex:
  292. raise ex
  293. body = json.dumps(delete_row_data)
  294. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/row"
  295. return self._send_request(http_methods.DELETE, path=path, config=config,
  296. body=body,
  297. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  298. def batch_delete_row(self, instance_name, table_name, batch_delete_row_args, config=None):
  299. """
  300. batch delete row
  301. :param instance_name: instance name
  302. :type instance_name: string
  303. :param table_name: table name
  304. :type table_name: string
  305. :param batch_delete_row_args: arguments for batch delete row
  306. :type batch_delete_row_args: BatchQueryRowArgs
  307. :param config: None
  308. :type config: BceClientConfiguration
  309. :return:
  310. :rtype baidubce.bce_response.BceResponse
  311. """
  312. if batch_delete_row_args is None or not isinstance(batch_delete_row_args, BatchQueryRowArgs):
  313. raise BceClientError(INVALID_ARGS_ERROR)
  314. rows_data = []
  315. try:
  316. for row in batch_delete_row_args.rows:
  317. if isinstance(row, QueryRowArgs):
  318. row_data = row.to_dict()
  319. elif isinstance(row, dict):
  320. row_data = row
  321. else:
  322. raise BceClientError(INVALID_ARGS_ERROR)
  323. if "rowkey" in row_data and row_data["rowkey"]:
  324. row_data["rowkey"] = _encode(row_data["rowkey"])
  325. else:
  326. raise BceClientError(INVALID_ARGS_ERROR)
  327. rows_data.append(row_data)
  328. except Exception as ex:
  329. raise ex
  330. batch_delete_row_data = {'rows': rows_data}
  331. body = json.dumps(batch_delete_row_data)
  332. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/rows"
  333. return self._send_request(http_methods.DELETE, path=path, config=config,
  334. body=body,
  335. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  336. def get_row(self, instance_name, table_name, get_row_args, config=None):
  337. """
  338. get row
  339. :param instance_name: instance name
  340. :type instance_name: string
  341. :param table_name: table name
  342. :type table_name: string
  343. :param get_row_args: arguments for get row
  344. :type get_row_args: QueryRowArg
  345. :param config: None
  346. :type config: BceClientConfiguration
  347. :return:
  348. :rtype baidubce.bce_response.BceResponse
  349. """
  350. if isinstance(get_row_args, dict):
  351. rowkey = get_row_args.get('rowkey')
  352. elif isinstance(get_row_args, QueryRowArgs):
  353. rowkey = get_row_args.rowkey
  354. else:
  355. raise BceClientError(INVALID_ARGS_ERROR)
  356. if not rowkey:
  357. raise BceClientError(INVALID_ARGS_ERROR)
  358. get_row_data = {
  359. 'rowkey': _encode(rowkey),
  360. 'cells': []
  361. }
  362. if hasattr(get_row_args, 'cells') and get_row_args.cells:
  363. for cell in get_row_args.cells:
  364. if isinstance(cell, QueryCell):
  365. get_row_data['cells'].append(cell.to_dict())
  366. elif isinstance(cell, dict):
  367. get_row_data['cells'].append(cell)
  368. else:
  369. raise BceClientError(INVALID_ARGS_ERROR)
  370. body = json.dumps(get_row_data)
  371. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/row"
  372. response = self._send_request(http_methods.POST, path=path, config=config,
  373. body=body,
  374. headers={http_headers.CONTENT_TYPE: http_content_types.JSON,
  375. http_headers.BTS_METHOD_HEADER: http_methods.GET})
  376. try:
  377. if response.result is not None:
  378. response.result[0].rowkey = _decode(str(response.result[0].rowkey))
  379. for i in range(len(response.result[0].cells)):
  380. response.result[0].cells[i].value = _decode(str(response.result[0].cells[i].value))
  381. except Exception as ex:
  382. raise ex
  383. return response
  384. def batch_get_row(self, instance_name, table_name, batch_get_row_args, config=None):
  385. """
  386. batch get row
  387. :param instance_name: instance name
  388. :type instance_name: string
  389. :param table_name: table name
  390. :type table_name: string
  391. :param batch_get_row_args: arguments for batch get row
  392. :type batch_get_row_args: BatchQueryRowArgs
  393. :param config: None
  394. :type config: BceClientConfiguration
  395. :return:
  396. :rtype baidubce.bce_response.BceResponse
  397. """
  398. batch_get_row_data = {}
  399. if isinstance(batch_get_row_args, BatchQueryRowArgs):
  400. rows_data = []
  401. for row_arg in batch_get_row_args.rows:
  402. if isinstance(row_arg, QueryRowArgs):
  403. row_data = row_arg.to_dict()
  404. elif isinstance(row_arg, dict):
  405. row_data = row_arg
  406. else:
  407. raise BceClientError(INVALID_ARGS_ERROR)
  408. if "rowkey" in row_data and row_data["rowkey"]:
  409. row_data["rowkey"] = _encode(row_data["rowkey"])
  410. else:
  411. raise BceClientError(INVALID_ARGS_ERROR)
  412. rows_data.append(row_data)
  413. batch_get_row_data['rows'] = rows_data
  414. elif isinstance(batch_get_row_args, dict):
  415. batch_get_row_data = batch_get_row_args
  416. else:
  417. raise BceClientError(INVALID_ARGS_ERROR)
  418. body = json.dumps(batch_get_row_data)
  419. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/rows"
  420. response = self._send_request(http_methods.POST, path=path, config=config,
  421. body=body,
  422. headers={http_headers.CONTENT_TYPE: http_content_types.JSON,
  423. http_headers.BTS_METHOD_HEADER: http_methods.GET})
  424. try:
  425. if response.result is not None:
  426. for i in range(len(response.result)):
  427. response.result[i].rowkey = _decode(str(response.result[i].rowkey))
  428. for j in range(len(response.result[i].cells)):
  429. response.result[i].cells[j].value = _decode(str(response.result[i].cells[j].value))
  430. except Exception as ex:
  431. raise ex
  432. return response
  433. def scan(self, instance_name, table_name, scan_args, config=None):
  434. """
  435. scan
  436. :param instance_name: instance name
  437. :type instance_name: string
  438. :param table_name: table name
  439. :type table_name: string
  440. :param scan_args: arguments for scan
  441. :type scan_args: ScanArgs
  442. :param config: None
  443. :type config: BceClientConfiguration
  444. :return:
  445. :rtype baidubce.bce_response.BceResponse
  446. """
  447. if isinstance(scan_args, ScanArgs):
  448. # Convert ScanArgs to a dictionary if necessary
  449. scan_args_dict = scan_args.to_dict() # Assuming ScanArgs has a to_dict() method
  450. elif isinstance(scan_args, dict):
  451. scan_args_dict = scan_args
  452. else:
  453. raise BceClientError(INVALID_ARGS_ERROR)
  454. if "startRowkey" in scan_args_dict and scan_args_dict["startRowkey"]:
  455. scan_args_dict["startRowkey"] = _encode(scan_args_dict["startRowkey"])
  456. if "stopRowkey" in scan_args_dict and scan_args_dict["stopRowkey"]:
  457. scan_args_dict["stopRowkey"] = _encode(scan_args_dict["stopRowkey"])
  458. body = json.dumps(scan_args_dict)
  459. path = bts.URL_PREFIX + b"/" + instance_name + b"/table/" + table_name + b"/rows"
  460. response = self._send_request(http_methods.GET, path=path, config=config,
  461. body=body,
  462. headers={http_headers.CONTENT_TYPE: http_content_types.JSON})
  463. try:
  464. if response.result is not None:
  465. for i in range(len(response.result)):
  466. response.result[i].rowkey = _decode(str(response.result[i].rowkey))
  467. for j in range(len(response.result[i].cells)):
  468. response.result[i].cells[j].value = _decode(str(response.result[i].cells[j].value))
  469. except Exception as ex:
  470. raise ex
  471. return response
  472. def _merge_config(self, config):
  473. if config is None:
  474. return self.config
  475. else:
  476. new_config = copy.copy(self.config)
  477. new_config.merge_non_none_values(config)
  478. return new_config
  479. # ------------- Http Request -----------
  480. def _send_request(
  481. self, http_method, path,
  482. body=None, headers=None, params=None,
  483. config=None,
  484. body_parser=None):
  485. config = self._merge_config(config)
  486. if body_parser is None:
  487. body_parser = handler.parse_json
  488. if config.security_token is not None:
  489. headers = headers or {}
  490. headers[http_headers.STS_SECURITY_TOKEN] = config.security_token
  491. return bce_http_client.send_request(
  492. config, bce_v1_signer.sign, [handler.parse_error, body_parser],
  493. http_method, path, body, headers, params)