Пример #1
0
    def start(self):
        """ starts rolekit """
        log.debug1("start()")

        try:
            os.makedirs(ETC_ROLEKIT_ROLES)
        except OSError as e:
            if e.errno == errno.EEXIST:
                if not os.path.isdir(ETC_ROLEKIT_ROLES):
                    log.fatal("'%s' is not a directory.", e.strerror)
            else:
                log.fatal("Failed to create '%s': %s", e.strerror)
                raise
        else:
            log.info1("Created missing '%s'.", ETC_ROLEKIT_ROLES)

        path = ROLEKIT_ROLES

        if not os.path.exists(path) or not os.path.isdir(path):
            log.error("Role directory '%s' does not exist.", path)
            return

        for name in sorted(os.listdir(path)):
            directory = "%s/%s" % (path, name)
            if not os.path.isdir(directory):
                continue

            if not os.path.exists(os.path.join(directory, "role.py")):
                continue

            log.debug1("Loading role '%s'", name)
            escaped_name = dbus_label_escape(name)

            try:
                if os.path.exists(os.path.join(directory, "role.py")):
                    mod = imp.load_source(name, "%s/role.py" % directory)

                # get Role from module
                role = getattr(mod, "Role")

                # create role object that contains the role instance class
                obj = DBusRole(role,
                               name,
                               directory,
                               self._path,
                               "%s/%s" % (DBUS_PATH_ROLES, escaped_name),
                               persistent=self.persistent)

                if obj in self._roles:
                    log.error("Duplicate role '%s'", obj.name)
                else:
                    self._roles.append(obj)
            except RolekitError as msg:
                log.error("Failed to load role '%s': %s", name, msg)
                continue
            except Exception as msg:
                log.error("Failed to load role '%s':", name)
                log.exception()
                continue
Пример #2
0
    def start(self):
        """ starts rolekit """
        log.debug1("start()")

        try:
            os.makedirs(ETC_ROLEKIT_ROLES)
        except OSError as e:
            if e.errno == errno.EEXIST:
                if not os.path.isdir(ETC_ROLEKIT_ROLES):
                    log.fatal("'%s' is not a directory.", e.strerror)
            else:
                log.fatal("Failed to create '%s': %s", e.strerror)
                raise
        else:
            log.info1("Created missing '%s'.", ETC_ROLEKIT_ROLES)

        path = ROLEKIT_ROLES

        if not os.path.exists(path) or not os.path.isdir(path):
            log.error("Role directory '%s' does not exist.", path)
            return

        for name in sorted(os.listdir(path)):
            directory = "%s/%s" % (path, name)
            if not os.path.isdir(directory):
                continue

            if not os.path.exists(os.path.join(directory, "role.py")):
                continue

            log.debug1("Loading role '%s'", name)
            escaped_name = dbus_label_escape(name)

            try:
                if os.path.exists(os.path.join(directory, "role.py")):
                    mod = imp.load_source(name, "%s/role.py" % directory)

                    # get Role from module
                    role = getattr(mod, "Role")

                    # create role object that contains the role instance class
                    obj = DBusRole(role, name, directory, self.busname,
                                    "%s/%s" % (DBUS_PATH_ROLES, escaped_name),
                                   persistent=self.persistent)

                    if obj in self._roles:
                        log.error("Duplicate role '%s'", obj.get_name())
                    else:
                        self._roles.append(obj)
            except RolekitError as msg:
                log.error("Failed to load role '%s': %s", name, msg)
                continue
            except Exception as msg:
                log.error("Failed to load role '%s':", name)
                log.exception()
                continue
Пример #3
0
    def __init__(self, type_name, name, deferred=False, *args, **kwargs):
        super(RoleSettings, self).__init__(*args, **kwargs)

        # If name is given check it
        if name:
            validate_name(name)
        # Check type name
        validate_name(type_name)

        self._name = name
        self._type = type_name

        if deferred:
            self.path = "%s/%s" % (ETC_ROLEKIT_DEFERREDROLES, self.get_type())
        else:
            self.path = "%s/%s" % (ETC_ROLEKIT_ROLES, self.get_type())

        # Ensure that this directory exists
        try:
            os.makedirs(self.path)
        except OSError as e:
            if e.errno == errno.EEXIST:
                if not os.path.isdir(self.path):
                    log.fatal("'%s' is not a directory.", e.strerror)
            else:
                log.fatal("Failed to create '%s': %s", e.strerror)
                raise
        else:
            log.debug1("Created missing '%s'.", self.path)

        # If we need to autogenerate a name, do it here
        if not name:
            # Check both the existing and deferred role directories
            self._name = self.get_unique_instance(self.get_type())

        self.filepath = "%s/%s.json" % (self.path, self.get_name())
        self._callbacks = {"changed": None}
Пример #4
0
    def __init__(self, type_name, name, deferred=False, *args, **kwargs):
        super(RoleSettings, self).__init__(*args, **kwargs)

        # If name is given check it
        if name:
            validate_name(name)
        # Check type name
        validate_name(type_name)

        self._name = name
        self._type = type_name

        if deferred:
            self.path = "%s/%s" % (ETC_ROLEKIT_DEFERREDROLES, self.get_type())
        else:
            self.path = "%s/%s" % (ETC_ROLEKIT_ROLES, self.get_type())

        # Ensure that this directory exists
        try:
            os.makedirs(self.path)
        except OSError as e:
            if e.errno == errno.EEXIST:
                if not os.path.isdir(self.path):
                    log.fatal("'%s' is not a directory.", e.strerror)
            else:
                log.fatal("Failed to create '%s': %s", e.strerror)
                raise
        else:
            log.debug1("Created missing '%s'.", self.path)

        # If we need to autogenerate a name, do it here
        if not name:
            # Check both the existing and deferred role directories
            self._name = self.get_unique_instance(self.get_type())

        self.filepath = "%s/%s.json" % (self.path, self.get_name())
        self._callbacks = { "changed": None }
Пример #5
0
    def do_deploy_async(self, values, sender=None):
        log.debug9("TRACE do_deploy_async(databaseserver)")
        # Do the magic
        #
        # In case of error raise an exception

        first_instance = True

        # Check whether this is the first instance of the database
        for value in self._parent.get_instances().values():
            if ('databaseserver' == value.get_type()
                    and self.get_name() != value.get_name()
                    and self.get_state() in deployed_states):
                first_instance = False
                break

        # If the database name wasn't specified
        if 'database' not in values:
            # Use the instance name if it was manually specified
            if self.get_name()[0].isalpha():
                values['database'] = self.get_name()
            else:
                # Either it was autogenerated or begins with a
                # non-alphabetic character; prefix it with db_
                values['database'] = "db_%s" % self.get_name()

        if 'owner' not in values:
            # We'll default to db_owner
            values['owner'] = "db_owner"

        # We will assume the owner is new until adding them fails
        new_owner = True

        # Determine if a password was passed in, so we know whether to
        # suppress it from the settings list later.
        if 'password' in values:
            password_provided = True
        else:
            password_provided = False

        if 'postgresql_conf' not in values:
            values['postgresql_conf'] = self._settings['postgresql_conf']

        if 'pg_hba_conf' not in values:
            values['pg_hba_conf'] = self._settings['pg_hba_conf']

        # Get the UID and GID of the 'postgres' user
        try:
            self.pg_uid = pwd.getpwnam('postgres').pw_uid
        except KeyError:
            raise RolekitError(MISSING_ID,
                               "Could not retrieve UID for postgres user")

        try:
            self.pg_gid = grp.getgrnam('postgres').gr_gid
        except KeyError:
            raise RolekitError(MISSING_ID,
                               "Could not retrieve GID for postgres group")

        if first_instance:
            # Initialize the database on the filesystem
            initdb_args = ["/usr/bin/postgresql-setup", "--initdb"]

            log.debug2("TRACE: Initializing database")
            result = yield async .subprocess_future(initdb_args)
            if result.status:
                # If this fails, it may be just that the filesystem
                # has already been initialized. We'll log the message
                # and continue.
                log.debug1("INITDB: %s" % result.stdout)

        # Now we have to start the service to set everything else up
        # It's safe to start an already-running service, so we'll
        # just always make this call, particularly in case other instances
        # exist but aren't running.
        log.debug2("TRACE: Starting postgresql.service unit")
        try:
            with SystemdJobHandler() as job_handler:
                job_path = job_handler.manager.StartUnit(
                    "postgresql.service", "replace")
                job_handler.register_job(job_path)
                log.debug2("TRACE: unit start job registered")

                job_results = yield job_handler.all_jobs_done_future()

                log.debug2("TRACE: unit start job concluded")

                if any([
                        x for x in job_results.values()
                        if x not in ("skipped", "done")
                ]):
                    details = ", ".join(
                        ["%s: %s" % item for item in job_results.items()])
                    log.error("Starting services failed: {}".format(details))
                    raise RolekitError(
                        COMMAND_FAILED,
                        "Starting services failed: %s" % details)
        except Exception as e:
            log.error("Error received starting unit: {}".format(e))
            raise

        # Next we create the owner
        log.debug2("TRACE: Creating owner of new database")
        createuser_args = ["/usr/bin/createuser", values['owner']]
        result = yield async .subprocess_future(createuser_args,
                                                uid=self.pg_uid,
                                                gid=self.pg_gid)

        if result.status:
            # If the subprocess returned non-zero, the user probably already exists
            # (such as when we're using db_owner). If the caller was trying to set
            # a password, they probably didn't realize this, so we need to throw
            # an exception.
            log.info1("User {} already exists in the database".format(
                values['owner']))

            if password_provided:
                raise RolekitError(INVALID_SETTING,
                                   "Cannot set password on pre-existing user")

            # If no password was specified, we'll continue
            new_owner = False

        # If no password was requested, generate a random one here
        if not password_provided:
            values['password'] = generate_password()

        log.debug2("TRACE: Creating new database")
        createdb_args = [
            "/usr/bin/createdb", values['database'], "-O", values['owner']
        ]
        result = yield async .subprocess_future(createdb_args,
                                                uid=self.pg_uid,
                                                gid=self.pg_gid)
        if result.status:
            # If the subprocess returned non-zero, raise an exception
            raise RolekitError(COMMAND_FAILED,
                               "Creating database failed: %d" % result.status)

        # Next, set the password on the owner
        # We'll skip this phase if the the user already existed
        if new_owner:
            log.debug2("TRACE: Setting password for database owner")
            pwd_args = [
                ROLEKIT_ROLES + "/databaseserver/tools/rk_db_setpwd.py",
                "--database", values['database'], "--user", values['owner']
            ]
            result = yield async .subprocess_future(pwd_args,
                                                    stdin=values['password'],
                                                    uid=self.pg_uid,
                                                    gid=self.pg_gid)

            if result.status:
                # If the subprocess returned non-zero, raise an exception
                log.error("Setting owner password failed: {}".format(
                    result.status))
                raise RolekitError(
                    COMMAND_FAILED,
                    "Setting owner password failed: %d" % result.status)

            # If this password was provided by the user, don't save it to
            # the settings for later retrieval. That could be a security
            # issue
            if password_provided:
                values.pop("password", None)
        else:  # Not a new owner
            # Never save the password to settings for an existing owner
            log.debug2("TRACE: Owner already exists, not setting password")
            values.pop("password", None)

        if first_instance:
            # Then update the server configuration to accept network
            # connections.
            log.debug2("TRACE: Opening access to external addresses")

            # edit postgresql.conf to add listen_addresses = '*'
            conffile = values['postgresql_conf']
            bakfile = conffile + ".rksave"

            try:
                linkfile(conffile, bakfile)

                with open(conffile) as f:
                    conflines = f.readlines()

                tweaking_rules = [{
                    'regex': r"^\s*#?\s*listen_addresses\s*=.*",
                    'replace': r"listen_addresses = '*'",
                    'append_if_missing': True
                }]

                overwrite_safely(
                    conffile, "".join(_tweak_lines(conflines, tweaking_rules)))
            except Exception as e:
                log.fatal("Couldn't write {!r}: {}".format(conffile, e))
                # At this point, conffile is unmodified, otherwise
                # overwrite_safely() would have succeeded
                try:
                    os.unlink(bakfile)
                except Exception as x:
                    if not (isinstance(x, OSError)
                            and x.errno == errno.ENOENT):
                        log.error("Couldn't remove {!r}: {}".format(
                            bakfile, x))

                raise RolekitError(
                    COMMAND_FAILED,
                    "Opening access to external addresses in '{}'"
                    "failed: {}".format(conffile, e))

            # Edit pg_hba.conf to allow 'md5' auth on IPv4 and
            # IPv6 interfaces.
            conffile = values['pg_hba_conf']
            bakfile = conffile + ".rksave"

            try:
                linkfile(conffile, bakfile)

                with open(conffile) as f:
                    conflines = f.readlines()

                tweaking_rules = [{
                    'regex': r"^\s*host((?:\s.*)$)",
                    'replace': r"#host\1"
                }, {
                    'regex':
                    r"^\s*local(?:\s.*|)$",
                    'append':
                    "# Use md5 method for all connections\nhost    all             all             all                     md5"
                }]

                overwrite_safely(
                    conffile, "".join(_tweak_lines(conflines, tweaking_rules)))
            except Exception as e:
                log.fatal("Couldn't write {!r}: {}".format(conffile, e))
                # At this point, conffile is unmodified, otherwise
                # overwrite_safely() would have succeeded
                try:
                    os.unlink(bakfile)
                except Exception as x:
                    if not (isinstance(x, OSError)
                            and x.errno == errno.ENOENT):
                        log.error("Couldn't remove {!r}: {}".format(
                            bakfile, x))

                # Restore previous postgresql.conf from the backup
                conffile = values['postgresql_conf']
                bakfile = conffile + ".rksave"
                try:
                    os.rename(bakfile, conffile)
                except Exception as x:
                    log.error(
                        "Couldn't restore {!r} from backup {!r}: {}".format(
                            conffile, bakfile, x))

                raise RolekitError(
                    COMMAND_FAILED,
                    "Changing all connections to use md5 method in '{}'"
                    "failed: {}".format(values['pg_hba_conf'], e))

            # Restart the postgresql server to accept the new configuration
            log.debug2("TRACE: Restarting postgresql.service unit")
            with SystemdJobHandler() as job_handler:
                job_path = job_handler.manager.RestartUnit(
                    "postgresql.service", "replace")
                job_handler.register_job(job_path)

                job_results = yield job_handler.all_jobs_done_future()
                if any([
                        x for x in job_results.values()
                        if x not in ("skipped", "done")
                ]):
                    details = ", ".join(
                        ["%s: %s" % item for item in job_results.items()])
                    raise RolekitError(
                        COMMAND_FAILED,
                        "Restarting service failed: %s" % details)

        # Create the systemd target definition
        target = RoleDeploymentValues(self.get_type(), self.get_name(),
                                      "Database Server")
        target.add_required_units(['postgresql.service'])

        log.debug2("TRACE: Database server deployed")

        yield target
Пример #6
0
    def do_deploy_async(self, values, sender=None):
        log.debug9("TRACE do_deploy_async(databaseserver)")
        # Do the magic
        #
        # In case of error raise an exception

        first_instance = True

        # Check whether this is the first instance of the database
        for value in self._parent.get_instances().values():
            if (
                "databaseserver" == value.get_type()
                and self.get_name() != value.get_name()
                and self.get_state() in deployed_states
            ):
                first_instance = False
                break

        # If the database name wasn't specified
        if "database" not in values:
            # Use the instance name if it was manually specified
            if self.get_name()[0].isalpha():
                values["database"] = self.get_name()
            else:
                # Either it was autogenerated or begins with a
                # non-alphabetic character; prefix it with db_
                values["database"] = "db_%s" % self.get_name()

        if "owner" not in values:
            # We'll default to db_owner
            values["owner"] = "db_owner"

        # We will assume the owner is new until adding them fails
        new_owner = True

        # Determine if a password was passed in, so we know whether to
        # suppress it from the settings list later.
        if "password" in values:
            password_provided = True
        else:
            password_provided = False

        if "postgresql_conf" not in values:
            values["postgresql_conf"] = self._settings["postgresql_conf"]

        if "pg_hba_conf" not in values:
            values["pg_hba_conf"] = self._settings["pg_hba_conf"]

        # Get the UID and GID of the 'postgres' user
        try:
            self.pg_uid = pwd.getpwnam("postgres").pw_uid
        except KeyError:
            raise RolekitError(MISSING_ID, "Could not retrieve UID for postgres user")

        try:
            self.pg_gid = grp.getgrnam("postgres").gr_gid
        except KeyError:
            raise RolekitError(MISSING_ID, "Could not retrieve GID for postgres group")

        if first_instance:
            # Initialize the database on the filesystem
            initdb_args = ["/usr/bin/postgresql-setup", "--initdb"]

            log.debug2("TRACE: Initializing database")
            result = yield async.subprocess_future(initdb_args)
            if result.status:
                # If this fails, it may be just that the filesystem
                # has already been initialized. We'll log the message
                # and continue.
                log.debug1("INITDB: %s" % result.stdout)

        # Now we have to start the service to set everything else up
        # It's safe to start an already-running service, so we'll
        # just always make this call, particularly in case other instances
        # exist but aren't running.
        log.debug2("TRACE: Starting postgresql.service unit")
        try:
            with SystemdJobHandler() as job_handler:
                job_path = job_handler.manager.StartUnit("postgresql.service", "replace")
                job_handler.register_job(job_path)
                log.debug2("TRACE: unit start job registered")

                job_results = yield job_handler.all_jobs_done_future()

                log.debug2("TRACE: unit start job concluded")

                if any([x for x in job_results.values() if x not in ("skipped", "done")]):
                    details = ", ".join(["%s: %s" % item for item in job_results.items()])
                    log.error("Starting services failed: {}".format(details))
                    raise RolekitError(COMMAND_FAILED, "Starting services failed: %s" % details)
        except Exception as e:
            log.error("Error received starting unit: {}".format(e))
            raise

        # Next we create the owner
        log.debug2("TRACE: Creating owner of new database")
        createuser_args = ["/usr/bin/createuser", values["owner"]]
        result = yield async.subprocess_future(createuser_args, uid=self.pg_uid, gid=self.pg_gid)

        if result.status:
            # If the subprocess returned non-zero, the user probably already exists
            # (such as when we're using db_owner). If the caller was trying to set
            # a password, they probably didn't realize this, so we need to throw
            # an exception.
            log.info1("User {} already exists in the database".format(values["owner"]))

            if password_provided:
                raise RolekitError(INVALID_SETTING, "Cannot set password on pre-existing user")

            # If no password was specified, we'll continue
            new_owner = False

        # If no password was requested, generate a random one here
        if not password_provided:
            values["password"] = generate_password()

        log.debug2("TRACE: Creating new database")
        createdb_args = ["/usr/bin/createdb", values["database"], "-O", values["owner"]]
        result = yield async.subprocess_future(createdb_args, uid=self.pg_uid, gid=self.pg_gid)
        if result.status:
            # If the subprocess returned non-zero, raise an exception
            raise RolekitError(COMMAND_FAILED, "Creating database failed: %d" % result.status)

        # Next, set the password on the owner
        # We'll skip this phase if the the user already existed
        if new_owner:
            log.debug2("TRACE: Setting password for database owner")
            pwd_args = [
                ROLEKIT_ROLES + "/databaseserver/tools/rk_db_setpwd.py",
                "--database",
                values["database"],
                "--user",
                values["owner"],
            ]
            result = yield async.subprocess_future(pwd_args, stdin=values["password"], uid=self.pg_uid, gid=self.pg_gid)

            if result.status:
                # If the subprocess returned non-zero, raise an exception
                log.error("Setting owner password failed: {}".format(result.status))
                raise RolekitError(COMMAND_FAILED, "Setting owner password failed: %d" % result.status)

            # If this password was provided by the user, don't save it to
            # the settings for later retrieval. That could be a security
            # issue
            if password_provided:
                values.pop("password", None)
        else:  # Not a new owner
            # Never save the password to settings for an existing owner
            log.debug2("TRACE: Owner already exists, not setting password")
            values.pop("password", None)

        if first_instance:
            # Then update the server configuration to accept network
            # connections.
            log.debug2("TRACE: Opening access to external addresses")

            # edit postgresql.conf to add listen_addresses = '*'
            conffile = values["postgresql_conf"]
            bakfile = conffile + ".rksave"

            try:
                linkfile(conffile, bakfile)

                with open(conffile) as f:
                    conflines = f.readlines()

                tweaking_rules = [
                    {
                        "regex": r"^\s*#?\s*listen_addresses\s*=.*",
                        "replace": r"listen_addresses = '*'",
                        "append_if_missing": True,
                    }
                ]

                overwrite_safely(conffile, "".join(_tweak_lines(conflines, tweaking_rules)))
            except Exception as e:
                log.fatal("Couldn't write {!r}: {}".format(conffile, e))
                # At this point, conffile is unmodified, otherwise
                # overwrite_safely() would have succeeded
                try:
                    os.unlink(bakfile)
                except Exception as x:
                    if not (isinstance(x, OSError) and x.errno == errno.ENOENT):
                        log.error("Couldn't remove {!r}: {}".format(bakfile, x))

                raise RolekitError(
                    COMMAND_FAILED, "Opening access to external addresses in '{}'" "failed: {}".format(conffile, e)
                )

            # Edit pg_hba.conf to allow 'md5' auth on IPv4 and
            # IPv6 interfaces.
            conffile = values["pg_hba_conf"]
            bakfile = conffile + ".rksave"

            try:
                linkfile(conffile, bakfile)

                with open(conffile) as f:
                    conflines = f.readlines()

                tweaking_rules = [
                    {"regex": r"^\s*host((?:\s.*)$)", "replace": r"#host\1"},
                    {
                        "regex": r"^\s*local(?:\s.*|)$",
                        "append": "# Use md5 method for all connections\nhost    all             all             all                     md5",
                    },
                ]

                overwrite_safely(conffile, "".join(_tweak_lines(conflines, tweaking_rules)))
            except Exception as e:
                log.fatal("Couldn't write {!r}: {}".format(conffile, e))
                # At this point, conffile is unmodified, otherwise
                # overwrite_safely() would have succeeded
                try:
                    os.unlink(bakfile)
                except Exception as x:
                    if not (isinstance(x, OSError) and x.errno == errno.ENOENT):
                        log.error("Couldn't remove {!r}: {}".format(bakfile, x))

                # Restore previous postgresql.conf from the backup
                conffile = values["postgresql_conf"]
                bakfile = conffile + ".rksave"
                try:
                    os.rename(bakfile, conffile)
                except Exception as x:
                    log.error("Couldn't restore {!r} from backup {!r}: {}".format(conffile, bakfile, x))

                raise RolekitError(
                    COMMAND_FAILED,
                    "Changing all connections to use md5 method in '{}'" "failed: {}".format(values["pg_hba_conf"], e),
                )

            # Restart the postgresql server to accept the new configuration
            log.debug2("TRACE: Restarting postgresql.service unit")
            with SystemdJobHandler() as job_handler:
                job_path = job_handler.manager.RestartUnit("postgresql.service", "replace")
                job_handler.register_job(job_path)

                job_results = yield job_handler.all_jobs_done_future()
                if any([x for x in job_results.values() if x not in ("skipped", "done")]):
                    details = ", ".join(["%s: %s" % item for item in job_results.items()])
                    raise RolekitError(COMMAND_FAILED, "Restarting service failed: %s" % details)

        # Create the systemd target definition
        target = RoleDeploymentValues(self.get_type(), self.get_name(), "Database Server")
        target.add_required_units(["postgresql.service"])

        log.debug2("TRACE: Database server deployed")

        yield target
Пример #7
0
    def deploy_async(self, values, sender=None):
        """deploy role"""
        remove_instance = False

        values = dbus_to_python(values)

        # Make sure we are in the proper state
        self.assert_state(NASCENT)

        # Log
        log.debug1("%s.deploy(%s)", self._log_prefix, values)

        # Check values
        try:
            self.check_values(values)
        except Exception as e:
            # Check values failed, remove the instance again if verification
            # failed, set state to error, save it (will be visible in the
            # .old backup file).
            self.change_state(ERROR, error=str(e), write=True)

            # cleanup
            self.__remove_instance()
            raise

        try:
            # Change to deploying state
            self.change_state(DEPLOYING)

            # Copy _DEFAULTS to self._settings
            self.copy_defaults()

            # Install package groups and packages
            log.debug9("TRACE: Installing packages")
            yield async.call_future(self.installPackages())

            # Install firewall
            self.installFirewall()

            # Call do_deploy
            log.debug9("TRACE: Performing role-specific deployment")
            try:
                target = yield async.call_future(self.do_deploy_async(values, sender))
            except RolekitError as e:
                if e.code == INVALID_VALUE:
                    # If we failed because the input values were incorrect,
                    # also remove the instance.
                    remove_instance = True
                raise

            # Continue only after successful deployment:
            # Apply values to self._settings
            log.debug9("TRACE: role-specific deployment complete, applying values")
            self.apply_values(values)

            # Set up systemd target files
            log.debug9("TRACE: Creating systemd target files")
            self.create_target(target)

            # Change to ready to start state
            self.change_state(READY_TO_START, write=True)

            # In case this was a nextboot deployment, make sure to remove
            # the deferred role settings and systemd unit
            try:
                # Remove settings
                deferredsettings = "%s/%s/%s.json" % (ETC_ROLEKIT_DEFERREDROLES, self.get_type(), self.get_name())
                os.unlink(deferredsettings)

                # Remove systemd service unit
                deferredunit = "%s/deferred-role-deployment-%s-%s.service" % (
                    SYSTEMD_UNITS, self.get_type(), self.get_name())
                disable_units([deferredunit])
                os.unlink(deferredunit)
            except FileNotFoundError:
                # Files didn't exist; ignore that
                pass
            except PermissionError:
                # SELinux bug?
                log.fatal("ERROR: permission error attempting to delete %s or %s" % (
                    deferredsettings, deferredunit
                ))
                # We'll continue anyway, since the service should be runnable at this point
                # The ConditionPathExists will prevent the service from trying to deploy
                # again

            # Tell systemd to reload the daemon configuration
            log.debug9("Reloading systemd units\n")
            with SystemdJobHandler() as job_handler:
                job_handler.manager.Reload()


            # Start monitoring the role
            self.monitor_unit()

            # Attempt to start the newly-deployed role
            # We do this because many role-installers will conclude by
            # starting anyway and we want to ensure that our role mechanism
            # is in sync with them.
            log.debug9("TRACE: Starting %s" % self.get_name())
            yield async.call_future(self.__start_async(sender))

        except Exception as e:
            # Something failed, set state to error
            self.change_state(ERROR, error=str(e), write=True)
            if remove_instance:
                self.__remove_instance()
            raise
Пример #8
0
    def deploy_async(self, values, sender=None):
        """deploy role"""
        remove_instance = False

        values = dbus_to_python(values)

        # Make sure we are in the proper state
        self.assert_state(NASCENT)

        # Log
        log.debug1("%s.deploy(%s)", self._log_prefix, values)

        # Check values
        try:
            self.check_values(values)
        except Exception as e:
            # Check values failed, remove the instance again if verification
            # failed, set state to error, save it (will be visible in the
            # .old backup file).
            self.change_state(ERROR, error=str(e), write=True)

            # cleanup
            self.__remove_instance()
            raise

        try:
            # Change to deploying state
            self.change_state(DEPLOYING)

            # Copy _DEFAULTS to self._settings
            self.copy_defaults()

            # Install package groups and packages
            log.debug9("TRACE: Installing packages")
            yield async .call_future(self.installPackages())

            # Install firewall
            self.installFirewall()

            # Call do_deploy
            log.debug9("TRACE: Performing role-specific deployment")
            try:
                target = yield async .call_future(
                    self.do_deploy_async(values, sender))
            except RolekitError as e:
                if e.code == INVALID_VALUE:
                    # If we failed because the input values were incorrect,
                    # also remove the instance.
                    remove_instance = True
                raise

            # Continue only after successful deployment:
            # Apply values to self._settings
            log.debug9(
                "TRACE: role-specific deployment complete, applying values")
            self.apply_values(values)

            # Set up systemd target files
            log.debug9("TRACE: Creating systemd target files")
            self.create_target(target)

            # Change to ready to start state
            self.change_state(READY_TO_START, write=True)

            # In case this was a nextboot deployment, make sure to remove
            # the deferred role settings and systemd unit
            try:
                # Remove settings
                deferredsettings = "%s/%s/%s.json" % (
                    ETC_ROLEKIT_DEFERREDROLES, self.get_type(),
                    self.get_name())
                os.unlink(deferredsettings)

                # Remove systemd service unit
                deferredunit = "%s/deferred-role-deployment-%s-%s.service" % (
                    SYSTEMD_UNITS, self.get_type(), self.get_name())
                disable_units([deferredunit])
                os.unlink(deferredunit)
            except FileNotFoundError:
                # Files didn't exist; ignore that
                pass
            except PermissionError:
                # SELinux bug?
                log.fatal(
                    "ERROR: permission error attempting to delete %s or %s" %
                    (deferredsettings, deferredunit))
                # We'll continue anyway, since the service should be runnable at this point
                # The ConditionPathExists will prevent the service from trying to deploy
                # again

            # Tell systemd to reload the daemon configuration
            log.debug9("Reloading systemd units\n")
            with SystemdJobHandler() as job_handler:
                job_handler.manager.Reload()

            # Start monitoring the role
            self.monitor_unit()

            # Attempt to start the newly-deployed role
            # We do this because many role-installers will conclude by
            # starting anyway and we want to ensure that our role mechanism
            # is in sync with them.
            log.debug9("TRACE: Starting %s" % self.get_name())
            yield async .call_future(self.__start_async(sender))

        except Exception as e:
            # Something failed, set state to error
            self.change_state(ERROR, error=str(e), write=True)
            if remove_instance:
                self.__remove_instance()
            raise