Пример #1
0
    def __init__(self, config):
        formatter = ResponseFormatter()
        ResponsePage.__init__(self, '', formatter)
        self.config = config

        # Regular Expression for matching variables in a path definition.
        # Currently only supports stuffing a single variable in a path
        # component.
        varmatch = re.compile(r'^%\((.*)\)s$')

        BINDIR = os.path.dirname(os.path.realpath(sys.argv[0]))
        tree = ET.parse(os.path.join(BINDIR, '..', 'etc', 'input.xml'))

        for command in tree.getiterator("command"):
            for transport in command.getiterator("transport"):
                if "name" not in command.attrib \
                        or "method" not in transport.attrib \
                        or "path" not in transport.attrib:
                    continue
                name = command.attrib["name"]
                method = transport.attrib["method"]
                path = transport.attrib["path"]
                trigger = transport.attrib.get("trigger")
                container = self
                relative = ""
                # Traverse down the resource tree, container will
                # end up pointing to the correct spot.
                # Create branches and leaves as necessary, continueing to
                # traverse downward.
                for component in path.split("/"):
                    relative = relative + "/" + component
                    #log.msg("Working with component '" + component + "' of '" + relative + "'.")
                    m = varmatch.match(component)
                    # Is this piece of the path dynamic?
                    if not m:
                        #log.msg("Component '" + component + "' is static.")
                        child = container.getStaticEntity(component)
                        if child is None:
                            #log.msg("Creating new static component '" + component + "'.")
                            child = ResponsePage(relative, formatter)
                            container.putChild(component, child)
                        container = child
                    else:
                        #log.msg("Component '" + component + "' is dynamic.")
                        path_variable = m.group(1)
                        if container.dynamic_child is not None:
                            #log.msg("Dynamic component '" + component + "' already exists.")
                            current_variable = container.dynamic_child.\
                                    path_variable
                            if current_variable != path_variable:
                                log.msg("Warning: Could not use variable '" +
                                        path_variable + "', already have " +
                                        "dynamic variable '" +
                                        current_variable + "'.")
                                # XXX: Raise an error if they don't match
                                container = container.dynamic_child
                            else:
                                #log.msg("Dynamic component '" + component + "' had correct variable.")
                                container = container.dynamic_child
                        else:
                            #log.msg("Creating new dynamic component '" + component + "'.")
                            child = ResponsePage(relative,
                                                 formatter,
                                                 path_variable=path_variable)
                            container.dynamic_child = child
                            container = child

                fullcommand = name
                if trigger:
                    fullcommand = fullcommand + "_" + trigger
                mymodule = getattr(commands, fullcommand, None)
                if not mymodule:
                    log.msg("No module available in aquilon.worker.commands " +
                            "for %s" % fullcommand)
                # See commands/__init__.py for more info here...
                myinstance = getattr(mymodule, "broker_command", None)
                if not myinstance:
                    log.msg("No class instance available for %s" % fullcommand)
                    myinstance = BrokerCommand()
                myinstance.command = name
                rendermethod = method.upper()
                if container.handlers.get(rendermethod, None):
                    log.msg("Warning: Already have a %s here at %s..." %
                            (rendermethod, container.path))
                #log.msg("Setting 'command_" + fullcommand + "' as '" + rendermethod + "' for container '" + container.path + "'.")
                container.handlers[rendermethod] = myinstance

                # Since we are parsing input.xml anyway, record the possible
                # parameters...
                for option in command.getiterator("option"):
                    if "name" not in option.attrib:
                        continue
                    option_name = option.attrib["name"]
                    if option_name not in myinstance.optional_parameters:
                        myinstance.optional_parameters.append(option_name)
                    if "type" in option.attrib:
                        paramtype = option.attrib["type"]
                        myinstance.parameter_types[option_name] = paramtype
                        if paramtype == "int":
                            myinstance.parameter_checks[
                                option_name] = force_int
                        elif paramtype == "float":
                            myinstance.parameter_checks[
                                option_name] = force_float
                        elif paramtype == "boolean" or paramtype == "flag":
                            myinstance.parameter_checks[
                                option_name] = force_boolean
                        elif paramtype == "ipv4":
                            myinstance.parameter_checks[
                                option_name] = force_ipv4
                        elif paramtype == "mac":
                            myinstance.parameter_checks[
                                option_name] = force_mac
                        elif paramtype == "json":
                            myinstance.parameter_checks[
                                option_name] = force_json_dict
                        elif paramtype == "string" or paramtype == "file":
                            # Current twisted can't handle unicode output, so
                            # do not allow non-ASCII input either
                            myinstance.parameter_checks[
                                option_name] = force_ascii
                        elif paramtype == "list":
                            myinstance.parameter_checks[
                                option_name] = force_list
                        else:  # pragma: no cover
                            log.msg("Warning: unknown option type %s" %
                                    paramtype)
                    else:  # pragma: no cover
                        log.msg("Warning: argument type not known for %s.%s" %
                                (myinstance.command, option_name))
                    pbt = myinstance.parameters_by_type
                    for option_name, paramtype \
                            in myinstance.parameter_types.items():
                        if paramtype in pbt:
                            pbt[paramtype].append(option_name)
                        else:
                            pbt[paramtype] = [option_name]

        cache_version(config)
        log.msg("Starting aqd version %s" % config.get("broker", "version"))
        self.make_required_dirs()

        def _logChildren(level, container):
            for (key, child) in container.listStaticEntities():
                log.msg("Resource at level %d for %s [key:%s]" %
                        (level, child.path, key))
                _logChildren(level + 1, child)
            if getattr(container, "dynamic_child", None):
                log.msg("Resource at level %d for %s [dynamic]" %
                        (level, container.dynamic_child.path))
                _logChildren(level + 1, container.dynamic_child)
Пример #2
0
    def __init__(self):
        """ Provides some convenient variables for commands.

        Also sets requires_* parameters for some sets of commands.
        All of the command objects are singletons (or Borg).

        """
        self.dbf = DbFactory()
        self.config = Config()
        self.az = AuthorizationBroker()
        self.formatter = ResponseFormatter()
        self.catalog = StatusCatalog()
        # Force the instance to have local copies of the class defaults...
        # This allows resources.py to modify instances without worrying
        # about inheritance issues (classes sharing required or optional
        # parameters).
        self.required_parameters = self.required_parameters[:]
        self.optional_parameters = self.optional_parameters[:]

        # Parameter checks are filled in automatically based on input.xml. This
        # lets us do some rudimentary checks before the actual command is
        # invoked.
        self.parameter_checks = {}

        # The parameter types are filled in automatically based on input.xml.
        self.parameter_types = {}
        # This is the pivot of the above, filled in at the same time.  It is a
        # dictionary of type names to lists of parameters.
        self.parameters_by_type = {}

        self.action = self.__module__
        package_prefix = "aquilon.worker.commands."
        if self.action.startswith(package_prefix):
            self.action = self.action[len(package_prefix):]
        # self.command is set correctly in resources.py after parsing input.xml
        self.command = self.action
        # The readonly and format flags are done here for convenience
        # and simplicity.  They could be overridden by the __init__
        # method of any show/search/cat commands that do not want these
        # defaults.  Some 'one-off' commands (like ping and status)
        # just set the variables themselves.
        if self.action.startswith("show") or self.action.startswith("search"):
            self.requires_readonly = True
            self.requires_format = True
        if self.action.startswith("cat"):
            self.requires_format = True
            self.requires_readonly = True
            self._is_lock_free = True
        if not self.requires_readonly \
           and self.config.get('broker', 'mode') == 'readonly':
            self.badmode = 'readonly'
        else:
            self.badmode = False
        self._update_render(self.render)
        if not self.defer_to_thread:
            if self.requires_azcheck or self.requires_transaction:
                self.defer_to_thread = True
                log.msg("Forcing defer_to_thread to True because of "
                        "required authorization or transaction for %s" %
                        self.command)
            # Not sure how to handle formatting with deferred...
            self.requires_format = False