1
# Copyright (c) 2013 OpenStack Foundation
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
17
from trove.common import cfg
18
from trove.guestagent.datastore.postgresql import pgutil
19
from trove.guestagent.datastore.postgresql.service.access import PgSqlAccess
20
from trove.openstack.common import log as logging
21
from trove.common.i18n import _
23
LOG = logging.getLogger(__name__)
25
IGNORE_USERS_LIST = CONF.get(CONF.datastore_manager).ignore_users
28
class PgSqlUsers(PgSqlAccess):
29
"""Mixin implementing the user CRUD API.
31
This mixin has a dependency on the PgSqlAccess mixin.
34
def create_user(self, context, users):
35
"""Create users and grant privileges for the specified databases.
37
The users parameter is a list of dictionaries in the following form:
39
{"_name": "", "_password": "", "_databases": [{"_name": ""}, ...]}
43
"{guest_id}: Creating user {name} with password {password}."
45
guest_id=CONF.guest_id,
47
password=user['_password'],
51
_("{guest_id}: Creating user {name} with password {password}.")
53
guest_id=CONF.guest_id,
55
password="<SANITIZED>",
59
pgutil.UserQuery.create(
61
password=user['_password'],
69
[d['_name'] for d in user['_databases']],
79
"""List all users on the instance along with their access permissions.
81
Return value is a list of dictionaries in the following form:
83
[{"_name": "", "_password": None, "_host": None,
84
"_databases": [{"_name": ""}, ...]}, ...]
86
results = pgutil.query(
87
pgutil.UserQuery.list(ignore=IGNORE_USERS_LIST),
90
# Convert results into dictionaries.
93
'_name': r[0].strip(),
96
'_databases': self.list_access(context, r[0], None),
101
# Force __iter__ of generator until marker found.
102
if marker is not None:
104
item = results.next()
105
while item['_name'] != marker:
106
item = results.next()
107
except StopIteration:
111
if limit is not None:
113
results = itertools.islice(results, limit)
115
results = tuple(results)
118
if remainder is not None:
120
next_marker = remainder.next()
121
except StopIteration:
124
return results, next_marker
126
def delete_user(self, context, user):
127
"""Delete the specified user.
129
The user parameter is a dictionary in the following form:
134
_("{guest_id}: Dropping user {name}.").format(
135
guest_id=CONF.guest_id,
140
pgutil.UserQuery.drop(name=user['_name']),
144
def get_user(self, context, username, hostname):
145
"""Return a single user matching the criteria.
147
The username and hostname parameter are strings.
149
The return value is a dictionary in the following form:
151
{"_name": "", "_host": None, "_password": None,
152
"_databases": [{"_name": ""}, ...]}
154
Where "_databases" is a list of databases the user has access to.
156
results = pgutil.query(
157
pgutil.UserQuery.get(name=username),
160
results = tuple(results)
165
"_name": results[0][0],
168
"_databases": self.list_access(context, username, None),
171
def change_passwords(self, context, users):
172
"""Change the passwords of one or more existing users.
174
The users parameter is a list of dictionaries in the following form:
176
{"name": "", "password": ""}
180
"{guest_id}: Changing password for {user} to {password}."
182
guest_id=CONF.guest_id,
184
password=user['password'],
188
_("{guest_id}: Changing password for {user} to {password}.")
190
guest_id=CONF.guest_id,
192
password="<SANITIZED>",
196
pgutil.UserQuery.update_password(
198
password=user['password'],
203
def update_attributes(self, context, username, hostname, user_attrs):
204
"""Change the attributes of one existing user.
206
The username and hostname parameters are strings.
207
The user_attrs parameter is a dictionary in the following form:
209
{"password": "", "name": ""}
211
Each key/value pair in user_attrs is optional.
213
if user_attrs.get('password') is not None:
214
self.change_passwords(
219
"password": user_attrs['password'],
224
if user_attrs.get('name') is not None:
225
access = self.list_access(context, username, None)
227
_("{guest_id}: Changing username for {old} to {new}.").format(
228
guest_id=CONF.guest_id,
230
new=user_attrs['name'],
234
pgutil.psql.UserQuery.update_name(
236
new=user_attrs['name'],
240
# Regrant all previous access after the name change.
242
_("{guest_id}: Regranting permissions from {old} to {new}.")
244
guest_id=CONF.guest_id,
246
new=user_attrs['name'],
251
username=user_attrs['name'],
253
databases=(db['_name'] for db in access)