Exemple #1
0
def _parse_params(params, params_name='<params>'):
    """Parse <params> into a dictionary

    Convert <params> list into a dictionary. Each <params> list element has the format: key=value
    where both key, value, and the tuple may be surrounded by "" to include spaces. These "" are
    removed.

    Repeated keys are not allowed so if one is repeated, an error will be launched.

    :param params List of strings with the optional <params> of the CLI
    :return Dictionary with the params list formatted
    """
    params_dict = {}
    if params:
        # param should have the format: key=value. However, " might be used for the key, value, or the pair (in order
        # to support spaces)
        for param in params:
            # Only one split (2 list elements)
            tokens = param.split('=', 1)
            if len(tokens) != 2:
                raise SdAdminLibraryException('{0} should match the format <key>=<value>'.format(params_name))
            else:
                key_dict = tokens[0].strip('"')  # remove the first "
                if key_dict in params_dict:
                    raise SdAdminLibraryException('{0} <key> can not be repeated'.format(key_dict))
                params_dict[key_dict] = tokens[1].strip('"')
    return params_dict
Exemple #2
0
def _get_config(path):
    """Parse a configuration file

    Parse configuration file, available at path, to extract relevant information to connect
    to the remote service directory

    :param path Path to the configuration file
    return Dictionary with the configuration parameters parsed from the file
    """

    try:
        # Open the config file and prepare a pseudo section to make it parsable with ConfigParser
        f = open(path, "r")
        pseudo_config = StringIO(u'[SD]\n' + f.read())
        parser = ConfigParser()
        parser.readfp(pseudo_config)

        # Prepare a dictionary with the required config parameters
        config = dict()
        for param_key in ('url', 'username', 'password', 'timeout'):
            try:
                config[param_key] = parser.get('SD', param_key)
            except NoOptionError:
                raise SdAdminLibraryException('Configuration parameter \"' + param_key + '\" is required')

        # Required config can not be empty strings
        if any(map(lambda x: x.strip() == '', config.itervalues())):
            raise SdAdminLibraryException('url, username and password can not be empty')
        # timeout must be integer
        try:
            config['timeout'] = int(config['timeout'])
        except ValueError:
            raise SdAdminLibraryException('timeout must be intenger')

        # Add optional config parameters
        try:
            config['verify'] = parser.getboolean('SD', 'verify')
        except ValueError:
            raise SdAdminLibraryException('The configuration parameter \"verify\" must be boolean')
        except NoOptionError:
            pass
        try:
            config['key'] = parser.get('SD', 'key')
        except NoOptionError:
            pass
        try:
            config['cert'] = parser.get('SD', 'cert')
        except NoOptionError:
            pass

        return config
    except IOError:
        raise SdAdminLibraryException('Error reading file \"' + path + '\"')
Exemple #3
0
def _get_client(arguments):
    """Get the HTTP client to the service directory

    Retrieve the default configuration for the service directory CLI and override with the command line
    options

    :param arguments CLI arguments formatted with docopt
    :return Client object to access the service directory
    """

    # Check if the user wants to override the configuration file
    config_path = arguments.get('--conf')
    if config_path == None:
        # Get the path to the default configuration
        config_path = DEFAULT_CONFIG_PATH
    # Parse the configuration file
    client_config = _get_config(config_path)

    # Override the default configuration with the options (if any) set in the command line
    for config_key in client_config.iterkeys():
        option = '--' + config_key
        if arguments.get(option) is not None:
            client_config[config_key] = arguments.get(option)

    # Check noverify option (it is not covered by the previous loop because it is set to "verify" parameter)
    if arguments.get('--noverify'):
        client_config['verify'] = False

    # Prepare tuple for client certificate (cert and key) if 2-way ssl required
    try:
        cert = client_config['cert']
        key = client_config['key']
        if not cert or not key:
            raise SdAdminLibraryException('To enable 2-way SSL, both certificate and private key must be set')
        # Verify that both files exist
        if not isfile(cert):
            raise SdAdminLibraryException('Invalid certificate path \"' + cert + '\"')
        if not isfile(key):
            raise SdAdminLibraryException('Invalid private key path \"' + key + '\"')
        # Save the certificate as a tuple (valid for "requests" library)
        del client_config['key']  # This param is not needed anymore
        client_config['cert'] = (cert, key)
    except KeyError:
        pass

    if arguments.get('--debug'):
        client_config['debug'] = True
        print('')
        print('[CLI Configuration]:')
        print(_format(client_config))

    return Client(**client_config)
Exemple #4
0
def _parse_json_file(path):
    """Parse a JSON file into a dict

    Open JSON file, available at path, and parse its content into a dictionary. The file must exist, with JSON content,
    and read access by the cli user.

    :param path Path to the JSON file
    :return Dictionary after parsing the JSON content of the file
    """
    if not exists(path):
        raise SdAdminLibraryException('Not existing file {0}'.format(path))
    with open(path, "r") as f:
        try:
            json_content = json.loads(f.read())
            if not isinstance(json_content, dict):
                raise SdAdminLibraryException('Json file should be a valid object (not array or null)')
            return json_content
        except ValueError as e:
            raise SdAdminLibraryException('Error parsing JSON file: {0}'.format(str(e)))
Exemple #5
0
def _validate_params(params, invalid_keys, allowed_keys=None):
    """Check params dictionary does not contain any invalid key

    Validate params dict by checking that no invalid key (from invalid_keys list) is included in params dict keys

    :param params Params dictionary
    :param invalid_keys List of keys not permitted in params dictionary
    :param allowed_keys
    """

    for key in invalid_keys:
        if key in params.keys():
            raise SdAdminLibraryException('\"{0}\" cannot be part of <params>'.format(key))

    if allowed_keys:
        invalid_keys = filter(lambda x: x not in allowed_keys, params)
        for key in params.keys():
            if key not in allowed_keys:
                raise SdAdminLibraryException('\"{0}\" cannot be part of <params>'.format(key))
Exemple #6
0
    def parse_json_from_sd(self, response):
        """
        Check that response can be safely converted to json according to the expected
        from SD.
        If no json object can be obtained an exception is raised
        """
        if response.status_code == codes.no_content:  # @UndefinedVariable
            return None
        try:
            resp_json = response.json()  # SD always respond with json
        except ValueError:
            raise SdAdminLibraryException()  # default error message is ok

        if not isinstance(resp_json, (dict, list)):
            raise SdAdminLibraryException()  # default error message is ok

        if isinstance(resp_json, dict):
            if len(resp_json) < 1:
                raise SdAdminLibraryException()  # default error message is ok

        return resp_json
Exemple #7
0
    def _request(self, method, path, data=None, headers=None, **kwargs):
        """Generic HTTP request to the service directory

        Only content-type "application/json" is supported in both request and response

        :param method HTTP method: GET, PUT, POST or DELETE (Mandatory)
        :param path Relative path to resource (Mandatory)
        :param **kwargs Extended parameters to set up the HTTP request
        :return Response object from requests library
        """

        # Get headers (if defined) and add the Accept header to application/json
        if not headers:
            headers = {}
        headers['Accept'] = 'application/json'

        # If data is defined and is a dictionary, then serialize it into a JSON string
        # Also add content-type header as application/json
        if (data):
            if isinstance(data, dict):
                data = json.dumps(data)
            else:
                data = str(data)
            headers['Content-Type'] = 'application/json'

        # Send the HTTP request to the service directory and get the response
        try:
            response = request(
                method,
                self._prepare_url(path),
                auth=self.auth,
                data=data,
                headers=headers,
                verify=self.verify,
                timeout=self.timeout,
                cert=self.cert,
                **kwargs)
        except SSLError as e:
            if self.debug:
                print(e)
            raise SdAdminLibraryException(
                    'SSL error when connecting to Service Directory. Try again later or contact support team.')
        except ConnectionError:
            raise SdAdminLibraryException(
                    'No connection to Service Directory. Try again later or contact support team.')
        except Timeout:
            raise SdAdminLibraryException(
                    'Timeout waiting for a Service Directory response. Try again later or contact support team.')

        # Check if debug is enabled to print request and response
        if self.debug:
            Client._print_debug(response)

        # Do a minimun response checking from SD, e.g valid dict or valid list but not other
        # only empty list is allowed
        # If the response status code is not successful, prepare the appropriate exception
        json_response = self.parse_json_from_sd(response)

        if not response.ok:
            raise ServerException(json_response)
        return json_response
Exemple #8
0
def _validate_non_empty(name, value):
    if value.strip() == '':
        raise SdAdminLibraryException('{0} argument can not be empty'.format(name))