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
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
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}
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 }
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
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
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
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