예제 #1
0
    def post_init(self):
        # Assure that exec_args is set to the actual arguments used for execution
        if self.command:
            self.exec_args = shlex.split(self.command)

        # Lookup signal number
        if self.kill_signal is not None:
            self.kill_signal = get_signal_number(self.kill_signal)

        # Expand before, after and service_groups into sets/tuples
        self.before = set(_RE_LISTSEP.split(self.before)) if self.before is not None else set()
        self.after = set(_RE_LISTSEP.split(self.after)) if self.after is not None else set()
        self.service_groups = tuple(_RE_LISTSEP.split(self.service_groups)) if self.service_groups is not None else tuple()

        for sname in chain(self.before, self.after):
            if sname.upper() == sname and sname not in chain(self.system_group_names, self.system_service_names):
                raise ChParameterError("{0} dependency reference not valid; '{1}' is not a recognized system name"
                                       .format(self.name, sname))

        for sname in self.service_groups:
            if sname.upper() == sname and sname not in self.system_group_names:
                raise ChParameterError("{0} contains an unrecognized system group name '{1}'".format(self.name, sname))

        if 'IDLE' in self.after:
            raise Exception("{0} cannot specify services which start *after* service_group IDLE".format(self.name))
        if 'INIT' in self.before:
            raise Exception("{0} cannot specify services which start *before* service_group INIT".format(self.name))
예제 #2
0
    def __init__(self, service, family=None):

        self.service = service
        self.family = family

        self._pending = set()

        if service.process_timeout is not None:
            self.process_timeout = service.process_timeout

        if not service.environment:
            self._procenv = Environment()
        else:
            self._procenv = service.environment

        if not service.exec_args:
            raise ChParameterError(
                "No command or arguments provided for service")

        # If the service is enabled, assure we check for the presence of the executable now.  This is
        # to catch any start-up situations (such as cron jobs without their executables being present).
        # However, we don't check this if a service is disabled.

        self._orig_executable = service.exec_args[0]

        if service.enabled:
            self._try_to_enable()
예제 #3
0
    def __init__(self, service, family=None):
        super().__init__(service, family)
        self._proclist = set()

        if not service.port:
            raise ChParameterError(
                "inetd-type service {0} requires 'port=' parameter".format(
                    self.name))
예제 #4
0
 def _typecheck_assure_int(self, attr):
     "Assures that the specified attribute is a legal integer."
     val = getattr(self, attr)
     if val is None or isinstance(val, int):
         return
     try:
         setattr(self, attr, int(val))
     except ValueError:
         raise ChParameterError("invalid integer parameter for '{0}': '{1}'".format(attr, val))
예제 #5
0
 def _typecheck_assure_bool(self, attr):
     "Assures that the specified attribute is a legal boolean."
     val = getattr(self, attr)
     if val is None or isinstance(val, bool):
         return
     # First, try both 'true' and 'false' according to YAML conventions
     match = _RE_YAML_BOOL.match(str(val))
     if not match:
         raise ChParameterError("invalid boolean parameter for '{0}': '{1}'".format(attr, val))
     setattr(self, attr, bool(match.group('true')))
예제 #6
0
 def _lookup_services(self, names):
     result = set()
     for name in names:
         serv = self.get(name)
         if not serv:
             serv = self.get(name + ".service")
         if not serv:
             raise ChParameterError("no such service: " + name)
         result.add(serv)
     return result
예제 #7
0
파일: misc.py 프로젝트: yutiansut/chaperone
def get_signal_number(signame):
    sup = signame.upper()
    if sup.startswith('SIG') and not sup.startswith('SIG_'):
        num = getattr(signal, sup, None)
    else:
        try:
            num = int(signame)
        except ValueError:
            num = None

    if num is None:
        raise ChParameterError("Invalid signal specifier: " + str(signame))

    return num
예제 #8
0
파일: cron.py 프로젝트: yutiansut/chaperone
    def __init__(self, service, family=None):
        super().__init__(service, family)
        if not self.interval:
            raise ChParameterError(
                "interval= property missing, required for cron service '{0}'".
                format(self.name))

        # Support specials with or without the @
        real_interval = _CRON_SPECIALS.get(
            self.interval) or _CRON_SPECIALS.get(
                '@' + self.interval) or self.interval

        # make a status note
        self.note = "{0} ({1})".format(
            self.interval,
            real_interval) if self.interval != real_interval else real_interval

        self._cron = crontab(real_interval, func=self._cron_hit, start=False)
예제 #9
0
    def __init__(self, initdict, name = "MAIN", env = None, settings = None):
        self.name = name

        if settings:
            for sd in self._settings_defaults:
                if sd not in initdict:
                    val = settings.get(sd)
                    if val is not None:
                        setattr(self, sd, val)

        for k,v in initdict.items():
            setattr(self, k, v)

        # User names always have .xxx qualifier because of schema restrictions.  Otherwise, it's a user
        # defined name subject to restrictions.

        splitname = self.name.rsplit('.', 1)
        if len(splitname) == 2 and splitname[0] == splitname[0].upper():
            raise ChParameterError("all-uppercase names such as '{0}' are reserved for the system.".format(self.name))

        # UID and GID are expanded according to the incoming environment,
        # since the new environment depends upon these.
        if env:
            env.expand_attributes(self, 'uid', 'gid')

        uid = self.get('uid')
        gid = self.get('gid')

        if gid is not None and uid is None:
            raise Exception("cannot specify 'gid' without 'uid'")

        # We can now use 'self' as our config, with all defaults. 

        env = self.environment = Environment(env, uid=uid, gid=gid, config=self, 
                                             resolve_xid = not self.get('optional', False))
        self.augment_environment(env)

        if self._expand_these:
            env.expand_attributes(self, *self._expand_these)

        for attr,func in self._typecheck.items():
            getattr(self, '_typecheck_'+func)(attr)

        self.post_init()
예제 #10
0
파일: cron.py 프로젝트: yutiansut/chaperone
    def start(self):
        """
        Takes over startup and sets up our cron loop to handle starts instead.
        """
        if not self.enabled or self._cron.handle:
            return

        self.start_attempted = True

        # Start up cron
        try:
            self._cron.start()
        except Exception:
            raise ChParameterError(
                "not a valid cron interval specification, '{0}'".format(
                    self.interval))

        self.loginfo(
            "cron service {0} scheduled using interval spec '{1}'".format(
                self.name, self.interval))
예제 #11
0
파일: misc.py 프로젝트: yutiansut/chaperone
def maybe_create_user(user,
                      uid=None,
                      gid=None,
                      using_file=None,
                      default_home=None):
    """
    If the user does not exist, then create one with the given name, and optionally
    the specified uid.  If a gid is specified, create a group with the same name as the 
    user, and the given gid.

    If the user does exist, then confirm that the uid and gid match, if either
    or both are specified.

    If 'using_file' is specified, then uid/gid are ignored and replaced with the uid/gid
    of the specified file.  The file must exist and be readable.
    """

    if using_file:
        stat = os.stat(using_file)
        if uid is None:
            uid = stat.st_uid
        if gid is None:
            gid = stat.st_gid

    if uid is not None:
        try:
            uid = int(uid)
        except ValueError:
            raise ChParameterError(
                "Specified UID is not a number: {0}".format(uid))

    try:
        pwrec = lookup_user(user)
    except ChNotFoundError:
        pwrec = None

    # If the user exists, we do nothing, but we do validate that their UID and GID
    # exist.

    if pwrec:
        if uid is not None and uid != pwrec.pw_uid:
            raise ChParameterError(
                "User {0} exists, but does not have expected UID={1}".format(
                    user, uid))
        if gid is not None and lookup_group(gid).gr_gid != pwrec.pw_gid:
            raise ChParameterError(
                "User {0} exists, but does not have expected GID={1}".format(
                    user, gid))
        return

    # Now, we need to create the user, and optionally the group.

    if gid is not None:

        create_group = False
        try:
            newgid = lookup_group(gid).gr_name  # always use name
        except ChNotFoundError:
            create_group = True
            try:
                newgid = int(gid)  # must be a number at this point
            except ValueError:
                # We don't report the numeric error, because we *know* there is no such group
                # and we won't create a symbolic group with a randomly-created number.
                raise ChParameterError("Group does not exist: {0}".format(gid))

        if create_group:
            groupadd(user, newgid)
            newgid = lookup_group(user).gr_name

        gid = newgid  # always will be the group name

    # Test to see if the user directory itself already exists, which should be the case.
    # If it doesn't, then use the default, if provided.

    home = None

    if default_home:
        udd = get_user_directories_directory()
        if not os.path.exists(os.path.join(udd, user)):
            home = default_home

    useradd(user, uid, gid, home)
예제 #12
0
    def _expand_into(self, k, wholematch, result, parent=None):
        """
        Internal workhorse that expands the variable 'k' INTO the given result dictionary.
        The result dictionary will conatin the expanded values.   The result dictionary is
        also a cache for nested and recursive environment expansion.

        'wholematch' is None unless called from in an re.sub() (or similar context).
                 If set, it indicates the complete expansion expression, including adornments.
                 It is used as the default expansion when a variable is not defined.
        'parent' is the name of the variable which was being expanded in the last
                 recursion, to catch the special case of self-referential variables.
        """

        match = _RE_OPERS.match(k)

        if match:
            (k, oper, repl, backtick) = match.groups()

        # Phase 1: Base variable value.  Start by determining the value of variable
        #          'k' within the current context.

        # 1A: We have a backtick shortcut, such as $(`date`)
        if match and backtick:
            return self._recurse(result, backtick, parent)

        # 1B: We have an embedded self reference such as "PATH": "/bin:$(PATH)".  We use
        #     the last defined value in a prior environment as the value.
        elif parent == k and wholematch is not None:
            val = (self._get_shadow_environment(k) or _DICT_CONST).get(k) or ''

        # 1C: We have already calculated a result and will use that instead, but only
        #     in a nested expansion.  We re-evaluate top-levels all the time.
        elif wholematch is not None and k in result:
            val = result[k]

        # 1D: We have a variable which is not part of our environment at all, and
        #     either treat it as empty, or as the wholematch value for further
        #     processing
        elif k not in self:
            val = "" if match else wholematch

        # 1E: Finally, we will store this value and expand further.
        else:
            result[k] = self[
                k]  # assure that recursion attempts stop with this value
            val = result[k] = self._recurse(result, self[k], k)

        # We now have, in 'val', the fully expanded contents of the variable 'k'

        if not match:
            return val

        # Phase 2: Process any operators to return a possibily modified
        #          value as the result of the complete expression.

        if oper == '?':
            if not val:
                raise ChVariableError(self._recurse(result, repl, parent))

        elif oper == '/':
            smatch = _RE_SLASHOP.match(repl)
            if not smatch:
                raise ChParameterError(
                    "invalid regex replacement syntax in '{0}'".format(
                        match.group(0)))

            val = self._recurse(
                result,
                re.sub((smatch.group(3) and "(?" + smatch.group(3) + ")") +
                       smatch.group(1),
                       smatch.group(2).replace('\/', '/'), val), parent)

        elif oper == '|':
            vts = _RE_BAREBAR.split(repl, 3)
            if len(vts) == 1:  # same as +
                val = '' if not val else self._recurse(result, vts[0], parent)
            elif len(vts) == 2:
                val = self._recurse(result, vts[0] if val else vts[1], parent)
            elif len(vts) >= 3:
                editval = vts[1] if fnmatch(
                    val.replace(r'\|', '|').lower(),
                    vts[0].lower()) else vts[2]
                val = self._recurse(result, editval.replace(r'\|', '|'),
                                    parent)

        elif oper == "+":
            val = '' if not val else self._recurse(result, repl, parent)

        elif oper == "_":  # strict opposite of +
            val = '' if val else self._recurse(result, repl, parent)

        elif oper == "-":  # bash :-
            if not val:
                val = self._recurse(result, repl, parent)

        return val