コード例 #1
0
    def __init__(self, component, version, **kwargs):
        """Class initialization

        Parameters
        ----------
        component : str
            the extension component
        version : str
            the extension component version
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        use_latest_metadata : bool
            use latest metadata (will be retrieved from remote CDN)

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.use_latest_metadata = kwargs.pop('use_latest_metadata', False)
        self.extension_metadata = self._load_metadata()
        self.component = self._validate_component(component)
        self.version = self._validate_component_version(
            self.component, version or self.get_latest_version())
コード例 #2
0
    def __init__(self, host, **kwargs):
        """Class initialization

        Parameters
        ----------
        host : str
            the hostname of the device
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        port : int
            the port to assign to the port attribute
        user : str
            the username for device authentication
        password : str
            the password for device authentication
        private_key_file : str
            the file containing the private key for device authentication
        set_user_password : str
            sets the user password to this value - used along with private_key_file
        token : str
            the token to assign to the token attribute
        skip_ready_check : bool
            skips the device ready check if set to true

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.host = host.split(':')[0]  # disallow providing port here
        self.port = int(kwargs.pop('port', None) or self._discover_port())
        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)
        self._private_key_file = kwargs.pop('private_key_file', None)
        self._set_user_password = kwargs.pop('set_user_password', None)
        self.token = kwargs.pop('token', None)

        self.token_details = {}

        # check device is ready
        if not kwargs.pop('skip_ready_check', False):
            self._is_ready()

        # handle multiple authentication mechanisms
        if self._user and self._password:
            self._login_using_credentials()
        elif self._user and self._private_key_file:
            self._set_password_using_key()
            self._login_using_credentials()
        elif self.token:
            pass
        else:
            raise Exception(
                'user|password, user|private_key_file or token required')
コード例 #3
0
    def test_logger_can_log():
        """Test: logger can log

        Assertions
        ----------
        - _log method should be called with 40, 'foo'
        """
        # pylint: disable=protected-access

        logger = Logger(LOGGER_NAME).get_logger()
        logger._log = Mock()
        logger.error('foo')
        logger._log.assert_called_with(40, 'foo', ())
コード例 #4
0
    def test_logger_with_custom_trace_level():
        """Test: logger can log with custom trace level

        Assertions
        ----------
        - _log method should be called with 5, 'foo'
        """
        # pylint: disable=protected-access

        logger = Logger(LOGGER_NAME, level='TRACE').get_logger()
        logger._log = Mock()
        logger.trace('foo')
        logger._log.assert_called_with(5, 'foo', ())
コード例 #5
0
ファイル: extension.py プロジェクト: jikui/f5-sdk-python
    def __init__(self, client, component, **kwargs):
        """Class initialization

        Parameters
        ----------
        client : object
            the management client object
        component : str
            the extension component
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        version : str
            a string specifying the component version to use
        use_latest_metadata : bool
            use latest metadata (will be retrieved from remote CDN)

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self._client = client
        self._metadata_client = MetadataClient(
            component,
            kwargs.pop('version', None),
            use_latest_metadata=kwargs.pop('use_latest_metadata', False)
        )
        self.component = self._metadata_client.component
        self.version = self._metadata_client.version
コード例 #6
0
    def __init__(self, client, **kwargs):
        """Class initialization

        Parameters
        ----------
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        logger_name : str
            the logger name to use in log messages
        uri : str
            the REST URI against which this client operates

        Returns
        -------
        None
        """

        self.logger = Logger(kwargs.pop('logger_name', __name__)).get_logger()

        self._client = client
        self._metadata = {'uri': kwargs.pop('uri', None)}

        self._exceptions = {'InputRequiredError': InputRequiredError}
コード例 #7
0
    def __init__(self, **kwargs):
        """Class initialization

        Parameters
        ----------
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        user : str
            the username for service authentication
        password : str
            the password for service authentication

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        # process kwargs
        self._api_endpoint = kwargs.pop('api_endpoint', None)
        if self._api_endpoint is None:
            self._api_endpoint = API_ENDPOINT

        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)
        self._subscription_id = kwargs.pop('subscription_id', None)

        self.access_token = None
        self.token_details = None

        if self._user and self._password:
            self._login_using_credentials()
        else:
            raise InputRequiredError('user|password required')
コード例 #8
0
    def __init__(self, host, **kwargs):
        """Class initialization

        Parameters
        ----------
        host : str
            the hostname of the device
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        port : int
            the port to assign to the port attribute
        user : str
            the username for device authentication
        password : str
            the password for device authentication

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.host = host.split(':')[0]
        self.port = kwargs.pop('port', 443)

        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)

        # account for multiple authentication schemes
        if self._user and self._password:
            self._login_using_credentials()
        else:
            raise Exception('user|password required')
コード例 #9
0
class ManagementClient(object):
    """A class used as a management client for BIG-IP

    Attributes
    ----------
    host : str
        the hostname of the device
    port : str
        the port of the device
    token : str
        the token of the device
    token_details : dict
        the token details of the device
    logger : object
        instantiated logger object

    Methods
    -------
    get_info()
        Refer to method documentation
    make_request()
        Refer to method documentation
    make_ssh_request()
        Refer to method documentation
    """
    def __init__(self, host, **kwargs):
        """Class initialization

        Parameters
        ----------
        host : str
            the hostname of the device
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        port : int
            the port to assign to the port attribute
        user : str
            the username for device authentication
        password : str
            the password for device authentication
        private_key_file : str
            the file containing the private key for device authentication
        set_user_password : str
            sets the user password to this value - used along with private_key_file
        token : str
            the token to assign to the token attribute
        skip_ready_check : bool
            skips the device ready check if set to true

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.host = host.split(':')[0]  # disallow providing port here
        self.port = int(kwargs.pop('port', None) or self._discover_port())
        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)
        self._private_key_file = kwargs.pop('private_key_file', None)
        self._set_user_password = kwargs.pop('set_user_password', None)
        self.token = kwargs.pop('token', None)

        self.token_details = {}

        # check device is ready
        if not kwargs.pop('skip_ready_check', False):
            self._is_ready()

        # handle multiple authentication mechanisms
        if self._user and self._password:
            self._login_using_credentials()
        elif self._user and self._private_key_file:
            self._set_password_using_key()
            self._login_using_credentials()
        elif self.token:
            pass
        else:
            raise Exception(
                'user|password, user|private_key_file or token required')

    def _test_socket(self, port):
        """Test TCP connection can be established

        Parameters
        ----------
        None

        Returns
        -------
        bool
            a boolean true/false
        """
        _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        _socket.settimeout(1)

        check = False
        try:
            _socket.connect((self.host, port))
            check = True
        except (socket.timeout, OSError) as err:
            self.logger.debug('connection timeout: %s', err)
        finally:
            _socket.close()
        return check

    def _discover_port(self):
        """Discover management port (best effort)

        Try 443 -> 8443, set port to 443 if neither responds.

        Timeout set to 1 second, if connect or connect refused assume it is the right port.

        Parameters
        ----------
        None

        Keyword Arguments
        -----------------
        None

        Returns
        -------
        int
            the discovered management port
        """

        if self._test_socket(DFL_PORT):
            return DFL_PORT
        if self._test_socket(DFL_PORT_1NIC):
            return DFL_PORT_1NIC
        return DFL_PORT

    @retry(tries=constants.RETRIES['LONG'],
           delay=constants.RETRIES['DELAY_IN_SECS'])
    def _is_ready(self):
        """Checks that the device is ready

        Notes
        -----
        Retries up to 5 minutes

        Parameters
        ----------
        None

        Returns
        -------
        bool
            boolean true if device is ready
        """

        self.logger.debug('Performing ready check using port %s' % self.port)

        if self._test_socket(self.port):
            return True

        raise DeviceReadyError('Unable to complete device ready check')

    def _make_ssh_request(self, command):
        """See public method for documentation: make_ssh_request """

        # note: command *might* contain sensitive information
        # logger should scrub those: i.e. secret foo -> secret ***
        self.logger.debug('Making SSH request: %s' % (command))

        # create client kwargs
        client_kwargs = {'username': self._user}
        if self._password:
            client_kwargs['password'] = self._password
        elif self._private_key_file:
            private_key_file = os.path.expanduser(self._private_key_file)
            client_kwargs['pkey'] = paramiko.RSAKey.from_private_key_file(
                private_key_file)
        else:
            raise Exception('password or private key file required')

        # workaround for deprecation warning described here, until fixed
        # https://github.com/paramiko/paramiko/issues/1369
        # workaround: temporarily catch warnings on client.connect
        with warnings.catch_warnings(record=True) as _:
            # create client
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
            try:
                client.connect(self.host, **client_kwargs)
            except SSH_EXCEPTIONS as _e:
                self.logger.error(_e)
                raise _e

        # collect result
        result = client.exec_command(command)

        # command output (tuple): stdin, stdout, stder
        stdout = result[1].read().decode('utf-8')
        stderr = result[2].read().decode('utf-8')
        client.close()

        if stderr:
            raise SSHCommandStdError('Error: %s' % stderr)

        return stdout.rstrip('\n\r')

    @retry(tries=constants.RETRIES['DEFAULT'],
           delay=constants.RETRIES['DELAY_IN_SECS'])
    def _set_password_using_key(self):
        """Sets password on device using user + private key

        Updates user's password using set_user_password

        Retries if unsuccessful, up to maximum allotment

        Parameters
        ----------
        None

        Returns
        -------
        None
        """

        # get password to set
        password = self._set_user_password
        if not password:
            raise Exception('set_user_password required')

        # get user shell - tmsh or bash
        tmsh = ''
        # note: if the shell is in fact bash the first command will fail, so catch
        # the exception and try with 'tmsh' explicitly added to the command
        auth_list_cmd = constants.BIGIP_CMDS['AUTH_LIST']
        try:
            user_info = self._make_ssh_request(auth_list_cmd %
                                               (tmsh, self._user))
        except SSHCommandStdError:
            user_info = self._make_ssh_request(auth_list_cmd %
                                               ('tmsh', self._user))
        if 'shell bash' in user_info:
            tmsh = 'tmsh'  # add tmsh to command

        # set password
        self._make_ssh_request(constants.BIGIP_CMDS['AUTH_MODIFY'] %
                               (tmsh, self._user, password))
        self._password = password

    @retry(exceptions=HTTPError,
           tries=constants.RETRIES['DEFAULT'],
           delay=constants.RETRIES['DELAY_IN_SECS'])
    def _get_token(self):
        """Gets authentication token

        Retries if unsuccessful, up to maximum allotment

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing authentication token, expiration date and expiration in seconds:
            {'token': 'token', 'expirationDate': '2019-01-01T01:01:01.00', 'expirationIn': 3600}
        """

        self.logger.debug('Getting authentication token')

        expiration_date = (datetime.now() + timedelta(hours=1)).isoformat()
        timeout = 3600  # set timeout to 1 hour

        uri = '/mgmt/shared/authn/login'
        body = {
            'username': self._user,
            'password': self._password,
            'loginProviderName': 'tmos'
        }

        # get token
        try:
            response = http_utils.make_request(self.host,
                                               uri,
                                               port=self.port,
                                               method='POST',
                                               body=body,
                                               basic_auth={
                                                   'user': self._user,
                                                   'password': self._password
                                               })
        except HTTPError as error:
            if constants.HTTP_STATUS_CODE['FAILED_AUTHENTICATION'] in str(
                    error):
                _exception = InvalidAuthError(error)
                _exception.__cause__ = None
                raise _exception
            raise error

        token = response['token']['token']
        # now extend token lifetime
        token_uri = '/mgmt/shared/authz/tokens/%s' % token

        http_utils.make_request(self.host,
                                token_uri,
                                port=self.port,
                                method='PATCH',
                                body={'timeout': timeout},
                                basic_auth={
                                    'user': self._user,
                                    'password': self._password
                                })
        return {
            'token': token,
            'expirationDate': expiration_date,
            'expirationIn': timeout
        }

    def _login_using_credentials(self):
        """Logs in to device using user + password

        Parameters
        ----------
        None

        Returns
        -------
        None
        """

        self.logger.debug('Logging in using user + password')

        token = self._get_token()
        self.token = token['token']
        self.token_details = token

    @check_auth
    @add_auth_header
    def make_request(self, uri, **kwargs):
        """Makes request to device (HTTP/S)

        Parameters
        ----------
        uri : str
            the URI where the request should be made
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        method : str
            the HTTP method to use
        headers : str
            the HTTP headers to use
        body : str
            the HTTP body to use
        body_content_type : str
            the HTTP body content type to use
        bool_response : bool
            return boolean based on HTTP success/failure
        advanced_return : bool
            return additional information, like HTTP status code to caller

        Returns
        -------
        dict
            a dictionary containing the JSON response
        """

        return http_utils.make_request(self.host,
                                       uri,
                                       port=self.port,
                                       **kwargs)

    @check_auth
    def make_ssh_request(self, command):
        """Makes request to device (SSH)

        Parameters
        ----------
        command : str
            the command to execute on the device

        Returns
        -------
        str
            the command response
        """

        return self._make_ssh_request(command)

    def get_info(self):
        """Gets device info

        Parameters
        ----------
        None

        Returns
        -------
        dict
            the device information

            ::

                {
                    'version': 'x.x.x.x'
                }

        """

        uri = '/mgmt/tm/sys/version'
        response = self.make_request(uri)

        version = response['entries'][
            'https://localhost/mgmt/tm/sys/version/0']['nestedStats'][
                'entries']['Version']['description']
        return {'version': version}
コード例 #10
0
Set local environment variables first
"""

# export F5_SDK_HOST='192.0.2.10'
# export F5_SDK_USERNAME='******'
# export F5_SDK_PWD='admin'
# export F5_SDK_AS3_DECL='./my_declaration.json'
# export F5_SDK_LOG_LEVEL='INFO'

import os

from f5sdk.bigip import ManagementClient
from f5sdk.bigip.extension import AS3Client
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def run_example():
    """ Update AS3 configuration

    Notes
    -----
    Includes package installation, service check while
    maintaining idempotency
    """
    # create management client
    mgmt_client = ManagementClient(
        os.environ['F5_SDK_HOST'],
        user=os.environ['F5_SDK_USERNAME'],
        password=os.environ['F5_SDK_PWD'])
コード例 #11
0
ファイル: newbare_cs.py プロジェクト: merps/f5devops
# export F5_SDK_USERNAME='******'
# export F5_SDK_PWD='admin'
# export F5_SDK_CS_SUBSCRIPTION_ID=''
# export F5_SDK_LOG_LEVEL='DEBUG'

#!/usr/bin/python3
import os, sys, json, requests
import argparse, getpass
from f5sdk.cs import ManagementClient
from f5sdk.cs.accounts import AccountClient
from f5sdk.cs.subscriptions import SubscriptionClient
from f5sdk.logger import Logger
# from netaddr import *


LOGGER = Logger(__name__).get_logger()


def parse_args():
    parser = argparse.ArgumentParser(description="command line client")
    subparsers = parser.add_subparsers(dest='command', metavar='command')
    subparsers.required = True
    parser.set_defaults(funct=argparser_handler)

    # Login
    sub_parser = subparsers.add_parser("login", help="Login with email and password")
    sub_parser.add_argument('-u', dest='user', help='user.  If this argument is not passed it will be requested.')
    sub_parser.add_argument('-p', dest='password',
                                help='password.  If this argument is not passed it will be requested.')

    args = parser.parse_args()
コード例 #12
0
-----
Set local environment variables first
"""

# export F5_SDK_USERNAME='******'
# export F5_SDK_PWD='admin'
# export F5_SDK_CS_SUBSCRIPTION_ID=''
# export F5_SDK_LOG_LEVEL='DEBUG'

import os

from f5sdk.cloud_services import ManagementClient
from f5sdk.cloud_services.subscriptions import SubscriptionClient
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def get_cs_config():
    """ Get Cloud Services configuration """
    # create management client
    cs_client = ManagementClient(
        user=os.environ['F5_SDK_USERNAME'], password=os.environ['F5_SDK_PWD'])

    # create subscription client
    subscription_client = SubscriptionClient(cs_client)

    # get subscription details
    return subscription_client.show(name=os.environ['F5_SDK_CS_SUBSCRIPTION_ID'])

コード例 #13
0
class MetadataClient(object):
    """A class used as a metadata client

    Attributes
    ----------
    component : str
        the extension component
    version : str
        the extension component version
    extension_metadata : dict
        the extension metadata

    Methods
    -------
    get_download_url()
        Refer to method documentation
    get_package_name()
        Refer to method documentation
    get_endpoints()
        Refer to method documentation
    """
    def __init__(self, component, version, **kwargs):
        """Class initialization

        Parameters
        ----------
        component : str
            the extension component
        version : str
            the extension component version
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        use_latest_metadata : bool
            use latest metadata (will be retrieved from remote CDN)

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.use_latest_metadata = kwargs.pop('use_latest_metadata', False)
        self.extension_metadata = self._load_metadata()
        self.component = self._validate_component(component)
        self.version = self._validate_component_version(
            self.component, version or self.get_latest_version())

    def _load_metadata(self):
        """Load extension metadata

        Load metadata using the follow order:
        - metadata from CDN (unless use_latest_metadata=False)
        - metadata included in package (local file)

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containg the JSON metadata
        """

        metadata = None

        # retrieve metadata from URL - unless opted out
        if self.use_latest_metadata:
            parsed_url = http_utils.parse_url(EXTENSION_METADATA['URL'])
            try:
                metadata = http_utils.make_request(parsed_url['host'],
                                                   parsed_url['path'])
            except Exception as err:  # pylint: disable=broad-except
                self.logger.warning('Error downloading metadata file: %s', err)

        # fallback to local metadata file
        if metadata is None:
            local_file = os.path.join(os.path.dirname(__file__),
                                      EXTENSION_METADATA['FILE'])
            try:
                with open(local_file) as m_file:
                    metadata = json.loads(m_file.read())
            except Exception as err:  # pylint: disable=broad-except
                raise FileLoadError(err)

        return metadata

    def _validate_component(self, component):
        """Validates the extension component exists in metadata

        Parameters
        ----------
        component : str
            a extension component to check

        Returns
        -------
        str
            the extension component provided if it exists (see Raises)

        Raises
        ------
        Exception
            if the extension component does not exist in metadata
        """

        components = list(self.extension_metadata['components'].keys())
        if not [i for i in components if i == component]:
            raise InvalidComponentError(
                'Valid component must be provided: %s' % (components))
        return component

    def _validate_component_version(self, component, version):
        """Validates the extension component version exists in metadata

        Parameters
        ----------
        component : str
            a extension component to check
        version : str
            a extension component version to check

        Returns
        -------
        str
            the extension component version provided if it exists (see Raises)

        Raises
        ------
        Exception
            if the extension component version does not exist in metadata
        """

        versions = list(self.extension_metadata['components'][component]
                        ['versions'].keys())
        if not [i for i in versions if i == version]:
            raise InvalidComponentVersionError(
                'Valid component version must be provided: %s' % (versions))
        return version

    def _get_component_metadata(self):
        """Gets the metadata for a specific component from the extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing the metadata
        """

        return self.extension_metadata['components'][self.component]

    def _get_version_metadata(self):
        """Gets the metadata for a specific component version from the extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing the metadata
        """

        return self.extension_metadata['components'][
            self.component]['versions'][self.version]

    def get_latest_version(self):
        """Gets the latest component version from the extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        str
            a string containing the latest version
        """

        c_v_metadata = self.extension_metadata['components'][
            self.component]['versions']
        latest = {k: v for (k, v) in c_v_metadata.items() if v['latest']}
        return list(latest.keys())[0]  # we should only have one

    def get_download_url(self):
        """Gets the component versions download url from extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        str
            a string containing the download url
        """

        return self._get_version_metadata()['downloadUrl']

    def get_package_name(self):
        """Gets the component versions package name from extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        str
            a string containing the package name
        """

        return self._get_version_metadata()['packageName']

    def get_component_package_name(self):
        """Gets the component's package name from extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        str
            a string containing the component's package name. Example: 'telemetry'
        """

        return re.split(
            '-[0-9]',
            re.split('f5-?',
                     self._get_version_metadata()['packageName'])[1])[0]

    def get_component_dependencies(self):
        """Gets the component dependencies

        Parameters
        ----------
        None

        Returns
        -------
        dict
            describes the component dependencies
        """

        return self._get_component_metadata()['componentDependencies']

    def get_endpoints(self):
        """Gets the component endpoints from extension metadata

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing the endpoints
        """

        return self._get_component_metadata()['endpoints']
コード例 #14
0
class ManagementClient(object):
    """A class used as a management client for F5 Cloud Services

    Attributes
    ----------
    access_token : str
        the access token for the service
    token_details : dict
        the token details for the service
    logger : object
        instantiated logger object

    Methods
    -------
    make_request()
        Refer to method documentation
    """
    def __init__(self, **kwargs):
        """Class initialization

        Parameters
        ----------
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        user : str
            the username for service authentication
        password : str
            the password for service authentication

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        # process kwargs
        self._api_endpoint = kwargs.pop('api_endpoint', None)
        if self._api_endpoint is None:
            self._api_endpoint = API_ENDPOINT

        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)
        self._subscription_id = kwargs.pop('subscription_id', None)

        self.access_token = None
        self.token_details = None

        if self._user and self._password:
            self._login_using_credentials()
        else:
            raise InputRequiredError('user|password required')

    @retry(exceptions=HTTPError,
           tries=constants.RETRIES['DEFAULT'],
           delay=constants.RETRIES['DELAY_IN_SECS'])
    def _get_token(self):
        """Gets access token

        Retries if unsuccessful, up to maximum allotment

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing access token and expiration in seconds:
            {'accessToken': 'token', 'expirationIn': 3600}
        """

        try:
            response = http_utils.make_request(self._api_endpoint,
                                               '/v1/svc-auth/login',
                                               method='POST',
                                               body={
                                                   'username': self._user,
                                                   'password': self._password
                                               })
        except HTTPError as error:
            if constants.HTTP_STATUS_CODE['BAD_REQUEST_BODY'] in str(error) or \
                constants.HTTP_STATUS_CODE['FAILED_AUTHENTICATION'] in str(error):
                _exception = InvalidAuthError(error)
                _exception.__cause__ = None
                raise _exception
            raise error
        return {
            'accessToken': response['access_token'],
            'expirationIn': response['expires_at']
        }

    def _login_using_credentials(self):
        """Logs in to service using user + password

        Parameters
        ----------
        None

        Returns
        -------
        None
        """

        self.logger.info('Logging in using user + password')
        self.token_details = self._get_token()
        self.access_token = self.token_details['accessToken']

    def make_request(self, uri, **kwargs):
        """Makes request to service (HTTP/S)

        Parameters
        ----------
        uri : str
            the URI where the request should be made
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        method : str
            the HTTP method to use
        headers : str
            the HTTP headers to use
        body : str
            the HTTP body to use
        body_content_type : str
            the HTTP body content type to use
        bool_response : bool
            return boolean based on HTTP success/failure

        Returns
        -------
        dict
            a dictionary containing the JSON response
        """

        # merge default authentication headers with any user supplied ones
        dfl_headers = {AUTH_TOKEN_HEADER: 'Bearer %s' % self.access_token}
        dfl_headers.update(kwargs.pop('headers', {}))

        return http_utils.make_request(self._api_endpoint,
                                       uri,
                                       headers=dfl_headers,
                                       **kwargs)
コード例 #15
0
class ManagementClient(object):
    """A class used as a management client for BIG-IQ

    Attributes
    ----------
    host : str
        the hostname of the device
    port : str
        the port of the device

    Methods
    -------
    get_info()
        Refer to method documentation
    make_request()
        Refer to method documentation
    """
    def __init__(self, host, **kwargs):
        """Class initialization

        Parameters
        ----------
        host : str
            the hostname of the device
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        port : int
            the port to assign to the port attribute
        user : str
            the username for device authentication
        password : str
            the password for device authentication

        Returns
        -------
        None
        """

        self.logger = Logger(__name__).get_logger()

        self.host = host.split(':')[0]
        self.port = kwargs.pop('port', 443)

        self._user = kwargs.pop('user', None)
        self._password = kwargs.pop('password', None)

        # account for multiple authentication schemes
        if self._user and self._password:
            self._login_using_credentials()
        else:
            raise Exception('user|password required')

    @retry(tries=constants.RETRIES['DEFAULT'],
           delay=constants.RETRIES['DELAY_IN_SECS'])
    def _get_token(self):
        """Gets authentication token

        Retries if unsuccessful, up to maximum allotment

        Parameters
        ----------
        None

        Returns
        -------
        dict
            a dictionary containing authentication token, expiration date and expiration in seconds:
            {
                'token': 'token',
                'expirationDate': '2019-01-01T01:01:01.00'
            }
        """

        self.logger.debug('Getting authentication token')

        response = http_utils.make_request(self.host,
                                           '/mgmt/shared/authn/login',
                                           port=self.port,
                                           method='POST',
                                           body={
                                               'username': self._user,
                                               'password': self._password
                                           },
                                           basic_auth={
                                               'user': self._user,
                                               'password': self._password
                                           })
        token_details = response['token']

        return {
            'token':
            token_details['token'],
            'expirationDate':
            (datetime.now() +
             timedelta(seconds=token_details['timeout'])).isoformat()
        }

    def _login_using_credentials(self):
        """Login to device using user + password

        Parameters
        ----------
        None

        Returns
        -------
        None
        """

        self.logger.info('Logging in using user + password')

        self.token = self._get_token()['token']

    @check_auth
    @add_auth_header
    def make_request(self, uri, **kwargs):
        """Makes request to device (HTTP/S)

        Parameters
        ----------
        uri : str
            the URI where the request should be made
        **kwargs :
            optional keyword arguments

        Keyword Arguments
        -----------------
        method : str
            the HTTP method to use
        headers : str
            the HTTP headers to use
        body : str
            the HTTP body to use
        body_content_type : str
            the HTTP body content type to use
        bool_response : bool
            return boolean based on HTTP success/failure
        advanced_return : bool
            return additional information, like HTTP status code to caller

        Returns
        -------
        dict
            a dictionary containing the JSON response
        """

        return http_utils.make_request(self.host,
                                       uri,
                                       port=self.port,
                                       **kwargs)

    def get_info(self):
        """Gets device info

        Parameters
        ----------
        None

        Returns
        -------
        dict
            the device information

            ::

                {
                    'version': 'x.x.x.x'
                }

        """

        response = self.make_request('/mgmt/tm/sys/version')

        version_info = response['entries'][
            'https://localhost/mgmt/tm/sys/version/0']['nestedStats'][
                'entries']
        return {'version': version_info['Version']['description']}
コード例 #16
0
import getopt
import os
import sys
import yaml
import json
import jsonschema
import requests
from jinja2 import Environment, FileSystemLoader
from f5sdk.bigip import ManagementClient
from f5sdk.bigip.extension import AS3Client, DOClient
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def create_declaration(data, atc_type):
    """ 
    create automation toolchain declaration 
    """
    file_loader = FileSystemLoader('templates')
    env = Environment(loader=file_loader)

    # load the template
    template_type = "as3_template" if atc_type == "as3" else "do_template"
    template = env.get_template(data[template_type] + '.j2')

    # render the template
    output = template.render(data=data)

    # write the template to file
    LOGGER.info('writing declaration for {}'.format(data['hostname']))
コード例 #17
0
# export F5_SDK_HOST='192.0.2.10'
# export F5_SDK_USERNAME='******'
# export F5_SDK_PWD='admin'
# export F5_SDK_ADDRESS_TO_REVOKE='192.0.2.100'
# export F5_SDK_LICENSE_POOL='my_pool'
# export F5_SDK_LOG_LEVEL='INFO'

import os

from f5sdk.bigiq import ManagementClient
from f5sdk.bigiq.licensing import AssignmentClient
from f5sdk.bigiq.licensing.pools import MemberManagementClient
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def run_example(address, pool):
    """ Revoke license"""

    # create management client
    mgmt_client = ManagementClient(os.environ['F5_SDK_HOST'],
                                   user=os.environ['F5_SDK_USERNAME'],
                                   password=os.environ['F5_SDK_PWD'])

    # create assignment client, member management client
    assignment_client = AssignmentClient(mgmt_client)
    member_mgmt_client = MemberManagementClient(mgmt_client)

    # list assignments
コード例 #18
0
"""Python module containing helper http utility functions """

import json
import os
import warnings
import requests
import urllib3

from f5sdk import constants
from f5sdk.logger import Logger

from f5sdk.exceptions import HTTPError

logger = Logger(__name__).get_logger()  # pylint: disable=invalid-name


def download_to_file(url, file_name):
    """Downloads an artifact to a local file

    Notes
    -----
    Uses a stream to avoid loading into memory

    Parameters
    ----------
    url : str
        the URL where the artifact should be downloaded from
    file_name : str
        the local file name where the artifact should be downloaded

    Returns
コード例 #19
0
Set local environment variables first
"""

# export F5_CS_USER='******'
# export F5_CS_PWD='example_password'
# export F5_SDK_LOG_LEVEL='INFO'

import os
import json

from f5sdk.cs import ManagementClient
from f5sdk.cs.accounts import AccountClient
from f5sdk.cs.subscriptions import SubscriptionClient
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def run_example():
    """ Get Cloud Services configuration """
    # create management client
    mgmt_client = ManagementClient(user=os.environ['F5_CS_USER'],
                                   password=os.environ['F5_CS_PWD'])

    # create account/subscription client
    account_client = AccountClient(mgmt_client)
    subscription_client = SubscriptionClient(mgmt_client)

    # discover account/subscription ID
    account_id = account_client.show_user()['primary_account_id']
    subscription_id = subscription_client.list(
コード例 #20
0
ファイル: extension_as3.py プロジェクト: jikui/f5-sdk-python
Set local environment variables first
"""

# export F5_SDK_HOST='192.0.2.10'
# export F5_SDK_USERNAME='******'
# export F5_SDK_PWD='admin'
# export F5_SDK_AS3_DECL='./my_declaration.json'
# export F5_SDK_LOG_LEVEL='DEBUG'

import os

from f5sdk.bigip import ManagementClient
from f5sdk.bigip.extension import ExtensionClient
from f5sdk.logger import Logger

LOGGER = Logger(__name__).get_logger()


def update_as3_config():
    """ Update AS3 configuration

    Notes
    -----
    Includes package installation, service check while
    maintaining idempotency
    """
    # create management client
    mgmt_client = ManagementClient(os.environ['F5_SDK_HOST'],
                                   user=os.environ['F5_SDK_USERNAME'],
                                   password=os.environ['F5_SDK_PWD'])