def __init__(self, parent, name, type_name, directory, settings, *args, **kwargs): """The DBUS_INTERFACE_ROLE_INSTANCE implementation. :param parent: The DBusRole Object this is attached to :param name: Instance name :param type_name: Role name :param directory: FIXME: unused??? :param settings: RoleSettings for the role :param path: (Implicit in *args) FIXME: unused??? """ super(RoleBase, self).__init__(*args, **kwargs) self.busname = args[0] self.path = args[1] self._bus = slip.dbus.SystemBus() self._parent = parent self._name = name self._escaped_name = dbus_label_escape(name) self._type = type_name self._escaped_type = dbus_label_escape(type_name) self._log_prefix = "role.%s.%s" % (self._escaped_type, self._escaped_name) self._directory = directory self._settings = settings self._settings.connect("changed", self._emit_property_changed) # TODO: place target_unit in settings self.target_unit = get_target_unit_name(self.get_type(), self.get_name()) # No loaded self._settings, set state to NASCENT if not "state" in self._settings: self._settings["state"] = NASCENT elif self._settings["state"] == SYSTEMD: # We need to get the current state from systemd try: self._settings["state"] = target_unit_state(self.target_unit) except: # If we couldn't get the target state, we need to assume that # it is ERROR self._settings["state"] = ERROR self.timeout_restart() return # Then we need to set up a signal monitor to update this state # if it changes in systemd self.monitor_unit() self.timeout_restart()
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 getNamedInstance(self, name, sender=None): """ return the role with the name, otherwise raise error """ name = dbus_to_python(name) log.debug1("%s.getNamedInstance('%s')", self._log_prefix, name) instance_escaped_name = dbus_label_escape(name) if instance_escaped_name in self._instances: return self._instances[instance_escaped_name] raise RolekitError(INVALID_INSTANCE, name)
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 remove_instance(self, instance): """Remove an instance from our list. Note that this neither undeploys it nor deletes the settings file. """ name = instance.get_name() escaped_name = dbus_label_escape(name) if escaped_name in self._instances: del self._instances[escaped_name] self.InstanceRemoved(escaped_name)
def __deploy_async(self, name, values): values = dbus_to_python(values) name = dbus_to_python(name) log.debug1("%s.deploy('%s', %s)", self._log_prefix, name, values) # limit role instances to max instances per role if len(self._instances) >= self._role._MAX_INSTANCES: raise RolekitError(TOO_MANY_INSTANCES, "> %d" % \ self._role._MAX_INSTANCES) # TODO: lock # Create the settings object. If no name has been passed in, # this function will create one from the next available value. # Note: this isn't protected by a lock, so name-generation # might be racy. settings = RoleSettings(self.get_name(), name) # create escaped name and check if it is already in use instance_escaped_name = dbus_label_escape(settings.get_name()) if instance_escaped_name in self._instances: raise RolekitError(NAME_CONFLICT, instance_escaped_name) try: settings.read() except ValueError: raise RolekitError(NAME_CONFLICT, settings.filename) except IOError: pass else: raise RolekitError(NAME_CONFLICT, settings.filename) # create role role = self._role( self, settings.get_name(), self.get_name(), self._directory, settings, self.busname, "%s/%s/%s" % (DBUS_PATH_ROLES, self._escaped_name, instance_escaped_name), persistent=self.persistent) self._instances[instance_escaped_name] = role self.InstanceAdded(instance_escaped_name) # TODO: unlock # deploy role, lock in role now result = yield async .call_future(role.deploy_async(values)) yield result
def __deploy_async(self, name, values): values = dbus_to_python(values) name = dbus_to_python(name) log.debug1("%s.deploy('%s', %s)", self._log_prefix, name, values) # limit role instances to max instances per role if len(self._instances) >= self._role._MAX_INSTANCES: raise RolekitError(TOO_MANY_INSTANCES, "> %d" % \ self._role._MAX_INSTANCES) # TODO: lock # Create the settings object. If no name has been passed in, # this function will create one from the next available value. # Note: this isn't protected by a lock, so name-generation # might be racy. settings = RoleSettings(self.get_name(), name) # create escaped name and check if it is already in use instance_escaped_name = dbus_label_escape(settings.get_name()) if instance_escaped_name in self._instances: raise RolekitError(NAME_CONFLICT, instance_escaped_name) try: settings.read() except ValueError: raise RolekitError(NAME_CONFLICT, settings.filename) except IOError: pass else: raise RolekitError(NAME_CONFLICT, settings.filename) # create role role = self._role(self, settings.get_name(), self.get_name(), self._directory, settings, self.busname, "%s/%s/%s" % (DBUS_PATH_ROLES, self._escaped_name, instance_escaped_name), persistent=self.persistent) self._instances[instance_escaped_name] = role self.InstanceAdded(instance_escaped_name) # TODO: unlock # deploy role, lock in role now result = yield async.call_future(role.deploy_async(values)) yield result
def __init__(self, role, name, directory, *args, **kwargs): """The DBUS_INTERFACE_ROLE implementation :param role: RoleBase descendant :param name: Role name :param directory: FIXME: unused??? :param path: (Implicit in *args) FIXME: unused??? """ super(DBusRole, self).__init__(*args, **kwargs) self.busname = args[0] self.path = args[1] self._role = role self._name = name self._escaped_name = dbus_label_escape(name) self._log_prefix = "role.%s" % self._escaped_name self._directory = directory self._instances = { } # create instances for stored instance settings path = "%s/%s" % (ETC_ROLEKIT_ROLES, self.get_name()) if os.path.exists(path) and os.path.isdir(path): for name in sorted(os.listdir(path)): if not name.endswith(".json"): continue instance = name[:-5] log.debug1("Loading '%s' instance '%s'", self.get_name(), instance) settings = RoleSettings(self.get_name(), instance) try: settings.read() except ValueError as e: log.error("Failed to load '%s' instance '%s': %s", self.get_name(), instance, e) continue instance_escaped_name = dbus_label_escape(instance) if instance_escaped_name in self._instances: raise RolekitError(NAME_CONFLICT, instance_escaped_name) role = self._role(self, instance, self.get_name(), self._directory, settings, self.busname, "%s/%s/%s" % (DBUS_PATH_ROLES, self._escaped_name, instance_escaped_name), persistent=self.persistent) # During roled startup (the only time this function should be # called), if any role is in a transitional state, it can only # mean that roled was terminated while it was still supposed # to be doing something. # Always set the state to ERROR here if it's in a transitional state, # otherwise we won't be able to clean it up. if role._settings["state"] in TRANSITIONAL_STATES: role.change_state(state=ERROR, write=True, error="roled terminated unexpectedly") self._instances[instance_escaped_name] = role self.timeout_restart()
def __init__(self, role, name, directory, *args, **kwargs): """The DBUS_INTERFACE_ROLE implementation :param role: RoleBase descendant :param name: Role name :param directory: FIXME: unused??? :param path: (Implicit in *args) FIXME: unused??? """ super(DBusRole, self).__init__(*args, **kwargs) self.busname = args[0] self.path = args[1] self._role = role self._name = name self._escaped_name = dbus_label_escape(name) self._log_prefix = "role.%s" % self._escaped_name self._directory = directory self._instances = {} # create instances for stored instance settings path = "%s/%s" % (ETC_ROLEKIT_ROLES, self.get_name()) if os.path.exists(path) and os.path.isdir(path): for name in sorted(os.listdir(path)): if not name.endswith(".json"): continue instance = name[:-5] log.debug1("Loading '%s' instance '%s'", self.get_name(), instance) settings = RoleSettings(self.get_name(), instance) try: settings.read() except ValueError as e: log.error("Failed to load '%s' instance '%s': %s", self.get_name(), instance, e) continue instance_escaped_name = dbus_label_escape(instance) if instance_escaped_name in self._instances: raise RolekitError(NAME_CONFLICT, instance_escaped_name) role = self._role(self, instance, self.get_name(), self._directory, settings, self.busname, "%s/%s/%s" % (DBUS_PATH_ROLES, self._escaped_name, instance_escaped_name), persistent=self.persistent) # During roled startup (the only time this function should be # called), if any role is in a transitional state, it can only # mean that roled was terminated while it was still supposed # to be doing something. # Always set the state to ERROR here if it's in a transitional state, # otherwise we won't be able to clean it up. if role._settings["state"] in TRANSITIONAL_STATES: role.change_state(state=ERROR, write=True, error="roled terminated unexpectedly") self._instances[instance_escaped_name] = role self.timeout_restart()