Example #1
0
    def get_agent_log(self, kwargs):
        """Return logfile"""
        node_ids = [ str(node.id) for node in self.nodes ]
        exp_params = [('agentId', is_in_list(node_ids)),
                      ('filename', is_string, None)]
        try:
            agent_id, filename = check_arguments(exp_params, kwargs)

            # Get the node that has the specified agent_id
            node = [ node for node in self.nodes if node.id == agent_id ][0]

            # If a filename was specified...
            if filename:
                # Get the logs for the node's role
                logs = self.get_role_logs(node.role)

                # Check that the filename is valid for that role
                filenames = map(lambda log: log['filename'], logs)
                exp_params = [('filename', is_in_list(filenames))]
                check_arguments(exp_params, dict(filename=filename))

                # Replace the filename with its corresponding path in the agent
                filename = [ log['path'] for log in logs
                                         if log['filename'] == filename ][0]

            res = self.fetch_agent_log(node.ip, self.AGENT_PORT, filename)
            return HttpJsonResponse(res)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)
Example #2
0
    def list_volumes(self, kwargs):
        exp_params = [('service_id', is_in_list(self.httpsserver.instances.keys()), 0)]
        try:
            service_id = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        try:
            self.check_state([self.S_RUNNING, self.S_ADAPTING])
        except:
            return HttpJsonResponse({ 'volumes': [] })

        vols = copy.copy(self.volumes)
        rep_vols = []

        for vol_name in vols:
            vol = vols[vol_name]
            vol['service_id'], vol['service_name'] = self.get_service_id_by_vm_id(vol['vm_id'])

            if service_id != 0:
                if vol['service_id'] == service_id:
                    rep_vols.append(vol)
            else:
                rep_vols.append(vol)

        return HttpJsonResponse({ 'volumes': rep_vols })
Example #3
0
    def execute_script(self, kwargs):
        valid_commands = [ 'run', 'interrupt', 'cleanup' ]
        exp_params = [('command', is_in_list(valid_commands)),
                      ('parameters', is_string, '')]
        try:
            command, parameters = check_arguments(exp_params, kwargs)
            self.check_state([self.S_RUNNING])
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        self.logger.info("Received request for executing the '%s' command "
                "with parameters '%s'" % (command, parameters))

        # if command is 'interrupt' and no scripts are running, return an error
        if command == 'interrupt' and not self._are_scripts_running():
            self.logger.info("No scripts are currently running inside agents")
            return HttpErrorResponse(self.NO_SCRIPTS_ARE_RUNNING_MSG)

        # for the other commands, if scripts are already running, return an error
        elif command != 'interrupt' and self._are_scripts_running():
            self.logger.info("Scripts are already running inside at least "
                    "one agent")
            return HttpErrorResponse(self.SCRIPTS_ARE_RUNNING_MSG)

        Thread(target=self._do_execute_script, args=[command,
                                                        self.nodes,
                                                        parameters]).start()

        return HttpJsonResponse({ 'state': self.state_get() })
Example #4
0
    def updateTomcatCode(self, kwargs):
        valid_filetypes = [ 'zip', 'tar', 'git' ]
        exp_params = [('filetype', is_in_list(valid_filetypes)),
                      ('codeVersionId', is_string),
                      ('file', is_uploaded_file, None),
                      ('revision', is_string, '')]
        try:
            filetype, codeVersionId, file, revision = check_arguments(exp_params, kwargs)
            if filetype != 'git' and not file:
                raise Exception("The '%s' filetype requires an uploaded file" % filetype)
            elif filetype == 'git' and not revision:
                raise Exception("The 'git' filetype requires the 'revision' parameter")
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        if filetype == 'zip':
            source = zipfile.ZipFile(file.file, 'r')
        elif filetype == 'tar':
            source = tarfile.open(fileobj=file.file)
        elif filetype == 'git':
            source = git.DEFAULT_CODE_REPO

        target_dir = join(self.VAR_CACHE, 'tomcat_instance', 'webapps', codeVersionId)
        if exists(target_dir):
            rmtree(target_dir)

        if filetype == 'git':
            subdir = str(self.SERVICE_ID)
            self.logger.debug("git_enable_revision('%s', '%s', '%s', '%s')" %
                    (target_dir, source, revision, subdir))
            git.git_enable_revision(target_dir, source, revision, subdir)
        else:
            source.extractall(target_dir)

        return HttpJsonResponse()
Example #5
0
    def update_php_configuration(self, kwargs):
        config = self._configuration_get()
        exp_params = [('codeVersionId', is_in_list(config.codeVersions), None),
                      ('phpconf', is_dict, {})]
        try:
            codeVersionId, phpconf = check_arguments(exp_params, kwargs)
            self.check_state([self.S_INIT, self.S_STOPPED, self.S_RUNNING])
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        if codeVersionId is None and not phpconf:
            return HttpErrorResponse(ManagerException(ManagerException.E_ARGS_MISSING,
                    'at least one of "codeVersionId" or "phpconf"').message)

        if phpconf:
            for key in phpconf.keys():
                if key not in config.backend_config.php_conf.defaults:
                    return HttpErrorResponse(ManagerException(ManagerException.E_ARGS_UNEXPECTED, 'phpconf attribute "%s"' % (str(key))).message)
                if not re.match(config.backend_config.php_conf.format[key], phpconf[key]):
                    return HttpErrorResponse(ManagerException(ManagerException.E_ARGS_INVALID).message)

        state = self.state_get()
        if state == self.S_INIT or state == self.S_STOPPED:
            if codeVersionId:
                config.currentCodeVersion = codeVersionId
            for key in phpconf:
                config.backend_config.php_conf.conf[key] = phpconf[key]
            self._configuration_set(config)
        elif state == self.S_RUNNING:
            self.state_set(self.S_ADAPTING, msg='Updating configuration')
            Thread(target=self.do_update_configuration, args=[config, codeVersionId, phpconf]).start()

        return HttpJsonResponse()
Example #6
0
    def get_node_info(self, kwargs):
        """Return information about the node identified by the given
        kwargs['serviceNodeId']"""

        node_ids = [ str(node.id) for node in self.nodes ]
        exp_params = [('serviceNodeId', is_in_list(node_ids))]
        try:
            serviceNodeId = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        serviceNode = None
        for node in self.nodes:
            if serviceNodeId == node.id:
                serviceNode = node
                break

        return HttpJsonResponse({
            'serviceNode': {
                'id': serviceNode.id,
                'ip': serviceNode.ip,
                'vmid': serviceNode.vmid,
                'cloud': serviceNode.cloud_name,
                'is_master': self.__is_master(serviceNode),
                'role': serviceNode.role,
                'logs': self.get_role_logs(serviceNode.role)

            }
        })
Example #7
0
    def delete_code_version(self, kwargs):
        config = self._configuration_get()
        exp_params = [('codeVersionId', is_in_list(config.codeVersions))]
        try:
            codeVersionId = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        if codeVersionId == config.currentCodeVersion:
            ex = ManagerException(ManagerException.E_ARGS_INVALID,
                                  detail='Cannot remove the active code version')
            return HttpErrorResponse("%s" % ex)

        if not config.codeVersions[codeVersionId].type == 'git':
            filename = os.path.abspath(os.path.join(self.code_repo, codeVersionId))
            if not filename.startswith(self.code_repo + '/') or not os.path.exists(filename):
                ex = ManagerException(ManagerException.E_ARGS_INVALID,
                                      detail='Invalid codeVersionId')
                return HttpErrorResponse("%s" % ex)

            os.remove(filename)

        config.codeVersions.pop(codeVersionId)
        self._configuration_set(config)

        return HttpJsonResponse()
Example #8
0
    def remove_service(self, kwargs):
        exp_params = [('service_id', is_in_list(self.httpsserver.instances.keys()))]
        try:
            service_id = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        self.state_set(self.S_ADAPTING)
        Thread(target=self._do_stop_service, args=[service_id, True]).start()
        return HttpJsonResponse()
Example #9
0
    def stop_service(self, kwargs):
        exp_params = [('service_id', is_in_list(self.httpsserver.instances.keys()))]
        try:
            service_id = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        service_manager = self.httpsserver.instances[service_id]
        service_manager.state_set(self.S_EPILOGUE)
        Thread(target=self._do_stop_service, args=[service_id, False]).start()
        return HttpJsonResponse({ 'state': service_manager.state_get() })
Example #10
0
    def get_startup_script(self, kwargs):
        """Return contents of the currently defined startup script, if any"""
        exp_params = [('sid', is_in_list(self.httpsserver.instances.keys()))]
        try:
            service_id = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        basedir = self.config_parser.get('manager', 'CONPAAS_HOME')
        fullpath = os.path.join(basedir, str(service_id), 'startup.sh')

        try:
            return HttpJsonResponse(file_get_contents(fullpath))
        except IOError:
            return HttpErrorResponse('No startup script')
Example #11
0
    def update_code(self, kwargs):
        valid_filetypes = [ 'zip', 'tar', 'git' ]
        exp_params = [('filetype', is_in_list(valid_filetypes)),
                      ('codeVersionId', is_string),
                      ('file', is_uploaded_file, None),
                      ('revision', is_string, '')]
        try:
            filetype, codeVersionId, file, revision = check_arguments(exp_params, kwargs)
            if filetype != 'git' and not file:
                raise Exception("The '%s' filetype requires an uploaded file" % filetype)
            elif filetype == 'git' and not revision:
                raise Exception("The 'git' filetype requires the 'revision' parameter")
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        self.logger.info("Updating code to version '%s'" % codeVersionId)

        if filetype == 'zip':
            source = zipfile.ZipFile(file.file, 'r')
        elif filetype == 'tar':
            source = tarfile.open(fileobj=file.file)
        elif filetype == 'git':
            source = git.DEFAULT_CODE_REPO

        # kill all scripts that may still be running
        if self.processes:
            self._kill_all_processes()
            self.processes = {}

        target_dir = self.CODE_DIR

        if exists(target_dir):
            rmtree(target_dir)

        if filetype == 'git':
            subdir = str(self.SERVICE_ID)
            self.logger.debug("git_enable_revision('%s', '%s', '%s', '%s')" %
                    (target_dir, source, revision, subdir))
            git.git_enable_revision(target_dir, source, revision, subdir)
        else:
            source.extractall(target_dir)

        self.logger.info("Code updated, executing the 'init' command")

        # every time a new code tarball is activated, execute the init.sh script
        self._execute_script('init')

        return HttpJsonResponse()
Example #12
0
    def add_service(self, kwargs):
        """Expose methods relative to a specific service manager"""

        exp_params = [('service_type', is_in_list(manager_services.keys()))]
        try:
            service_type = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        self.kwargs.update(kwargs)
        services = manager_services

        try:
            module = __import__(services[service_type]['module'], globals(), locals(), ['*'])
        except ImportError:
            self.state_set(self.S_ERROR)
            raise Exception('Could not import module containing service class "%(module)s"' %
                services[service_type])

        # Get the appropriate class for this service
        service_class = services[service_type]['class']
        try:
            instance_class = getattr(module, service_class)
        except AttributeError:
            self.state_set(self.S_ERROR)
            raise Exception('Could not get service class %s from module %s' % (service_class, module))

        self.state_set(self.S_ADAPTING)

        #probably lock it
        self.service_id = self.service_id + 1

        service_config_parser = self.__copy_config_parser(self.config_parser)
        self._add_manager_configuration(service_config_parser, str(self.service_id), service_type)
        # self._run_manager_start_script(service_config_parser, service_type)

        #Create an instance of the service class
        service_insance = instance_class(service_config_parser, **self.kwargs)

        self.httpsserver.instances[self.service_id] = service_insance
        service_manager_exposed_functions = service_insance.get_exposed_methods()

        for http_method in service_manager_exposed_functions:
           for func_name in service_manager_exposed_functions[http_method]:
               self.httpsserver._register_method(http_method, self.service_id, func_name, service_manager_exposed_functions[http_method][func_name])

        self.state_set(self.S_RUNNING)
        return HttpJsonResponse({ 'service_id': self.service_id })
Example #13
0
    def remove_nodes(self, kwargs):
        exp_params = [('service_id', is_in_list(self.httpsserver.instances.keys())),
                      ('nodes', is_dict)]
        try:
            service_id, node_roles = check_arguments(exp_params, kwargs)

            service_manager = self.httpsserver.instances[service_id]
            service_manager.check_node_roles(node_roles)
            service_manager.check_state([self.S_RUNNING])
            service_manager.check_remove_nodes(node_roles)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        service_manager.state_set(self.S_ADAPTING)
        Thread(target=self._do_remove_nodes, args=[service_id, node_roles]).start()
        return HttpJsonResponse({ 'state': service_manager.state_get() })
Example #14
0
    def start_service(self, kwargs):
        exp_params = [('service_id', is_in_list(self.httpsserver.instances.keys())),
                      ('cloud', is_string)]
        try:
            service_id, cloud = check_arguments(exp_params, kwargs)
            self.check_credits()

            service_manager = self.httpsserver.instances[service_id]
            service_manager.check_state([self.S_INIT, self.S_STOPPED])
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        service_manager.logger.info('Manager starting up')
        service_manager.state_set(self.S_PROLOGUE)

        Thread(target=self._do_start_service, args=[service_id, cloud]).start()

        return HttpJsonResponse({ 'state': service_manager.state_get() })
Example #15
0
    def execute_script(self, kwargs):
        valid_commands = [ 'notify', 'run', 'interrupt', 'cleanup' ]
        exp_params = [('command', is_in_list(valid_commands)),
                      ('parameters', is_string, ''),
                      ('agents_info', is_string)]
        try:
            command, parameters, agents_info = check_arguments(exp_params, kwargs)
            agents_info = simplejson.loads(agents_info)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        if command == 'notify':
            self.logger.info("Executing the '%s' command" % command)
        else:
            self.logger.info("Executing the '%s' command with parameters '%s'"
                    % (command, parameters))

        target_dir = self.VAR_CACHE
        with open(join(target_dir, 'agents.json'), 'w') as outfile:
            simplejson.dump(agents_info, outfile)

        if command == 'interrupt':
            # if no script is running, do nothing
            if not self._are_scripts_running():
                self.logger.info("No scripts are currently running")

            # if interrupt is already running, kill all processes
            elif self._get_script_status('interrupt') == 'RUNNING':
                self.logger.info("Script 'interrupt.sh' is already running")
                self._kill_all_processes()

            # execute the script and afterwards kill all processes
            else:
                Thread(target=self._do_interrupt, args=[parameters]).start()
        else:
            # if scripts are already running, do nothing
            if self._are_scripts_running():
                self.logger.info("Scripts are already running")

            # execute the script
            else:
                self._execute_script(command, parameters)

        return HttpJsonResponse()
Example #16
0
    def update_java_configuration(self, kwargs):
        config = self._configuration_get()
        exp_params = [('codeVersionId', is_in_list(config.codeVersions))]
        try:
            codeVersionId = check_arguments(exp_params, kwargs)
            self.check_state([self.S_INIT, self.S_STOPPED, self.S_RUNNING])
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        state = self.state_get()
        if state == self.S_INIT or state == self.S_STOPPED:
            if codeVersionId:
                config.currentCodeVersion = codeVersionId
            self._configuration_set(config)
        elif state == self.S_RUNNING:
            self.state_set(self.S_ADAPTING, msg='Updating configuration')
            Thread(target=self.do_update_configuration, args=[config, codeVersionId]).start()

        return HttpJsonResponse()
Example #17
0
    def delete_volume(self, kwargs):
        exp_params = [('volumeName', is_in_list(self.volumes.keys()))]
        try:
            vol_name = check_arguments(exp_params, kwargs)
            self.check_volume_name(vol_name)

            volume = self.volumes[vol_name]
            node = [ node for node in self.nodes if node.id == volume['vm_id'] ][0]
            service_id, _ = self.get_service_id_by_vm_id(node.id)

            service_manager = self.httpsserver.instances[service_id]
            service_manager.check_state([self.S_RUNNING])
            service_manager.check_delete_volume(node, volume)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        service_manager.state_set(self.S_ADAPTING)
        Thread(target=self._do_delete_volume, args=[volume, node, service_manager]).start()

        return HttpJsonResponse({ 'service_id': service_id })
Example #18
0
    def download_code_version(self, kwargs):
        config = self._configuration_get()
        exp_params = [('codeVersionId',
                       is_in_list(config.codeVersions),
                       config.currentCodeVersion)]
        try:
            codeVersionId = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        if config.codeVersions[codeVersionId].type == 'git':
            return HttpErrorResponse(
                'ERROR: To download this code, please clone the git repository');

        filename = os.path.abspath(os.path.join(self.code_repo, codeVersionId))
        if not filename.startswith(self.code_repo + '/') or not os.path.exists(filename):
            ex = ManagerException(ManagerException.E_ARGS_INVALID,
                                  detail='Invalid codeVersionId')
            return HttpErrorResponse("%s" % ex)
        return HttpFileDownloadResponse(config.codeVersions[codeVersionId].filename,
                filename)
Example #19
0
    def create_volume(self, kwargs):
        node_ids = [ str(node.id) for node in self.nodes ]
        exp_params = [('volumeName', is_not_in_list(self.volumes.keys())),
                      ('volumeSize', is_pos_int),
                      ('agentId', is_in_list(node_ids))]
        try:
            vol_name, vol_size, agent_id = check_arguments(exp_params, kwargs)
            self.check_volume_name(vol_name)

            service_id, _ = self.get_service_id_by_vm_id(agent_id)

            service_manager = self.httpsserver.instances[service_id]
            service_manager.check_state([self.S_RUNNING])
            service_manager.check_create_volume(vol_name, vol_size, agent_id)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        service_manager.state_set(self.S_ADAPTING)
        Thread(target=self._do_create_volume, args=[vol_name, vol_size, agent_id, service_manager]).start()

        return HttpJsonResponse({ 'service_id': service_id })
Example #20
0
    def enable_code(self, kwargs):
        config = self._configuration_get()
        exp_params = [('codeVersionId', is_in_list(config.codeVersions))]
        try:
            codeVersionId = check_arguments(exp_params, kwargs)
            self.check_state([self.S_INIT, self.S_STOPPED, self.S_RUNNING])
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        state = self.state_get()
        if state == self.S_INIT or state == self.S_STOPPED:
            config.currentCodeVersion = codeVersionId
            self._configuration_set(config)
        elif state == self.S_RUNNING:
            if self._are_scripts_running():
                self.logger.info("Code activation is disabled when scripts are "\
                        "running")
                return HttpErrorResponse(self.SCRIPTS_ARE_RUNNING_MSG);
            self.state_set(self.S_ADAPTING, msg='Updating configuration')
            Thread(target=self._do_enable_code, args=[config, codeVersionId]).start()

        return HttpJsonResponse()
Example #21
0
    def get_node_info(self, kwargs):
        """
        Gets info of a specific node.

        Parameters
        ----------
        serviceNodeId : string
            identifier of node to query

        Returns a dict with keys:
        serviceNode : dict with keys:
            id : string
                node identifier
            ip : string
                node public IP address
            vmid : string
                unique identifier of the VM inside the cloud provider
            cloud :string
                name of cloud provider
        """
        try:
            node_ids = self.config.serviceNodes.keys() + self.config.glb_service_nodes.keys()
            exp_params = [('serviceNodeId', is_in_list(node_ids))]
            serviceNodeId = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        serviceNode = self.config.getMySQLNode(serviceNodeId)
        return HttpJsonResponse({'serviceNode': {'id': serviceNode.id,
                                                 'ip': serviceNode.ip,
                                                 'vmid': serviceNode.vmid,
                                                 'cloud': serviceNode.cloud_name,
                                                 'isNode': serviceNode.isNode,
                                                 'isGlb_node': serviceNode.isGlb_node,
                                                 'role': serviceNode.role,
                                                 'logs': self.get_role_logs(serviceNode.role)
                                                 }
                                 })
Example #22
0
    def on_autoscaling(self, kwargs):
        """
        Enable auto-scaling for this PHP service.
        The auto-scaling will add or remove nodes to reach the expected response
        time in milliseconds while keeping a low credit usage.

        POST parameters
        ---------------
        cool_down : int
            time in minutes between adaptation points
        reponse_time : int
            service level objective (SLO) for the web and backend response time in milliseconds
        strategy : string
            one of "low", "medium_down", "medium_up", "medium", "high"
        """
        self.logger.info('on_autoscaling entering')
        try:
            valid_strategy = [ 'low', 'medium_down', 'medium_up', 'medium', 'high' ]
            exp_params = [('cool_down', is_pos_nul_int),
                          ('reponse_time', is_pos_nul_int),
                          ('strategy', is_in_list(valid_strategy))]
            cool_down, reponse_time, strategy = check_arguments(exp_params, kwargs)

            if not self.scaler:
                raise Exception(
                    'Provisioning Manager has not been initialized: %s' %
                    provision_mng_error)

            self.autoscaling_threads = ThreadPool(processes=1)
            self.autoscaling_threads.apply_async(self.scaler.do_provisioning, (response_time, cool_down, strategy))
            config = self._configuration_get()
            config.autoscaling = True
            self._configuration_set(config)

            return HttpJsonResponse({'autoscaling': config.autoscaling})
        except Exception as ex:
            self.logger.critical('Error when trying to stop the autoscaling mechanism: %s' % ex)
            return HttpErrorResponse("%s" % ex)
Example #23
0
    def get_node_info(self, kwargs):
        node_ids = [ str(node.id) for node in self.nodes ]
        exp_params = [('serviceNodeId', is_in_list(node_ids))]
        try:
            serviceNodeId = check_arguments(exp_params, kwargs)
        except Exception as ex:
            return HttpErrorResponse("%s" % ex)

        for node in self.nodes:
            if serviceNodeId == node.id:
                serviceNode = node
                break

        return HttpJsonResponse({
            'serviceNode': {
                            'id': serviceNode.id,
                            'ip': serviceNode.ip,
                            'vmid': serviceNode.vmid,
                            'cloud': serviceNode.cloud_name,
                            'role': serviceNode.role,
                            'logs': self.get_role_logs(serviceNode.role)
                            }
            })
Example #24
0
    def test_check_arguments(self):
        ## No parameters
        exp_params = []
        args = {}
        parsed_args = check_arguments(exp_params, args)
        self.assertEqual(parsed_args, [])

        # One single integer parameter
        exp_params = [('name1', is_int)]
        args = {'name1': 3}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 3)

        # Missing one parameter
        exp_params = [('name1', is_int)]
        args = {}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # Wrong type
        exp_params = [('name1', is_int)]
        args = {'name1': 'value'}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # One single string parameter
        exp_params = [('name1', is_string)]
        args = {'name1': 'value'}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 'value')

        exp_params = [('name1', is_string)]
        args = {'name1': u'value'}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 'value')

        # An integer when a string was expected
        exp_params = [('name1', is_string)]
        args = {'name1': 3}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # A positive integer
        exp_params = [('name1', is_pos_int)]
        args = {'name1': 3}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 3)

        # A positive integer
        exp_params = [('name1', is_pos_int)]
        args = {'name1': -3}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # A positive integer
        exp_params = [('name1', is_pos_int)]
        args = {'name1': 0}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # A positive or null integer
        exp_params = [('name1', is_pos_nul_int)]
        args = {'name1': 3}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 3)

        # A positive or null integer
        exp_params = [('name1', is_pos_nul_int)]
        args = {'name1': -3}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # A positive or null integer
        exp_params = [('name1', is_pos_nul_int)]
        args = {'name1': 0}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 0)

        # Extra unknown parameter
        exp_params = [('name1', is_int)]
        args = {'name1': 3, 'name2': 'value'}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # Default value
        exp_params = [('name1', is_int, 5)]
        args = {}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 5)

        # Mix of mandatory args and optional ones
        exp_params = [('name1', is_int, 5), ('name2', is_int)]
        args = {'name2': 7}
        name1, name2 = check_arguments(exp_params, args)
        self.assertEqual(name1, 5)
        self.assertEqual(name2, 7)

        # Check uploaded file type
        exp_params = [('uploaded_file', is_uploaded_file)]
        filename = 'myfile.txt'
        filecontent = 'file'
        args = {'uploaded_file': FileUploadField(filename, filecontent)}
        uploaded_file = check_arguments(exp_params, args)
        self.assertEqual(uploaded_file.filename, filename)
        self.assertEqual(uploaded_file.file, filecontent)

        # Check in_list constraint
        exp_params = [('name1', is_in_list([3, 5, 6]))]
        args = {'name1': 6}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, 6)

        # Check not in_list constraint
        exp_params = [('name1', is_in_list([3, 5, 6]))]
        args = {'name1': 1}
        self.assertRaises(Exception, check_arguments, exp_params, args)

        # Check is_list constraint
        exp_params = [('name1', is_list)]
        mylist = [3, 'a']
        args = {'name1': mylist}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mylist)

        # Check is_dict constraint
        exp_params = [('name1', is_dict)]
        mydict = {'key': 3}
        args = {'name1': mydict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mydict)

        # Check is_dict2 constraint
        exp_params = [('name1', is_dict2(["key"]))]
        mydict = {'key': 3}
        args = {'name1': mydict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mydict)

        # Check is_dict2 constraint
        exp_params = [('name1', is_dict2(["key"], ["optkey"]))]
        mydict = {'key': 3}
        args = {'name1': mydict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mydict)

        # Check is_dict2 constraint: missing mandatory
        exp_params = [('name1', is_dict2(["key"], ["optkey"]))]
        mydict = {'optkey': 3}
        args = {'name1': mydict}
        self.assertRaisesRegexp(Exception, ".*expecting key.*", check_arguments, exp_params, args)

        # Check is_dict2 constraint: extra unknown key
        exp_params = [('name1', is_dict2(["key"], ["optkey"]))]
        mydict = {'key': 42, 'optkey': 3, 'newkey': 'great value'}
        args = {'name1': mydict}
        self.assertRaisesRegexp(Exception, ".*Unexpected key.*", check_arguments, exp_params, args)

        # Check is_list_dict constraint
        exp_params = [('name1', is_list_dict)]
        mylistdict = [{'key': 3}]
        args = {'name1': mylistdict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mylistdict)

        # Check is_list_dict2 constraint
        exp_params = [('name1', is_list_dict2(['key']))]
        mylistdict = [{'key': 3}, {'key': 56}]
        args = {'name1': mylistdict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mylistdict)

        # Check is_list_dict2 constraint
        exp_params = [('name1', is_list_dict2(['key']))]
        mylistdict = [{'key': 3}, {'key': 56, 'nokey': 42}]
        args = {'name1': mylistdict}
        self.assertRaisesRegexp(Exception, ".*Unexpected key.*", check_arguments, exp_params, args)

        # Try with a JSON conversion first
        # Check is_list constraint
        exp_params = [('name1', is_list)]
        mylist = unicode('[3, "a"]')
        mylist = json.loads(mylist)
        args = {'name1': mylist}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mylist)

        # Check is_dict constraint
        exp_params = [('name1', is_dict)]
        mydict = unicode('{"key": 3}')
        mydict = json.loads(mydict)
        args = {'name1': mydict}
        name1 = check_arguments(exp_params, args)
        self.assertEqual(name1, mydict)