Merge "Add UID/GID configurations for each datastore"

This commit is contained in:
Zuul 2024-08-17 06:48:24 +00:00 committed by Gerrit Code Review
commit 7358330c14
10 changed files with 170 additions and 54 deletions

View File

@ -303,6 +303,25 @@ Some config options specifically for trove guest agent:
docker_image = your-registry/your-repo/mysql
backup_docker_image = your-registry/your-repo/db-backup-mysql
* Setting username, uid, gid for each datastore
Currently, when a database container is running, it is owned by user:
database (UID: 1001) and group: database (GID: 1001).
In some cases, you may need to set the owner of files,
directories or container to adapt to your own datastore image.
To achieve this, you can configure the option
database_service_uname, database_service_uid, database_service_gid
in trove-guestagent.conf with following:
.. code-block:: ini
[<datastore_manage>]
database_service_uid = 1001
database_service_gid = 0
database_service_uname = postgres
Make Trove work with multiple versions for each datastore
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When Trove do a backup/restore actions, The Trove guest agent pulls container

View File

@ -0,0 +1,7 @@
---
features:
- |
Add support of setting owner,uid,gid for each datastore instances
by configuring database_service_uname,
database_service_uid and database_service_gid
Story 2010827 <https://storyboard.openstack.org/#!/story/2010827>

View File

@ -83,8 +83,11 @@ def main():
# Create user and group for running docker container.
LOG.info('Creating user and group for database service')
uid = cfg.get_configuration_property('database_service_uid')
operating_system.create_user('database', uid)
uid = CONF.get(CONF.datastore_manager
).database_service_uid or CONF.database_service_uid
gid = CONF.get(CONF.datastore_manager).database_service_gid or uid
uname = CONF.get(CONF.datastore_manager).database_service_uname
operating_system.create_user(uname, user_id=uid, group_id=gid)
# Mount device if needed.
# When doing rebuild, the device should be already formatted but not
@ -97,9 +100,8 @@ def main():
device_path, mount_point)
device.format()
device.mount(mount_point)
operating_system.chown(mount_point, CONF.database_service_uid,
CONF.database_service_uid,
recursive=True, as_root=True)
operating_system.chown(
mount_point, uid, gid, recursive=True, as_root=True)
# rpc module must be loaded after decision about thread monkeypatching
# because if thread module is not monkeypatched we can't use eventlet

View File

@ -544,6 +544,12 @@ mysql_group = cfg.OptGroup(
'mysql', title='MySQL options',
help="Oslo option group designed for MySQL datastore")
mysql_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -621,6 +627,12 @@ percona_group = cfg.OptGroup(
'percona', title='Percona options',
help="Oslo option group designed for Percona datastore")
percona_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -690,6 +702,12 @@ pxc_group = cfg.OptGroup(
'pxc', title='Percona XtraDB Cluster options',
help="Oslo option group designed for Percona XtraDB Cluster datastore")
pxc_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -771,6 +789,12 @@ redis_group = cfg.OptGroup(
'redis', title='Redis options',
help="Oslo option group designed for Redis datastore")
redis_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -830,6 +854,12 @@ cassandra_group = cfg.OptGroup(
'cassandra', title='Cassandra options',
help="Oslo option group designed for Cassandra datastore")
cassandra_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -914,6 +944,12 @@ couchbase_group = cfg.OptGroup(
'couchbase', title='Couchbase options',
help="Oslo option group designed for Couchbase datastore")
couchbase_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -959,6 +995,12 @@ mongodb_group = cfg.OptGroup(
'mongodb', title='MongoDB options',
help="Oslo option group designed for MongoDB datastore")
mongodb_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -1038,6 +1080,12 @@ postgresql_group = cfg.OptGroup(
'postgresql', title='PostgreSQL options',
help="Oslo option group for the PostgreSQL datastore.")
postgresql_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt(
'enable_clean_wal_archives',
default=True,
@ -1123,6 +1171,12 @@ couchdb_group = cfg.OptGroup(
'couchdb', title='CouchDB options',
help="Oslo option group designed for CouchDB datastore")
couchdb_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -1174,6 +1228,12 @@ vertica_group = cfg.OptGroup(
'vertica', title='Vertica options',
help="Oslo option group designed for Vertica datastore")
vertica_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -1241,6 +1301,12 @@ db2_group = cfg.OptGroup(
'db2', title='DB2 options',
help="Oslo option group designed for DB2 datastore")
db2_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),
@ -1284,6 +1350,12 @@ mariadb_group = cfg.OptGroup(
'mariadb', title='MariaDB options',
help="Oslo option group designed for MariaDB datastore")
mariadb_opts = [
cfg.StrOpt('database_service_uname', default='database',
help='The name of database service user.'),
cfg.StrOpt('database_service_uid',
help='The UID of database service user.'),
cfg.StrOpt('database_service_gid',
help='The GID of database service user.'),
cfg.BoolOpt('icmp', default=False,
help='Whether to permit ICMP.',
deprecated_for_removal=True),

View File

@ -71,10 +71,11 @@ class MySqlManager(manager.Manager):
"""This is called from prepare in the base class."""
data_dir = mount_point + '/data'
self.app.stop_db()
operating_system.ensure_directory(data_dir,
user=CONF.database_service_uid,
group=CONF.database_service_uid,
as_root=True)
operating_system.ensure_directory(
data_dir,
user=self.app.database_service_uid,
group=self.app.database_service_gid,
as_root=True)
# This makes sure the include dir is created.
self.app.set_data_dir(data_dir)
@ -223,9 +224,11 @@ class MySqlManager(manager.Manager):
# Allow database service user to access the temporary files.
try:
for file in [init_file.name, err_file.name]:
operating_system.chown(file, CONF.database_service_uid,
CONF.database_service_uid, force=True,
as_root=True)
operating_system.chown(
file,
self.app.database_service_uid,
self.app.database_service_gid,
force=True, as_root=True)
except Exception as err:
LOG.error('Failed to change file owner, error: %s', str(err))
for file in [init_file.name, err_file.name]:
@ -338,8 +341,8 @@ class MySqlManager(manager.Manager):
mount_point = CONF.get(CONF.datastore_manager).mount_point
data_dir = mount_point + '/data'
operating_system.ensure_directory(data_dir,
user=CONF.database_service_uid,
group=CONF.database_service_uid,
user=self.app.database_service_uid,
group=self.app.database_service_gid,
as_root=True)
# This makes sure the include dir is created.
self.app.set_data_dir(data_dir)

View File

@ -445,7 +445,7 @@ class BaseMySqlApp(service.BaseDbApp):
return self._configuration_manager
self._configuration_manager = ConfigurationManager(
MYSQL_CONFIG, CONF.database_service_uid, CONF.database_service_uid,
MYSQL_CONFIG, self.database_service_uid, self.database_service_gid,
service.BaseDbApp.CFG_CODEC, requires_root=True,
override_strategy=ImportOverrideStrategy(CNF_INCLUDE_DIR, CNF_EXT)
)
@ -591,14 +591,14 @@ class BaseMySqlApp(service.BaseDbApp):
root_pass = utils.generate_random_password()
# Get uid and gid
user = "%s:%s" % (CONF.database_service_uid, CONF.database_service_uid)
user = "%s:%s" % (self.database_service_uid, self.database_service_gid)
# Create folders for mysql on localhost
for folder in ['/etc/mysql', constants.MYSQL_HOST_SOCKET_PATH,
'/etc/mysql/mysql.conf.d']:
operating_system.ensure_directory(
folder, user=CONF.database_service_uid,
group=CONF.database_service_uid, force=True,
folder, user=self.database_service_uid,
group=self.database_service_gid, force=True,
as_root=True)
volumes = {
@ -678,8 +678,8 @@ class BaseMySqlApp(service.BaseDbApp):
for folder in ['/etc/mysql', constants.MYSQL_HOST_SOCKET_PATH,
'/etc/mysql/mysql.conf.d']:
operating_system.ensure_directory(
folder, user=CONF.database_service_uid,
group=CONF.database_service_uid, force=True,
folder, user=self.database_service_uid,
group=self.database_service_gid, force=True,
as_root=True)
try:
@ -742,8 +742,8 @@ class BaseMySqlApp(service.BaseDbApp):
LOG.debug('Deleting ib_logfile files after restore from backup %s',
backup_id)
operating_system.chown(restore_location, CONF.database_service_uid,
CONF.database_service_uid, force=True,
operating_system.chown(restore_location, self.database_service_uid,
self.database_service_gid, force=True,
as_root=True)
self.wipe_ib_logfiles()

View File

@ -123,14 +123,12 @@ class PostgresManager(manager.Manager):
device_path, mount_point, backup_info,
config_contents, root_password, overrides,
cluster_config, snapshot, ds_version=None):
operating_system.ensure_directory(self.app.datadir,
user=CONF.database_service_uid,
group=CONF.database_service_uid,
as_root=True)
operating_system.ensure_directory(service.WAL_ARCHIVE_DIR,
user=CONF.database_service_uid,
group=CONF.database_service_uid,
as_root=True)
for datadir in [self.app.datadir, service.WAL_ARCHIVE_DIR]:
operating_system.ensure_directory(
datadir,
user=self.app.database_service_uid,
group=self.app.database_service_gid,
as_root=True)
LOG.info('Preparing database config files')
self.app.configuration_manager.reset_configuration(config_contents)
@ -149,9 +147,11 @@ class PostgresManager(manager.Manager):
signal_file = f"{self.app.datadir}/recovery.signal"
operating_system.execute_shell_cmd(
f"touch {signal_file}", [], shell=True, as_root=True)
operating_system.chown(signal_file, CONF.database_service_uid,
CONF.database_service_uid, force=True,
as_root=True)
operating_system.chown(
signal_file,
user=self.app.database_service_uid,
group=self.app.database_service_gid,
force=True, as_root=True)
if snapshot:
# This instance is a replica
@ -198,7 +198,8 @@ class PostgresManager(manager.Manager):
}
def is_log_enabled(self, logname):
return self.configuration_manager.get_value('logging_collector', False)
return self.configuration_manager.get_value(
'logging_collector', default=False)
def create_backup(self, context, backup_info):
"""Create backup for the database.

View File

@ -85,8 +85,8 @@ class PgSqlApp(service.BaseDbApp):
self._configuration_manager = configuration.ConfigurationManager(
CONFIG_FILE,
CONF.database_service_uid,
CONF.database_service_uid,
self.database_service_uid,
self.database_service_gid,
stream_codecs.KeyValueCodec(
value_quoting=True,
bool_case=stream_codecs.KeyValueCodec.BOOL_LOWER,
@ -143,8 +143,8 @@ class PgSqlApp(service.BaseDbApp):
stream_codecs.PropertiesCodec(string_mappings={'\t': None}),
as_root=True)
operating_system.chown(HBA_CONFIG_FILE,
CONF.database_service_uid,
CONF.database_service_uid,
self.database_service_uid,
self.database_service_gid,
as_root=True)
operating_system.chmod(HBA_CONFIG_FILE,
operating_system.FileMode.SET_USR_RO,
@ -174,14 +174,14 @@ class PgSqlApp(service.BaseDbApp):
postgres_pass = utils.generate_random_password()
# Get uid and gid
user = "%s:%s" % (CONF.database_service_uid, CONF.database_service_uid)
user = "%s:%s" % (self.database_service_uid, self.database_service_gid)
# Create folders for postgres on localhost
for folder in ['/etc/postgresql',
constants.POSTGRESQL_HOST_SOCKET_PATH]:
operating_system.ensure_directory(
folder, user=CONF.database_service_uid,
group=CONF.database_service_uid, force=True,
folder, user=self.database_service_uid,
group=self.database_service_gid, force=True,
as_root=True)
volumes = {
@ -244,8 +244,8 @@ class PgSqlApp(service.BaseDbApp):
for folder in ['/etc/postgresql',
constants.POSTGRESQL_HOST_SOCKET_PATH]:
operating_system.ensure_directory(
folder, user=CONF.database_service_uid,
group=CONF.database_service_uid, force=True,
folder, user=self.database_service_uid,
group=self.database_service_gid, force=True,
as_root=True)
try:
@ -311,8 +311,8 @@ class PgSqlApp(service.BaseDbApp):
raise Exception(msg)
for dir in [WAL_ARCHIVE_DIR, self.datadir]:
operating_system.chown(dir, CONF.database_service_uid,
CONF.database_service_uid, force=True,
operating_system.chown(dir, self.database_service_uid,
self.database_service_gid, force=True,
as_root=True)
def is_replica(self):
@ -341,7 +341,7 @@ class PgSqlApp(service.BaseDbApp):
def pg_rewind(self, conn_info):
docker_image = CONF.get(CONF.datastore_manager).docker_image
image = f'{docker_image}:{CONF.datastore_version}'
user = "%s:%s" % (CONF.database_service_uid, CONF.database_service_uid)
user = "%s:%s" % (self.database_service_uid, self.database_service_gid)
volumes = {
constants.POSTGRESQL_HOST_SOCKET_PATH:
{"bind": "/var/run/postgresql", "mode": "rw"},

View File

@ -562,3 +562,13 @@ class BaseDbApp(object):
sent=timeutils.utcnow_ts(microsecond=True),
**backup_state)
LOG.debug("Updated state for %s to %s.", backup_id, backup_state)
@property
def database_service_uid(self):
return cfg.get_configuration_property(
'database_service_uid') or CONF.database_service_uid
@property
def database_service_gid(self):
return cfg.get_configuration_property(
'database_service_gid') or self.database_service_uid

View File

@ -41,8 +41,9 @@ class PostgresqlReplicationStreaming(base.Replication):
"""
pw = utils.generate_random_password()
operating_system.write_file(pwfile, pw, as_root=True)
operating_system.chown(pwfile, user=CONF.database_service_uid,
group=CONF.database_service_uid, as_root=True)
operating_system.chown(pwfile, user=service.database_service_uid,
group=service.database_service_gid,
as_root=True)
operating_system.chmod(pwfile, FileMode.SET_USR_RWX(),
as_root=True)
LOG.debug(f"File {pwfile} created")
@ -108,8 +109,9 @@ class PostgresqlReplicationStreaming(base.Replication):
operating_system.copy(tmp_hba, pg_service.HBA_CONFIG_FILE,
force=True, as_root=True)
operating_system.chown(pg_service.HBA_CONFIG_FILE,
user=CONF.database_service_uid,
group=CONF.database_service_uid, as_root=True)
user=service.database_service_uid,
group=service.database_service_gid,
as_root=True)
operating_system.chmod(pg_service.HBA_CONFIG_FILE,
FileMode.SET_USR_RWX(),
as_root=True)
@ -166,8 +168,8 @@ class PostgresqlReplicationStreaming(base.Replication):
signal_file = f"{service.datadir}/standby.signal"
operating_system.execute_shell_cmd(
f"touch {signal_file}", [], shell=True, as_root=True)
operating_system.chown(signal_file, CONF.database_service_uid,
CONF.database_service_uid, force=True,
operating_system.chown(signal_file, service.database_service_uid,
service.database_service_gid, force=True,
as_root=True)
LOG.debug("Standby signal file created")
@ -217,8 +219,8 @@ class PostgresqlReplicationStreaming(base.Replication):
signal_file = f"{service.datadir}/standby.signal"
operating_system.execute_shell_cmd(
f"touch {signal_file}", [], shell=True, as_root=True)
operating_system.chown(signal_file, CONF.database_service_uid,
CONF.database_service_uid, force=True,
operating_system.chown(signal_file, service.database_service_uid,
service.database_service_gid, force=True,
as_root=True)
LOG.debug("Standby signal file created")