Пример #1
0
    def build_log_file_name(self, log_name, owner, datastore_dir=None):
        """Build a log file name based on the log_name and make sure the
        directories exist and are accessible by owner.
        """
        if datastore_dir is None:
            base_dir = self.GUEST_LOG_BASE_DIR
            if not operating_system.exists(base_dir, is_directory=True):
                operating_system.ensure_directory(base_dir,
                                                  user=owner,
                                                  group=owner,
                                                  force=True,
                                                  as_root=True)
            datastore_dir = guestagent_utils.build_file_path(
                base_dir, self.GUEST_LOG_DATASTORE_DIRNAME)

        if not operating_system.exists(datastore_dir, is_directory=True):
            operating_system.ensure_directory(datastore_dir,
                                              user=owner,
                                              group=owner,
                                              force=True,
                                              as_root=True)
        log_file_name = guestagent_utils.build_file_path(
            datastore_dir, '%s-%s.log' % (self.manager, log_name))

        return self.validate_log_file(log_file_name, owner)
Пример #2
0
    def rebuild(self,
                context,
                ds_version,
                config_contents=None,
                config_overrides=None):
        """Restore datastore service after instance rebuild."""
        LOG.info("Starting to restore database service")
        self.status.begin_install()

        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,
                                          as_root=True)
        # This makes sure the include dir is created.
        self.app.set_data_dir(data_dir)

        try:
            # Prepare mysql configuration
            LOG.debug('Preparing database configuration')
            self.app.configuration_manager.reset_configuration(config_contents)
            self.app.update_overrides(config_overrides)

            # Start database service.
            command = self.get_start_db_params(data_dir)
            self.app.start_db(ds_version=ds_version, command=command)
        except Exception as e:
            LOG.error(f"Failed to restore database service after rebuild, "
                      f"error: {str(e)}")
            self.prepare_error = True
            raise
        finally:
            self.status.end_install(error_occurred=self.prepare_error)
Пример #3
0
 def build_module_dir(cls, module_type, module_id):
     sub_dir = os.path.join(module_type, module_id)
     module_dir = guestagent_utils.build_file_path(cls.MODULE_BASE_DIR,
                                                   sub_dir)
     if not operating_system.exists(module_dir, is_directory=True):
         operating_system.ensure_directory(module_dir, force=True)
     return module_dir
Пример #4
0
 def _initialize_import_directory(self):
     """Lazy-initialize the directory for imported revision files.
     """
     if not os.path.exists(self._revision_dir):
         operating_system.ensure_directory(
             self._revision_dir, user=self._owner, group=self._group,
             force=True, as_root=self._requires_root)
Пример #5
0
    def start_db(self, update_db=False, ds_version=None, command=None,
                 extra_volumes=None):
        """Start and wait for database service."""
        docker_image = CONF.get(CONF.datastore_manager).docker_image
        image = (f'{docker_image}:latest' if not ds_version else
                 f'{docker_image}:{ds_version}')
        command = command if command else ''

        try:
            root_pass = self.get_auth_password(file="root.cnf")
        except exception.UnprocessableEntity:
            root_pass = utils.generate_random_password()

        # Get uid and gid
        user = "******" % (CONF.database_service_uid, CONF.database_service_uid)

        # Create folders for mysql on localhost
        for folder in ['/etc/mysql', '/var/run/mysqld']:
            operating_system.ensure_directory(
                folder, user=CONF.database_service_uid,
                group=CONF.database_service_uid, force=True,
                as_root=True)

        volumes = {
            "/etc/mysql": {"bind": "/etc/mysql", "mode": "rw"},
            "/var/run/mysqld": {"bind": "/var/run/mysqld",
                                "mode": "rw"},
            "/var/lib/mysql": {"bind": "/var/lib/mysql", "mode": "rw"},
        }
        if extra_volumes:
            volumes.update(extra_volumes)

        try:
            LOG.info("Starting docker container, image: %s", image)
            docker_util.start_container(
                self.docker_client,
                image,
                volumes=volumes,
                network_mode="host",
                user=user,
                environment={
                    "MYSQL_ROOT_PASSWORD": root_pass,
                    "MYSQL_INITDB_SKIP_TZINFO": 1,
                },
                command=command
            )

            # Save root password
            LOG.debug("Saving root credentials to local host.")
            self.save_password('root', root_pass)
        except Exception:
            LOG.exception("Failed to start mysql")
            raise exception.TroveError(_("Failed to start mysql"))

        if not self.status.wait_for_status(
            service_status.ServiceStatuses.HEALTHY,
            CONF.state_change_wait_time, update_db
        ):
            raise exception.TroveError(_("Failed to start mysql"))
Пример #6
0
    def __init__(self, base_config_path, owner, group, codec,
                 requires_root=False, override_strategy=None):
        """
        :param base_config_path     Path to the configuration file.
        :type base_config_path      string

        :param owner                Owner of the configuration files.
        :type owner                 string

        :param group                Group of the configuration files.
        :type group                 string

        :param codec                Codec for reading/writing of the particular
                                    configuration format.
        :type codec                 StreamCodec

        :param requires_root        Whether the manager requires superuser
                                    privileges.
        :type requires_root         boolean

        :param override_strategy    Strategy used to manage configuration
                                    overrides (e.g. ImportOverrideStrategy).
                                    Defaults to OneFileOverrideStrategy
                                    if None. This strategy should be
                                    compatible with very much any datastore.
                                    It is recommended each datastore defines
                                    its strategy explicitly to avoid upgrade
                                    compatibility issues in case the default
                                    implementation changes in the future.
        :type override_strategy     ConfigurationOverrideStrategy
        """
        base_config_dir = os.path.dirname(base_config_path)
        operating_system.ensure_directory(
            base_config_dir, user=owner, group=group, force=True, as_root=True
        )

        self._base_config_path = base_config_path
        self._owner = owner
        self._group = group
        self._codec = codec
        self._requires_root = requires_root
        self._value_cache = None

        if not override_strategy:
            # Use OneFile strategy by default. Store the revisions in a
            # sub-directory at the location of the configuration file.
            revision_dir = guestagent_utils.build_file_path(
                os.path.dirname(base_config_path),
                self.DEFAULT_STRATEGY_OVERRIDES_SUB_DIR)
            self._override_strategy = OneFileOverrideStrategy(revision_dir)
        else:
            self._override_strategy = override_strategy

        self._override_strategy.configure(
            base_config_path, owner, group, codec, requires_root)
Пример #7
0
def get_conf_dir():
    """Get the config directory for the database related settings.

    For now, the files inside the config dir are mainly for instance rebuild.
    """
    mount_point = CONF.get(CONF.datastore_manager).mount_point
    conf_dir = os.path.join(mount_point, 'conf.d')
    if not operating_system.exists(conf_dir, is_directory=True, as_root=True):
        operating_system.ensure_directory(conf_dir, as_root=True)

    return conf_dir
Пример #8
0
    def do_prepare(self,
                   context,
                   packages,
                   databases,
                   memory_mb,
                   users,
                   device_path,
                   mount_point,
                   backup_info,
                   config_contents,
                   root_password,
                   overrides,
                   cluster_config,
                   snapshot,
                   ds_version=None):
        """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)
        # This makes sure the include dir is created.
        self.app.set_data_dir(data_dir)

        # Prepare mysql configuration
        LOG.info('Preparing database configuration')
        self.app.configuration_manager.reset_configuration(config_contents)
        self.app.update_overrides(overrides)

        # Restore data from backup and reset root password
        if backup_info:
            self.perform_restore(context, data_dir, backup_info)
            self.reset_password_for_restore(ds_version=ds_version,
                                            data_dir=data_dir)

        # Start database service.
        command = self.get_start_db_params(data_dir)
        self.app.start_db(ds_version=ds_version, command=command)

        self.app.secure()
        enable_remote_root = (backup_info and self.adm.is_root_enabled())
        if enable_remote_root:
            self.status.report_root(context)
        else:
            self.app.secure_root()

        if snapshot:
            # This instance is a replication slave
            self.attach_replica(context, snapshot, snapshot['config'])
Пример #9
0
    def do_prepare(self, context, packages, databases, memory_mb, users,
                   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)

        LOG.info('Preparing database config files')
        self.app.configuration_manager.save_configuration(config_contents)
        self.app.set_data_dir(self.app.datadir)
        self.app.update_overrides(overrides)

        # Prepare pg_hba.conf
        self.app.apply_access_rules()
        self.configuration_manager.apply_system_override(
            {'hba_file': service.HBA_CONFIG_FILE})

        # Restore data from backup and reset root password
        if backup_info:
            self.perform_restore(context, self.app.datadir, backup_info)
            if not snapshot:
                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)

        if snapshot:
            # This instance is a replica
            self.attach_replica(context, snapshot, snapshot['config'])

        # config_file can only be set on the postgres command line
        command = f"postgres -c config_file={service.CONFIG_FILE}"
        self.app.start_db(ds_version=ds_version, command=command)
Пример #10
0
 def mount(self):
     if not operating_system.exists(
             self.mount_point, is_directory=True, as_root=True):
         operating_system.ensure_directory(self.mount_point, as_root=True)
     LOG.debug("Mounting volume. Device path:{0}, mount_point:{1}, "
               "volume_type:{2}, mount options:{3}".format(
                   self.device_path, self.mount_point, self.volume_fstype,
                   self.mount_options))
     try:
         utils.execute("mount",
                       "-t",
                       self.volume_fstype,
                       "-o",
                       self.mount_options,
                       self.device_path,
                       self.mount_point,
                       run_as_root=True,
                       root_helper="sudo")
     except exception.ProcessExecutionError:
         log_fmt = "Could not mount '%s'."
         exc_fmt = _("Could not mount '%s'.")
         log_and_raise(log_fmt, exc_fmt, self.mount_point)
Пример #11
0
    def restart(self):
        LOG.info("Restarting mysql")

        # Ensure folders permission for database.
        for folder in ['/etc/mysql', '/var/run/mysqld']:
            operating_system.ensure_directory(
                folder, user=CONF.database_service_uid,
                group=CONF.database_service_uid, force=True,
                as_root=True)

        try:
            docker_util.restart_container(self.docker_client)
        except Exception:
            LOG.exception("Failed to restart mysql")
            raise exception.TroveError("Failed to restart mysql")

        if not self.status.wait_for_status(
            service_status.ServiceStatuses.HEALTHY,
            CONF.state_change_wait_time, update_db=True
        ):
            raise exception.TroveError("Failed to start mysql")

        LOG.info("Finished restarting mysql")
Пример #12
0
    def start_db(self,
                 update_db=False,
                 ds_version=None,
                 command=None,
                 extra_volumes=None):
        """Start and wait for database service."""
        docker_image = CONF.get(CONF.datastore_manager).docker_image
        image = (f'{docker_image}:latest'
                 if not ds_version else f'{docker_image}:{ds_version}')
        command = command if command else ''

        try:
            postgres_pass = self.get_auth_password(file="postgres.cnf")
        except exception.UnprocessableEntity:
            postgres_pass = utils.generate_random_password()

        # Get uid and gid
        user = "******" % (CONF.database_service_uid, CONF.database_service_uid)

        # Create folders for postgres on localhost
        for folder in ['/etc/postgresql', '/var/run/postgresql']:
            operating_system.ensure_directory(folder,
                                              user=CONF.database_service_uid,
                                              group=CONF.database_service_uid,
                                              force=True,
                                              as_root=True)

        volumes = {
            "/etc/postgresql": {
                "bind": "/etc/postgresql",
                "mode": "rw"
            },
            "/var/run/postgresql": {
                "bind": "/var/run/postgresql",
                "mode": "rw"
            },
            "/var/lib/postgresql": {
                "bind": "/var/lib/postgresql",
                "mode": "rw"
            },
            "/var/lib/postgresql/data": {
                "bind": "/var/lib/postgresql/data",
                "mode": "rw"
            },
        }
        if extra_volumes:
            volumes.update(extra_volumes)

        # Expose ports
        ports = {}
        tcp_ports = cfg.get_configuration_property('tcp_ports')
        for port_range in tcp_ports:
            for port in port_range:
                ports[f'{port}/tcp'] = port

        try:
            docker_util.start_container(self.docker_client,
                                        image,
                                        volumes=volumes,
                                        network_mode="bridge",
                                        ports=ports,
                                        user=user,
                                        environment={
                                            "POSTGRES_PASSWORD": postgres_pass,
                                            "PGDATA": self.datadir,
                                        },
                                        command=command)

            # Save root password
            LOG.debug("Saving root credentials to local host.")
            self.save_password('postgres', postgres_pass)
        except Exception:
            LOG.exception("Failed to start database service")
            raise exception.TroveError("Failed to start database service")

        if not self.status.wait_for_status(
                service_status.ServiceStatuses.HEALTHY,
                CONF.state_change_wait_time, update_db):
            raise exception.TroveError("Failed to start database service")