From e683a1c933b2785bdf908f394e48c5d1cf5d91e3 Mon Sep 17 00:00:00 2001 From: Georgi Dimitrov Date: Mon, 4 May 2015 17:19:58 +0100 Subject: [PATCH 1/5] Add alter_retention_policy method to the client. --- influxdb/client.py | 37 +++++++++++++++ tests/influxdb/client_test.py | 38 ++++++++++++++++ tests/influxdb/client_test_with_server.py | 55 +++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/influxdb/client.py b/influxdb/client.py index 35fdad4a..e4b9cbc7 100755 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -470,6 +470,43 @@ def create_retention_policy(self, name, duration, replication, self.query(query_string) + def alter_retention_policy(self, name, database=None, + duration=None, replication=None, default=None): + """Mofidy an existing retention policy for a database. + + :param name: the name of the retention policy to modify + :type name: str + :param database: the database for which the retention policy is + modified. Defaults to current client's database + :type database: str + :param duration: the new duration of the existing retention policy. + Durations such as 1h, 90m, 12h, 7d, and 4w, are all supported + and mean 1 hour, 90 minutes, 12 hours, 7 day, and 4 weeks, + respectively. For infinite retention – meaning the data will + never be deleted – use 'INF' for duration. + The minimum retention period is 1 hour. + :type duration: str + :param replication: the new replication of the existing + retention policy + :type replication: str + :param default: whether or not to set the modified policy as default + :type default: bool + + .. note:: at least one of duration, replication, or default flag + should be set. Otherwise the operation will fail. + """ + query_string = ( + "ALTER RETENTION POLICY {} ON {}" + ).format(name, database or self._database) + if duration: + query_string += " DURATION {}".format(duration) + if replication: + query_string += " REPLICATION {}".format(replication) + if default is True: + query_string += " DEFAULT" + + self.query(query_string) + def get_list_retention_policies(self, database=None): """Get the list of retention policies for a database. diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index c81c3c30..266bdd24 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -490,6 +490,44 @@ def test_create_retention_policy(self): 'db duration 1d replication 4' ) + def test_alter_retention_policy(self): + example_response = '{"results":[{}]}' + + with requests_mock.Mocker() as m: + m.register_uri( + requests_mock.GET, + "http://localhost:8086/query", + text=example_response + ) + # Test alter duration + self.cli.alter_retention_policy('somename', 'db', + duration='4d') + self.assertEqual( + m.last_request.qs['q'][0], + 'alter retention policy somename on db duration 4d' + ) + # Test alter replication + self.cli.alter_retention_policy('somename', 'db', + replication=4) + self.assertEqual( + m.last_request.qs['q'][0], + 'alter retention policy somename on db replication 4' + ) + + # Test alter default + self.cli.alter_retention_policy('somename', 'db', + default=True) + self.assertEqual( + m.last_request.qs['q'][0], + 'alter retention policy somename on db default' + ) + + @raises(Exception) + def test_alter_retention_policy_invalid(self): + cli = InfluxDBClient('host', 8086, 'username', 'password') + with _mocked_session(cli, 'get', 400): + self.cli.alter_retention_policy('somename', 'db') + def test_get_list_retention_policies(self): example_response = \ '{"results": [{"series": [{"values": [["fsfdsdf", "24h0m0s", 2]],'\ diff --git a/tests/influxdb/client_test_with_server.py b/tests/influxdb/client_test_with_server.py index 7b9a70ee..997e7b06 100644 --- a/tests/influxdb/client_test_with_server.py +++ b/tests/influxdb/client_test_with_server.py @@ -657,6 +657,61 @@ def test_create_retention_policy(self): rsp ) + def test_alter_retention_policy(self): + self.cli.create_retention_policy('somename', '1d', 1) + + # Test alter duration + self.cli.alter_retention_policy('somename', 'db', + duration='4d') + rsp = self.cli.get_list_retention_policies() + self.assertEqual( + [{'duration': '0', 'default': True, + 'replicaN': 1, 'name': 'default'}, + {'duration': '96h0m0s', 'default': False, + 'replicaN': 1, 'name': 'somename'}], + rsp + ) + + # Test alter replication + self.cli.alter_retention_policy('somename', 'db', + replication=4) + rsp = self.cli.get_list_retention_policies() + self.assertEqual( + [{'duration': '0', 'default': True, + 'replicaN': 1, 'name': 'default'}, + {'duration': '96h0m0s', 'default': False, + 'replicaN': 4, 'name': 'somename'}], + rsp + ) + + # Test alter default + self.cli.alter_retention_policy('somename', 'db', + default=True) + rsp = self.cli.get_list_retention_policies() + self.assertEqual( + [{'duration': '0', 'default': False, + 'replicaN': 1, 'name': 'default'}, + {'duration': '96h0m0s', 'default': True, + 'replicaN': 4, 'name': 'somename'}], + rsp + ) + + def test_alter_retention_policy_invalid(self): + self.cli.create_retention_policy('somename', '1d', 1) + with self.assertRaises(InfluxDBClientError) as ctx: + self.cli.alter_retention_policy('somename', 'db') + self.assertEqual(400, ctx.exception.code) + self.assertIn('{"error":"error parsing query: ', + ctx.exception.content) + rsp = self.cli.get_list_retention_policies() + self.assertEqual( + [{'duration': '0', 'default': True, + 'replicaN': 1, 'name': 'default'}, + {'duration': '24h0m0s', 'default': False, + 'replicaN': 1, 'name': 'somename'}], + rsp + ) + def test_issue_143(self): pt = partial(point, 'a_serie_name', timestamp='2015-03-30T16:16:37Z') pts = [ From 352071492a0ff518e6f000963deb121071aca651 Mon Sep 17 00:00:00 2001 From: Georgi Dimitrov Date: Mon, 4 May 2015 18:45:54 +0100 Subject: [PATCH 2/5] Add grant_admin_privileges method to the client. --- influxdb/client.py | 12 ++++++++++++ tests/influxdb/client_test.py | 22 ++++++++++++++++++++++ tests/influxdb/client_test_with_server.py | 15 +++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/influxdb/client.py b/influxdb/client.py index e4b9cbc7..15562920 100755 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -618,6 +618,18 @@ def delete_series(self, name, database=None): database = database or self._database self.query('DROP SERIES \"%s\"' % name, database=database) + def grant_admin_privileges(self, username): + """Grant cluster administration privileges to an user. + + :param username: the username to grant privileges to + :type username: str + + .. note:: Only a cluster administrator can create/ drop databases + and manage users. + """ + text = "GRANT ALL PRIVILEGES TO {}".format(username) + self.query(text) + def send_packet(self, packet): """Send an UDP packet. diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 266bdd24..5f8a0528 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -624,6 +624,28 @@ def test_get_list_users_empty(self): self.assertListEqual(self.cli.get_list_users(), []) + def test_grant_admin_privileges(self): + example_response = '{"results":[{}]}' + + with requests_mock.Mocker() as m: + m.register_uri( + requests_mock.GET, + "http://localhost:8086/query", + text=example_response + ) + self.cli.grant_admin_privileges('test') + + self.assertEqual( + m.last_request.qs['q'][0], + 'grant all privileges to test' + ) + + @raises(Exception) + def test_grant_admin_privileges_invalid(self): + cli = InfluxDBClient('host', 8086, 'username', 'password') + with _mocked_session(cli, 'get', 400): + self.cli.grant_admin_privileges('') + class FakeClient(InfluxDBClient): fail = False diff --git a/tests/influxdb/client_test_with_server.py b/tests/influxdb/client_test_with_server.py index 997e7b06..41adee55 100644 --- a/tests/influxdb/client_test_with_server.py +++ b/tests/influxdb/client_test_with_server.py @@ -376,6 +376,21 @@ def test_drop_user_invalid(self): 'found invalid, expected', ctx.exception.content) + def test_grant_admin_privileges(self): + self.cli.create_user('test', 'test') + self.assertEqual([{'user': 'test', 'admin': False}], + self.cli.get_list_users()) + self.cli.grant_admin_privileges('test') + self.assertEqual([{'user': 'test', 'admin': True}], + self.cli.get_list_users()) + + def test_grant_admin_privileges_invalid(self): + with self.assertRaises(InfluxDBClientError) as ctx: + self.cli.grant_admin_privileges('') + self.assertEqual(400, ctx.exception.code) + self.assertIn('{"error":"error parsing query: ', + ctx.exception.content) + ############################################################################ From a4072b10706e4973c9563087d4dedc0628525c4b Mon Sep 17 00:00:00 2001 From: Georgi Dimitrov Date: Mon, 4 May 2015 19:02:35 +0100 Subject: [PATCH 3/5] Add revoke_admin_privileges to the client. --- influxdb/client.py | 12 ++++++++++++ tests/influxdb/client_test.py | 22 ++++++++++++++++++++++ tests/influxdb/client_test_with_server.py | 16 ++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/influxdb/client.py b/influxdb/client.py index 15562920..cd53a3e9 100755 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -630,6 +630,18 @@ def grant_admin_privileges(self, username): text = "GRANT ALL PRIVILEGES TO {}".format(username) self.query(text) + def revoke_admin_privileges(self, username): + """Revoke cluster administration privileges from an user. + + :param username: the username to revoke privileges from + :type username: str + + .. note:: Only a cluster administrator can create/ drop databases + and manage users. + """ + text = "REVOKE ALL PRIVILEGES FROM {}".format(username) + self.query(text) + def send_packet(self, packet): """Send an UDP packet. diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 5f8a0528..7720d1ed 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -646,6 +646,28 @@ def test_grant_admin_privileges_invalid(self): with _mocked_session(cli, 'get', 400): self.cli.grant_admin_privileges('') + def test_revoke_admin_privileges(self): + example_response = '{"results":[{}]}' + + with requests_mock.Mocker() as m: + m.register_uri( + requests_mock.GET, + "http://localhost:8086/query", + text=example_response + ) + self.cli.revoke_admin_privileges('test') + + self.assertEqual( + m.last_request.qs['q'][0], + 'revoke all privileges from test' + ) + + @raises(Exception) + def test_revoke_admin_privileges_invalid(self): + cli = InfluxDBClient('host', 8086, 'username', 'password') + with _mocked_session(cli, 'get', 400): + self.cli.revoke_admin_privileges('') + class FakeClient(InfluxDBClient): fail = False diff --git a/tests/influxdb/client_test_with_server.py b/tests/influxdb/client_test_with_server.py index 41adee55..d6bf4282 100644 --- a/tests/influxdb/client_test_with_server.py +++ b/tests/influxdb/client_test_with_server.py @@ -391,6 +391,22 @@ def test_grant_admin_privileges_invalid(self): self.assertIn('{"error":"error parsing query: ', ctx.exception.content) + def test_revoke_admin_privileges(self): + self.cli.create_user('test', 'test') + self.cli.grant_admin_privileges('test') + self.assertEqual([{'user': 'test', 'admin': True}], + self.cli.get_list_users()) + self.cli.revoke_admin_privileges('test') + self.assertEqual([{'user': 'test', 'admin': False}], + self.cli.get_list_users()) + + def test_revoke_admin_privileges_invalid(self): + with self.assertRaises(InfluxDBClientError) as ctx: + self.cli.revoke_admin_privileges('') + self.assertEqual(400, ctx.exception.code) + self.assertIn('{"error":"error parsing query: ', + ctx.exception.content) + ############################################################################ From 36e50eacf3e3ad7daa83e9d9c935fe3b23d0fdf7 Mon Sep 17 00:00:00 2001 From: Georgi Dimitrov Date: Mon, 4 May 2015 20:42:07 +0100 Subject: [PATCH 4/5] Add grant_priviliege method to the client. --- influxdb/client.py | 16 ++++++++++++++++ tests/influxdb/client_test.py | 22 ++++++++++++++++++++++ tests/influxdb/client_test_with_server.py | 15 +++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/influxdb/client.py b/influxdb/client.py index cd53a3e9..3efa1b49 100755 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -642,6 +642,22 @@ def revoke_admin_privileges(self, username): text = "REVOKE ALL PRIVILEGES FROM {}".format(username) self.query(text) + def grant_privilege(self, privilege, database, username): + """Grant a privilege on a database to an user. + + :param privilege: the privilege to grant, one of 'read', 'write' + or 'all'. The string is case-insensitive + :type privilege: str + :param database: the database to grant the privilege on + :type database: str + :param username: the username to grant the privilege to + :type username: str + """ + text = "GRANT {} ON {} TO {}".format(privilege, + database, + username) + self.query(text) + def send_packet(self, packet): """Send an UDP packet. diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 7720d1ed..1b368c2d 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -668,6 +668,28 @@ def test_revoke_admin_privileges_invalid(self): with _mocked_session(cli, 'get', 400): self.cli.revoke_admin_privileges('') + def test_grant_privilege(self): + example_response = '{"results":[{}]}' + + with requests_mock.Mocker() as m: + m.register_uri( + requests_mock.GET, + "http://localhost:8086/query", + text=example_response + ) + self.cli.grant_privilege('read', 'testdb', 'test') + + self.assertEqual( + m.last_request.qs['q'][0], + 'grant read on testdb to test' + ) + + @raises(Exception) + def test_grant_privilege_invalid(self): + cli = InfluxDBClient('host', 8086, 'username', 'password') + with _mocked_session(cli, 'get', 400): + self.cli.grant_privilege('', 'testdb', 'test') + class FakeClient(InfluxDBClient): fail = False diff --git a/tests/influxdb/client_test_with_server.py b/tests/influxdb/client_test_with_server.py index d6bf4282..208f265d 100644 --- a/tests/influxdb/client_test_with_server.py +++ b/tests/influxdb/client_test_with_server.py @@ -407,6 +407,21 @@ def test_revoke_admin_privileges_invalid(self): self.assertIn('{"error":"error parsing query: ', ctx.exception.content) + def test_grant_privilege(self): + self.cli.create_user('test', 'test') + self.cli.create_database('testdb') + self.cli.grant_privilege('all', 'testdb', 'test') + # TODO: when supported by InfluxDB, check if privileges are granted + + def test_grant_privilege_invalid(self): + self.cli.create_user('test', 'test') + self.cli.create_database('testdb') + with self.assertRaises(InfluxDBClientError) as ctx: + self.cli.grant_privilege('', 'testdb', 'test') + self.assertEqual(400, ctx.exception.code) + self.assertIn('{"error":"error parsing query: ', + ctx.exception.content) + ############################################################################ From 731c4e0730118d5f131c4b1918b50c7ddbd18a8b Mon Sep 17 00:00:00 2001 From: Georgi Dimitrov Date: Mon, 4 May 2015 20:42:28 +0100 Subject: [PATCH 5/5] Add revoke_privilege method to the client. --- influxdb/client.py | 16 ++++++++++++++++ tests/influxdb/client_test.py | 22 ++++++++++++++++++++++ tests/influxdb/client_test_with_server.py | 15 +++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/influxdb/client.py b/influxdb/client.py index 3efa1b49..a31373ed 100755 --- a/influxdb/client.py +++ b/influxdb/client.py @@ -658,6 +658,22 @@ def grant_privilege(self, privilege, database, username): username) self.query(text) + def revoke_privilege(self, privilege, database, username): + """Revoke a privilege on a database from an user. + + :param privilege: the privilege to revoke, one of 'read', 'write' + or 'all'. The string is case-insensitive + :type privilege: str + :param database: the database to revoke the privilege on + :type database: str + :param username: the username to revoke the privilege from + :type username: str + """ + text = "REVOKE {} ON {} FROM {}".format(privilege, + database, + username) + self.query(text) + def send_packet(self, packet): """Send an UDP packet. diff --git a/tests/influxdb/client_test.py b/tests/influxdb/client_test.py index 1b368c2d..04342ac2 100644 --- a/tests/influxdb/client_test.py +++ b/tests/influxdb/client_test.py @@ -690,6 +690,28 @@ def test_grant_privilege_invalid(self): with _mocked_session(cli, 'get', 400): self.cli.grant_privilege('', 'testdb', 'test') + def test_revoke_privilege(self): + example_response = '{"results":[{}]}' + + with requests_mock.Mocker() as m: + m.register_uri( + requests_mock.GET, + "http://localhost:8086/query", + text=example_response + ) + self.cli.revoke_privilege('read', 'testdb', 'test') + + self.assertEqual( + m.last_request.qs['q'][0], + 'revoke read on testdb from test' + ) + + @raises(Exception) + def test_revoke_privilege_invalid(self): + cli = InfluxDBClient('host', 8086, 'username', 'password') + with _mocked_session(cli, 'get', 400): + self.cli.revoke_privilege('', 'testdb', 'test') + class FakeClient(InfluxDBClient): fail = False diff --git a/tests/influxdb/client_test_with_server.py b/tests/influxdb/client_test_with_server.py index 208f265d..8cf7c8d4 100644 --- a/tests/influxdb/client_test_with_server.py +++ b/tests/influxdb/client_test_with_server.py @@ -422,6 +422,21 @@ def test_grant_privilege_invalid(self): self.assertIn('{"error":"error parsing query: ', ctx.exception.content) + def test_revoke_privilege(self): + self.cli.create_user('test', 'test') + self.cli.create_database('testdb') + self.cli.revoke_privilege('all', 'testdb', 'test') + # TODO: when supported by InfluxDB, check if privileges are revoked + + def test_revoke_privilege_invalid(self): + self.cli.create_user('test', 'test') + self.cli.create_database('testdb') + with self.assertRaises(InfluxDBClientError) as ctx: + self.cli.revoke_privilege('', 'testdb', 'test') + self.assertEqual(400, ctx.exception.code) + self.assertIn('{"error":"error parsing query: ', + ctx.exception.content) + ############################################################################