Exemplo n.º 1
0
 def route_request(self, handle, connection, command, headers, data):
     if self.node.quitting:
         # Answer internal error on all requests while quitting, assume client can handle that
         # TODO: Answer permantely moved (301) instead with header Location: <another-calvin-runtime>???
         self.send_response(handle,
                            connection,
                            None,
                            status=calvinresponse.INTERNAL_ERROR)
         return
     try:
         issuetracker = IssueTracker()
         handler, match = self._handler_for_route(command)
         if handler:
             credentials = None
             if data:
                 data = json.loads(data)
             _log.debug("Calvin control handles:%s\n%s\n---------------" %
                        (command, data))
             handler(handle, connection, match, data, headers)
         else:
             _log.error("No route found for: %s\n%s" % (command, data))
             self.send_response(handle, connection, None, status=404)
     except Exception as e:
         _log.info("Failed to parse request", exc_info=e)
         self.send_response(handle,
                            connection,
                            None,
                            status=calvinresponse.BAD_REQUEST)
Exemplo n.º 2
0
 def process(self, source_file, issuetracker=None):
     path = os.path.dirname(source_file)
     self.path = _expand_path(path)
     self.source_file = _expand_path(source_file)
     self.issuetracker = issuetracker or IssueTracker()
     self.line_number = 0
     return self._process(), self.issuetracker
Exemplo n.º 3
0
 def get_components(filename, names):
     try:
         with open(filename, 'r') as source:
             source_text = source.read()
     except:
         from calvin.utilities.issuetracker import IssueTracker
         it = IssueTracker()
         it.add_error('File not found', {'script': filename})
         return [], it
     return calvin_components(source_text, names)
Exemplo n.º 4
0
 def parse(self, source_text):
     # return ir (AST) and issuetracker
     self.issuetracker = IssueTracker()
     self.source_text = source_text
     try:
         ir = self.parser.parse(source_text)
     except SyntaxError as e:
         self.issuetracker.add_error(e.text, {
             'line': e.lineno,
             'col': e.offset
         })
         ir = ast.Node()
     return ir, self.issuetracker
Exemplo n.º 5
0
    def parse(self, source_text, logger=None):
        # return ir (AST) and issuetracker
        self.issuetracker = IssueTracker()
        self.source_text = source_text
        root = None

        try:
            root = self.parser.parse(source_text, debug=logger)
        except SyntaxError as e:
            self.issuetracker.add_error(e.text, {'line':e.lineno, 'col':e.offset})
        finally:
            ir = root or ast.Node()

        return ir, self.issuetracker
Exemplo n.º 6
0
 def _handle_policy_decision(data,
                             appname,
                             verify,
                             access_decision,
                             org_cb,
                             security=None):
     if not access_decision:
         _log.error("Access denied")
         # This error reason is detected in calvin control and gives proper REST response
         _exit_with_error(org_cb)
         return
     if 'app_info' not in data and 'script' in data:
         deployable, issuetracker = compile_script(data['script'], appname)
     elif 'app_info' in data:
         deployable = data['app_info']
         issuetracker = IssueTracker()
     else:
         _log.error("Neither app_info or script supplied")
         # This error reason is detected in calvin control and gives proper REST response
         _exit_with_error(org_cb)
         return
     org_cb(deployable, issuetracker, security=security)
Exemplo n.º 7
0
def visualize_component(source_text, name):
    # STUB
    from calvin.utilities.issuetracker import IssueTracker
    it = IssueTracker()
    it.add_error('Visualizing components not yet implemented.')
    return "digraph structs {ERROR}", it
Exemplo n.º 8
0
 def _exit_with_error(callback):
     """Helper method to generate a proper error"""
     it = IssueTracker()
     it.add_error("UNAUTHORIZED", info={'status': 401})
     callback({}, it)
     return
Exemplo n.º 9
0
def compile_script_check_security(data,
                                  filename,
                                  cb,
                                  security=None,
                                  content=None,
                                  verify=True,
                                  node=None,
                                  signature=None):
    """
    Compile a script and return a tuple (deployable, errors, warnings).

    'credentials' are optional security credentials(?)
    'verify' is deprecated and will be removed
    'node' is the runtime performing security check(?)
    'cb' is a CalvinCB callback

    N.B. If callback 'cb' is given, this method calls cb(deployable, errors, warnings) and returns None
    N.B. If callback 'cb' is given, and method runs to completion, cb is called with additional parameter 'security' (?)
    """
    def _exit_with_error(callback):
        """Helper method to generate a proper error"""
        it = IssueTracker()
        it.add_error("UNAUTHORIZED", info={'status': 401})
        callback({}, it)
        return

    def _handle_policy_decision(data,
                                appname,
                                verify,
                                access_decision,
                                org_cb,
                                security=None):
        if not access_decision:
            _log.error("Access denied")
            # This error reason is detected in calvin control and gives proper REST response
            _exit_with_error(org_cb)
            return
        if 'app_info' not in data and 'script' in data:
            deployable, issuetracker = compile_script(data['script'], appname)
        elif 'app_info' in data:
            deployable = data['app_info']
            issuetracker = IssueTracker()
        else:
            _log.error("Neither app_info or script supplied")
            # This error reason is detected in calvin control and gives proper REST response
            _exit_with_error(org_cb)
            return
        org_cb(deployable, issuetracker, security=security)

    #
    # Actual code for compile_script
    #
    appname = appname_from_filename(filename)
    # FIXME: if node is None we bypass security even if enabled. Is that the intention?
    if node is not None and security_enabled():
        # FIXME: If cb is None, we will return from this method with None instead of a tuple, failing silently
        if security:
            sec = security
        else:
            sec = Security(node)

        verified, signer = sec.verify_signature_content(content, "application")
        if not verified:
            # Verification not OK if sign or cert not OK.
            _log.error("Failed application verification")
            # This error reason is detected in calvin control and gives proper REST response
            _exit_with_error(cb)
            return
        sec.check_security_policy(CalvinCB(_handle_policy_decision,
                                           data,
                                           appname,
                                           verify,
                                           security=security,
                                           org_cb=cb),
                                  element_type="application",
                                  element_value=signer)
        return

    #
    # We get here if node is None, or security is disabled
    #
    # This used to be
    # _handle_policy_decision(data, filename, verify, access_decision=True, security=None, org_cb=cb)
    # but since _handle_policy_decision is called with access_decision=True, security=None only compile_script would be called
    if 'app_info' not in data and 'script' in data:
        deployable, issuetracker = compile_script(data['script'], appname)
    elif 'app_info' in data:
        deployable = data['app_info']
        issuetracker = IssueTracker()
    else:
        _log.error("Neither app_info or script supplied")
        # This error reason is detected in calvin control and gives proper REST response
        _exit_with_error(org_cb)
        return
    cb(deployable, issuetracker, security=None)
Exemplo n.º 10
0
def handle_deploy(self, handle, connection, match, data, hdr):
    """
    POST /deploy
    Compile and deploy a calvin script to this calvin node
    Apply deployment requirements to actors of an application
    and initiate migration of actors accordingly
    Body:
    {
        "name": <application name>,
        "script": <calvin script>  # alternativly "app_info"
        "app_info": <compiled script as app_info>  # alternativly "script"
        "sec_sign": {<cert hash>: <security signature of script>, ...} # optional and only with "script"
        "sec_credentials": <security credentials of user> # optional
        "deploy_info":
           {"groups": {"<group 1 name>": ["<actor instance 1 name>", ...]},  # TODO not yet implemented
            "requirements": {
                "<actor instance 1 name>": [ {"op": "<matching rule name>",
                                              "kwargs": {<rule param key>: <rule param value>, ...},
                                              "type": "+" or "-" for set intersection or set removal, respectively
                                              }, ...
                                           ],
                ...
                            }
           }
    }
    Note that either a script or app_info must be supplied. Optionally security
    verification of application script can be made. Also optionally user credentials
    can be supplied, some runtimes are configured to require credentials. The
    credentials takes for example the following form:
        {"user": <username>,
         "password": <password>,
         "role": <role>,
         "group": <group>,
         ...
        }

    The matching rules are implemented as plug-ins, intended to be extended.
    The type "+" is "and"-ing rules together (actually the intersection of all
    possible nodes returned by the rules.) The type "-" is explicitly removing
    the nodes returned by this rule from the set of possible nodes. Note that
    only negative rules will result in no possible nodes, i.e. there is no
    implied "all but these."

    A special matching rule exist, to first form a union between matching
    rules, i.e. alternative matches. This is useful for e.g. alternative
    namings, ownerships or specifying either of two specific nodes.
        {"op": "union_group",
         "requirements": [list as above of matching rules but without type key]
         "type": "+"
        }
    Other matching rules available is current_node, all_nodes and
    node_attr_match which takes an index param which is attribute formatted,
    e.g.
        {"op": "node_attr_match",
         "kwargs": {"index": ["node_name", {"organization": "org.testexample", "name": "testNode1"}]}
         "type": "+"
        }
    Response status code: OK, CREATED, BAD_REQUEST, UNAUTHORIZED or INTERNAL_ERROR
    Response: {"application_id": <application-id>,
               "actor_map": {<actor name with namespace>: <actor id>, ...}
               "placement": {<actor_id>: <node_id>, ...},
               "requirements_fulfilled": True/False}
    Failure response: {'errors': <compilation errors>,
                       'warnings': <compilation warnings>,
                       'exception': <exception string>}
    """
    try:
        _log.analyze(self.node.id, "+", data)
        if 'app_info' not in data:
            kwargs = {}
            credentials = ""
            # Supply security verification data when available
            content = None
            if "sec_credentials" in data:
                credentials = data['sec_credentials']
                content = {}
                if not "sec_sign" in data:
                    data['sec_sign'] = {}
                content = {
                    'file': data["script"],
                    'sign': {
                        h: s.decode('hex_codec')
                        for h, s in data['sec_sign'].iteritems()
                    }
                }
            compiler.compile_script_check_security(
                data["script"],
                filename=data["name"],
                security=self.security,
                content=content,
                node=self.node,
                verify=(data["check"] if "check" in data else True),
                cb=CalvinCB(self.handle_deploy_cont,
                            handle=handle,
                            connection=connection,
                            data=data),
                **kwargs)
        else:
            # Supplying app_info is for backward compatibility hence abort if node configured security
            # Main user is csruntime when deploying script at the same time and some tests used
            # via calvin.Tools.deployer (the Deployer below is the new in appmanager)
            # TODO rewrite these users to send the uncompiled script as cscontrol does.
            if security_enabled():
                _log.error(
                    "Can't combine compiled script with runtime having security"
                )
                self.send_response(handle,
                                   connection,
                                   None,
                                   status=calvinresponse.UNAUTHORIZED)
                return
            app_info = data['app_info']
            issuetracker = IssueTracker()
            self.handle_deploy_cont(app_info, issuetracker, handle, connection,
                                    data)
    except Exception as e:
        _log.exception("Deployer failed, e={}".format(e))
        self.send_response(handle,
                           connection,
                           json.dumps({'exception': str(e)}),
                           status=calvinresponse.INTERNAL_ERROR)