client.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. # -*- coding: utf-8 -*-
  2. """Python client for InfluxDB v0.8."""
  3. import warnings
  4. import json
  5. import socket
  6. import requests
  7. import requests.exceptions
  8. from six.moves import xrange
  9. from six.moves.urllib.parse import urlparse
  10. from influxdb import chunked_json
  11. session = requests.Session()
  12. class InfluxDBClientError(Exception):
  13. """Raised when an error occurs in the request."""
  14. def __init__(self, content, code=-1):
  15. """Initialize an InfluxDBClientError handler."""
  16. super(InfluxDBClientError, self).__init__(
  17. "{0}: {1}".format(code, content))
  18. self.content = content
  19. self.code = code
  20. class InfluxDBClient(object):
  21. """Define the standard InfluxDBClient for influxdb v0.8.
  22. The ``InfluxDBClient`` object holds information necessary to connect
  23. to InfluxDB. Requests can be made to InfluxDB directly through the client.
  24. :param host: hostname to connect to InfluxDB, defaults to 'localhost'
  25. :type host: string
  26. :param port: port to connect to InfluxDB, defaults to 'localhost'
  27. :type port: int
  28. :param username: user to connect, defaults to 'root'
  29. :type username: string
  30. :param password: password of the user, defaults to 'root'
  31. :type password: string
  32. :param database: database name to connect to, defaults is None
  33. :type database: string
  34. :param ssl: use https instead of http to connect to InfluxDB, defaults is
  35. False
  36. :type ssl: boolean
  37. :param verify_ssl: verify SSL certificates for HTTPS requests, defaults is
  38. False
  39. :type verify_ssl: boolean
  40. :param retries: number of retries your client will try before aborting,
  41. defaults to 3. 0 indicates try until success
  42. :type retries: int
  43. :param timeout: number of seconds Requests will wait for your client to
  44. establish a connection, defaults to None
  45. :type timeout: int
  46. :param use_udp: use UDP to connect to InfluxDB, defaults is False
  47. :type use_udp: int
  48. :param udp_port: UDP port to connect to InfluxDB, defaults is 4444
  49. :type udp_port: int
  50. """
  51. def __init__(self,
  52. host='localhost',
  53. port=8086,
  54. username='root',
  55. password='root',
  56. database=None,
  57. ssl=False,
  58. verify_ssl=False,
  59. timeout=None,
  60. retries=3,
  61. use_udp=False,
  62. udp_port=4444):
  63. """Construct a new InfluxDBClient object."""
  64. self._host = host
  65. self._port = port
  66. self._username = username
  67. self._password = password
  68. self._database = database
  69. self._timeout = timeout
  70. self._retries = retries
  71. self._verify_ssl = verify_ssl
  72. self._use_udp = use_udp
  73. self._udp_port = udp_port
  74. if use_udp:
  75. self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  76. self._scheme = "http"
  77. if ssl is True:
  78. self._scheme = "https"
  79. self._baseurl = "{0}://{1}:{2}".format(
  80. self._scheme,
  81. self._host,
  82. self._port)
  83. self._headers = {
  84. 'Content-type': 'application/json',
  85. 'Accept': 'text/plain'}
  86. @staticmethod
  87. def from_dsn(dsn, **kwargs):
  88. r"""Return an instaance of InfluxDBClient from given data source name.
  89. Returns an instance of InfluxDBClient from the provided data source
  90. name. Supported schemes are "influxdb", "https+influxdb",
  91. "udp+influxdb". Parameters for the InfluxDBClient constructor may be
  92. also be passed to this function.
  93. Examples:
  94. >> cli = InfluxDBClient.from_dsn('influxdb://username:password@\
  95. ... localhost:8086/databasename', timeout=5)
  96. >> type(cli)
  97. <class 'influxdb.client.InfluxDBClient'>
  98. >> cli = InfluxDBClient.from_dsn('udp+influxdb://username:pass@\
  99. ... localhost:8086/databasename', timeout=5, udp_port=159)
  100. >> print('{0._baseurl} - {0.use_udp} {0.udp_port}'.format(cli))
  101. http://localhost:8086 - True 159
  102. :param dsn: data source name
  103. :type dsn: string
  104. :param **kwargs: additional parameters for InfluxDBClient.
  105. :type **kwargs: dict
  106. :note: parameters provided in **kwargs may override dsn parameters.
  107. :note: when using "udp+influxdb" the specified port (if any) will be
  108. used for the TCP connection; specify the udp port with the additional
  109. udp_port parameter (cf. examples).
  110. :raise ValueError: if the provided DSN has any unexpected value.
  111. """
  112. init_args = {}
  113. conn_params = urlparse(dsn)
  114. scheme_info = conn_params.scheme.split('+')
  115. if len(scheme_info) == 1:
  116. scheme = scheme_info[0]
  117. modifier = None
  118. else:
  119. modifier, scheme = scheme_info
  120. if scheme != 'influxdb':
  121. raise ValueError('Unknown scheme "{0}".'.format(scheme))
  122. if modifier:
  123. if modifier == 'udp':
  124. init_args['use_udp'] = True
  125. elif modifier == 'https':
  126. init_args['ssl'] = True
  127. else:
  128. raise ValueError('Unknown modifier "{0}".'.format(modifier))
  129. if conn_params.hostname:
  130. init_args['host'] = conn_params.hostname
  131. if conn_params.port:
  132. init_args['port'] = conn_params.port
  133. if conn_params.username:
  134. init_args['username'] = conn_params.username
  135. if conn_params.password:
  136. init_args['password'] = conn_params.password
  137. if conn_params.path and len(conn_params.path) > 1:
  138. init_args['database'] = conn_params.path[1:]
  139. init_args.update(kwargs)
  140. return InfluxDBClient(**init_args)
  141. # Change member variables
  142. def switch_database(self, database):
  143. """Change client database.
  144. :param database: the new database name to switch to
  145. :type database: string
  146. """
  147. self._database = database
  148. def switch_db(self, database):
  149. """Change client database.
  150. DEPRECATED.
  151. """
  152. warnings.warn(
  153. "switch_db is deprecated, and will be removed "
  154. "in future versions. Please use "
  155. "``InfluxDBClient.switch_database(database)`` instead.",
  156. FutureWarning)
  157. return self.switch_database(database)
  158. def switch_user(self, username, password):
  159. """Change client username.
  160. :param username: the new username to switch to
  161. :type username: string
  162. :param password: the new password to switch to
  163. :type password: string
  164. """
  165. self._username = username
  166. self._password = password
  167. def request(self, url, method='GET', params=None, data=None,
  168. expected_response_code=200):
  169. """Make a http request to API."""
  170. url = "{0}/{1}".format(self._baseurl, url)
  171. if params is None:
  172. params = {}
  173. auth = {
  174. 'u': self._username,
  175. 'p': self._password
  176. }
  177. params.update(auth)
  178. if data is not None and not isinstance(data, str):
  179. data = json.dumps(data)
  180. retry = True
  181. _try = 0
  182. # Try to send the request more than once by default (see #103)
  183. while retry:
  184. try:
  185. response = session.request(
  186. method=method,
  187. url=url,
  188. params=params,
  189. data=data,
  190. headers=self._headers,
  191. verify=self._verify_ssl,
  192. timeout=self._timeout
  193. )
  194. break
  195. except (requests.exceptions.ConnectionError,
  196. requests.exceptions.Timeout):
  197. _try += 1
  198. if self._retries != 0:
  199. retry = _try < self._retries
  200. else:
  201. raise requests.exceptions.ConnectionError
  202. if response.status_code == expected_response_code:
  203. return response
  204. else:
  205. raise InfluxDBClientError(response.content, response.status_code)
  206. def write(self, data):
  207. """Provide as convenience for influxdb v0.9.0, this may change."""
  208. self.request(
  209. url="write",
  210. method='POST',
  211. params=None,
  212. data=data,
  213. expected_response_code=200
  214. )
  215. return True
  216. # Writing Data
  217. #
  218. # Assuming you have a database named foo_production you can write data
  219. # by doing a POST to /db/foo_production/series?u=some_user&p=some_password
  220. # with a JSON body of points.
  221. def write_points(self, data, time_precision='s', *args, **kwargs):
  222. """Write to multiple time series names.
  223. An example data blob is:
  224. data = [
  225. {
  226. "points": [
  227. [
  228. 12
  229. ]
  230. ],
  231. "name": "cpu_load_short",
  232. "columns": [
  233. "value"
  234. ]
  235. }
  236. ]
  237. :param data: A list of dicts in InfluxDB 0.8.x data format.
  238. :param time_precision: [Optional, default 's'] Either 's', 'm', 'ms'
  239. or 'u'.
  240. :param batch_size: [Optional] Value to write the points in batches
  241. instead of all at one time. Useful for when doing data dumps from
  242. one database to another or when doing a massive write operation
  243. :type batch_size: int
  244. """
  245. def list_chunks(l, n):
  246. """Yield successive n-sized chunks from l."""
  247. for i in xrange(0, len(l), n):
  248. yield l[i:i + n]
  249. batch_size = kwargs.get('batch_size')
  250. if batch_size and batch_size > 0:
  251. for item in data:
  252. name = item.get('name')
  253. columns = item.get('columns')
  254. point_list = item.get('points', [])
  255. for batch in list_chunks(point_list, batch_size):
  256. item = [{
  257. "points": batch,
  258. "name": name,
  259. "columns": columns
  260. }]
  261. self._write_points(
  262. data=item,
  263. time_precision=time_precision)
  264. return True
  265. return self._write_points(data=data,
  266. time_precision=time_precision)
  267. def write_points_with_precision(self, data, time_precision='s'):
  268. """Write to multiple time series names.
  269. DEPRECATED.
  270. """
  271. warnings.warn(
  272. "write_points_with_precision is deprecated, and will be removed "
  273. "in future versions. Please use "
  274. "``InfluxDBClient.write_points(time_precision='..')`` instead.",
  275. FutureWarning)
  276. return self._write_points(data=data, time_precision=time_precision)
  277. def _write_points(self, data, time_precision):
  278. if time_precision not in ['s', 'm', 'ms', 'u']:
  279. raise Exception(
  280. "Invalid time precision is given. (use 's', 'm', 'ms' or 'u')")
  281. if self._use_udp and time_precision != 's':
  282. raise Exception(
  283. "InfluxDB only supports seconds precision for udp writes"
  284. )
  285. url = "db/{0}/series".format(self._database)
  286. params = {
  287. 'time_precision': time_precision
  288. }
  289. if self._use_udp:
  290. self.send_packet(data)
  291. else:
  292. self.request(
  293. url=url,
  294. method='POST',
  295. params=params,
  296. data=data,
  297. expected_response_code=200
  298. )
  299. return True
  300. # One Time Deletes
  301. def delete_points(self, name):
  302. """Delete an entire series."""
  303. url = "db/{0}/series/{1}".format(self._database, name)
  304. self.request(
  305. url=url,
  306. method='DELETE',
  307. expected_response_code=204
  308. )
  309. return True
  310. # Regularly Scheduled Deletes
  311. def create_scheduled_delete(self, json_body):
  312. """Create schedule delete from database.
  313. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  314. but it is documented in http://influxdb.org/docs/api/http.html.
  315. See also: src/api/http/api.go:l57
  316. """
  317. raise NotImplementedError()
  318. # get list of deletes
  319. # curl http://localhost:8086/db/site_dev/scheduled_deletes
  320. #
  321. # remove a regularly scheduled delete
  322. # curl -X DELETE http://localhost:8086/db/site_dev/scheduled_deletes/:id
  323. def get_list_scheduled_delete(self):
  324. """Get list of scheduled deletes.
  325. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  326. but it is documented in http://influxdb.org/docs/api/http.html.
  327. See also: src/api/http/api.go:l57
  328. """
  329. raise NotImplementedError()
  330. def remove_scheduled_delete(self, delete_id):
  331. """Remove scheduled delete.
  332. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  333. but it is documented in http://influxdb.org/docs/api/http.html.
  334. See also: src/api/http/api.go:l57
  335. """
  336. raise NotImplementedError()
  337. def query(self, query, time_precision='s', chunked=False):
  338. """Query data from the influxdb v0.8 database.
  339. :param time_precision: [Optional, default 's'] Either 's', 'm', 'ms'
  340. or 'u'.
  341. :param chunked: [Optional, default=False] True if the data shall be
  342. retrieved in chunks, False otherwise.
  343. """
  344. return self._query(query, time_precision=time_precision,
  345. chunked=chunked)
  346. # Querying Data
  347. #
  348. # GET db/:name/series. It takes five parameters
  349. def _query(self, query, time_precision='s', chunked=False):
  350. if time_precision not in ['s', 'm', 'ms', 'u']:
  351. raise Exception(
  352. "Invalid time precision is given. (use 's', 'm', 'ms' or 'u')")
  353. if chunked is True:
  354. chunked_param = 'true'
  355. else:
  356. chunked_param = 'false'
  357. # Build the URL of the series to query
  358. url = "db/{0}/series".format(self._database)
  359. params = {
  360. 'q': query,
  361. 'time_precision': time_precision,
  362. 'chunked': chunked_param
  363. }
  364. response = self.request(
  365. url=url,
  366. method='GET',
  367. params=params,
  368. expected_response_code=200
  369. )
  370. if chunked:
  371. try:
  372. decoded = chunked_json.loads(response.content.decode())
  373. except UnicodeDecodeError:
  374. decoded = chunked_json.loads(response.content.decode('utf-8'))
  375. return list(decoded)
  376. return response.json()
  377. # Creating and Dropping Databases
  378. #
  379. # ### create a database
  380. # curl -X POST http://localhost:8086/db -d '{"name": "site_development"}'
  381. #
  382. # ### drop a database
  383. # curl -X DELETE http://localhost:8086/db/site_development
  384. def create_database(self, database):
  385. """Create a database on the InfluxDB server.
  386. :param database: the name of the database to create
  387. :type database: string
  388. :rtype: boolean
  389. """
  390. url = "db"
  391. data = {'name': database}
  392. self.request(
  393. url=url,
  394. method='POST',
  395. data=data,
  396. expected_response_code=201
  397. )
  398. return True
  399. def delete_database(self, database):
  400. """Drop a database on the InfluxDB server.
  401. :param database: the name of the database to delete
  402. :type database: string
  403. :rtype: boolean
  404. """
  405. url = "db/{0}".format(database)
  406. self.request(
  407. url=url,
  408. method='DELETE',
  409. expected_response_code=204
  410. )
  411. return True
  412. # ### get list of databases
  413. # curl -X GET http://localhost:8086/db
  414. def get_list_database(self):
  415. """Get the list of databases."""
  416. url = "db"
  417. response = self.request(
  418. url=url,
  419. method='GET',
  420. expected_response_code=200
  421. )
  422. return response.json()
  423. def get_database_list(self):
  424. """Get the list of databases.
  425. DEPRECATED.
  426. """
  427. warnings.warn(
  428. "get_database_list is deprecated, and will be removed "
  429. "in future versions. Please use "
  430. "``InfluxDBClient.get_list_database`` instead.",
  431. FutureWarning)
  432. return self.get_list_database()
  433. def delete_series(self, series):
  434. """Drop a series on the InfluxDB server.
  435. :param series: the name of the series to delete
  436. :type series: string
  437. :rtype: boolean
  438. """
  439. url = "db/{0}/series/{1}".format(
  440. self._database,
  441. series
  442. )
  443. self.request(
  444. url=url,
  445. method='DELETE',
  446. expected_response_code=204
  447. )
  448. return True
  449. def get_list_series(self):
  450. """Get a list of all time series in a database."""
  451. response = self._query('list series')
  452. return [series[1] for series in response[0]['points']]
  453. def get_list_continuous_queries(self):
  454. """Get a list of continuous queries."""
  455. response = self._query('list continuous queries')
  456. return [query[2] for query in response[0]['points']]
  457. # Security
  458. # get list of cluster admins
  459. # curl http://localhost:8086/cluster_admins?u=root&p=root
  460. # add cluster admin
  461. # curl -X POST http://localhost:8086/cluster_admins?u=root&p=root \
  462. # -d '{"name": "paul", "password": "i write teh docz"}'
  463. # update cluster admin password
  464. # curl -X POST http://localhost:8086/cluster_admins/paul?u=root&p=root \
  465. # -d '{"password": "new pass"}'
  466. # delete cluster admin
  467. # curl -X DELETE http://localhost:8086/cluster_admins/paul?u=root&p=root
  468. # Database admins, with a database name of site_dev
  469. # get list of database admins
  470. # curl http://localhost:8086/db/site_dev/admins?u=root&p=root
  471. # add database admin
  472. # curl -X POST http://localhost:8086/db/site_dev/admins?u=root&p=root \
  473. # -d '{"name": "paul", "password": "i write teh docz"}'
  474. # update database admin password
  475. # curl -X POST http://localhost:8086/db/site_dev/admins/paul?u=root&p=root\
  476. # -d '{"password": "new pass"}'
  477. # delete database admin
  478. # curl -X DELETE \
  479. # http://localhost:8086/db/site_dev/admins/paul?u=root&p=root
  480. def get_list_cluster_admins(self):
  481. """Get list of cluster admins."""
  482. response = self.request(
  483. url="cluster_admins",
  484. method='GET',
  485. expected_response_code=200
  486. )
  487. return response.json()
  488. def add_cluster_admin(self, new_username, new_password):
  489. """Add cluster admin."""
  490. data = {
  491. 'name': new_username,
  492. 'password': new_password
  493. }
  494. self.request(
  495. url="cluster_admins",
  496. method='POST',
  497. data=data,
  498. expected_response_code=200
  499. )
  500. return True
  501. def update_cluster_admin_password(self, username, new_password):
  502. """Update cluster admin password."""
  503. url = "cluster_admins/{0}".format(username)
  504. data = {
  505. 'password': new_password
  506. }
  507. self.request(
  508. url=url,
  509. method='POST',
  510. data=data,
  511. expected_response_code=200
  512. )
  513. return True
  514. def delete_cluster_admin(self, username):
  515. """Delete cluster admin."""
  516. url = "cluster_admins/{0}".format(username)
  517. self.request(
  518. url=url,
  519. method='DELETE',
  520. expected_response_code=200
  521. )
  522. return True
  523. def set_database_admin(self, username):
  524. """Set user as database admin."""
  525. return self.alter_database_admin(username, True)
  526. def unset_database_admin(self, username):
  527. """Unset user as database admin."""
  528. return self.alter_database_admin(username, False)
  529. def alter_database_admin(self, username, is_admin):
  530. """Alter the database admin."""
  531. url = "db/{0}/users/{1}".format(self._database, username)
  532. data = {'admin': is_admin}
  533. self.request(
  534. url=url,
  535. method='POST',
  536. data=data,
  537. expected_response_code=200
  538. )
  539. return True
  540. def get_list_database_admins(self):
  541. """Get list of database admins.
  542. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  543. but it is documented in http://influxdb.org/docs/api/http.html.
  544. See also: src/api/http/api.go:l57
  545. """
  546. raise NotImplementedError()
  547. def add_database_admin(self, new_username, new_password):
  548. """Add cluster admin.
  549. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  550. but it is documented in http://influxdb.org/docs/api/http.html.
  551. See also: src/api/http/api.go:l57
  552. """
  553. raise NotImplementedError()
  554. def update_database_admin_password(self, username, new_password):
  555. """Update database admin password.
  556. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  557. but it is documented in http://influxdb.org/docs/api/http.html.
  558. See also: src/api/http/api.go:l57
  559. """
  560. raise NotImplementedError()
  561. def delete_database_admin(self, username):
  562. """Delete database admin.
  563. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  564. but it is documented in http://influxdb.org/docs/api/http.html.
  565. See also: src/api/http/api.go:l57
  566. """
  567. raise NotImplementedError()
  568. ###
  569. # Limiting User Access
  570. # Database users
  571. # get list of database users
  572. # curl http://localhost:8086/db/site_dev/users?u=root&p=root
  573. # add database user
  574. # curl -X POST http://localhost:8086/db/site_dev/users?u=root&p=root \
  575. # -d '{"name": "paul", "password": "i write teh docz"}'
  576. # update database user password
  577. # curl -X POST http://localhost:8086/db/site_dev/users/paul?u=root&p=root \
  578. # -d '{"password": "new pass"}'
  579. # delete database user
  580. # curl -X DELETE http://localhost:8086/db/site_dev/users/paul?u=root&p=root
  581. def get_database_users(self):
  582. """Get list of database users."""
  583. url = "db/{0}/users".format(self._database)
  584. response = self.request(
  585. url=url,
  586. method='GET',
  587. expected_response_code=200
  588. )
  589. return response.json()
  590. def add_database_user(self, new_username, new_password, permissions=None):
  591. """Add database user.
  592. :param permissions: A ``(readFrom, writeTo)`` tuple
  593. """
  594. url = "db/{0}/users".format(self._database)
  595. data = {
  596. 'name': new_username,
  597. 'password': new_password
  598. }
  599. if permissions:
  600. try:
  601. data['readFrom'], data['writeTo'] = permissions
  602. except (ValueError, TypeError):
  603. raise TypeError(
  604. "'permissions' must be (readFrom, writeTo) tuple"
  605. )
  606. self.request(
  607. url=url,
  608. method='POST',
  609. data=data,
  610. expected_response_code=200
  611. )
  612. return True
  613. def update_database_user_password(self, username, new_password):
  614. """Update password."""
  615. return self.alter_database_user(username, new_password)
  616. def alter_database_user(self, username, password=None, permissions=None):
  617. """Alter a database user and/or their permissions.
  618. :param permissions: A ``(readFrom, writeTo)`` tuple
  619. :raise TypeError: if permissions cannot be read.
  620. :raise ValueError: if neither password nor permissions provided.
  621. """
  622. url = "db/{0}/users/{1}".format(self._database, username)
  623. if not password and not permissions:
  624. raise ValueError("Nothing to alter for user {0}.".format(username))
  625. data = {}
  626. if password:
  627. data['password'] = password
  628. if permissions:
  629. try:
  630. data['readFrom'], data['writeTo'] = permissions
  631. except (ValueError, TypeError):
  632. raise TypeError(
  633. "'permissions' must be (readFrom, writeTo) tuple"
  634. )
  635. self.request(
  636. url=url,
  637. method='POST',
  638. data=data,
  639. expected_response_code=200
  640. )
  641. if username == self._username:
  642. self._password = password
  643. return True
  644. def delete_database_user(self, username):
  645. """Delete database user."""
  646. url = "db/{0}/users/{1}".format(self._database, username)
  647. self.request(
  648. url=url,
  649. method='DELETE',
  650. expected_response_code=200
  651. )
  652. return True
  653. # update the user by POSTing to db/site_dev/users/paul
  654. def update_permission(self, username, json_body):
  655. """Update read/write permission.
  656. 2013-11-08: This endpoint has not been implemented yet in ver0.0.8,
  657. but it is documented in http://influxdb.org/docs/api/http.html.
  658. See also: src/api/http/api.go:l57
  659. """
  660. raise NotImplementedError()
  661. def send_packet(self, packet):
  662. """Send a UDP packet along the wire."""
  663. data = json.dumps(packet)
  664. byte = data.encode('utf-8')
  665. self.udp_socket.sendto(byte, (self._host, self._udp_port))