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( query_parameters={'account_id': account_id })['subscriptions'][0]['subscription_id'] # get subscription details return subscription_client.show(name=subscription_id) if __name__ == '__main__': LOGGER.info(json.dumps(run_example(), indent=4))
# configure service return client.service.create(config_file='./files/{}.{}.json'.format( data['hostname'].split('.')[0], atc_type)) if __name__ == '__main__': # Read BIG-IP data from YAML file or environment variables inputfile = '' bigip_data = {} try: # Ensure data file is provided if len(sys.argv) == 1: print( "Please provide a yaml file containing variables.\nExample:\n") print("python3 bigip.py data.yml\n") # Set BIG-IP data from the YAML file else: inputfile = sys.argv[1] stream = open(inputfile, 'r') bigip_data = yaml.load(stream, Loader=yaml.BaseLoader) stream.close() except OSError as err: print(str(err)) sys.exit(2) # Loop through the BIG-IPs for bigip in bigip_data['bigips']: # LOGGER.info(create_declaration({ **bigip, **bigip_data['dataCenters'][bigip['dataCenter']] },"do")) LOGGER.info(create_declaration(bigip, "as3")) # LOGGER.info(update_config(bigip, "do")) LOGGER.info(update_config(bigip, "as3"))
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']) # create extension client as3_client = AS3Client(mgmt_client) # Get installed package version info version_info = as3_client.package.is_installed() LOGGER.info(version_info['installed']) LOGGER.info(version_info['installed_version']) LOGGER.info(version_info['latest_version']) # install package if not version_info['installed']: as3_client.package.install() # ensure service is available as3_client.service.is_available() # configure AS3 return as3_client.service.create(config_file=os.environ['F5_SDK_AS3_DECL']) if __name__ == '__main__': LOGGER.info(run_example())
# create assignment client, member management client assignment_client = AssignmentClient(mgmt_client) member_mgmt_client = MemberManagementClient(mgmt_client) # list assignments assignments = assignment_client.list() # get address assignment - there should only be one assignments = assignments['items'] assignment = [i for i in assignments if i['deviceAddress'] == address][0] if not assignment: raise Exception('Unable to locate assignment from BIG-IQ assignments') # perform revoke - unreachable device return member_mgmt_client.create( config={ 'licensePoolName': pool, 'command': 'revoke', 'address': assignment['deviceAddress'], 'assignmentType': 'UNREACHABLE', 'macAddress': assignment['macAddress'] }) if __name__ == '__main__': RESPONSE = run_example(os.environ['F5_SDK_ADDRESS_TO_REVOKE'], os.environ['F5_SDK_LICENSE_POOL']) LOGGER.info('Response: %s', RESPONSE)
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)
# 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']) if __name__ == '__main__': LOGGER.info(get_cs_config())
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']}
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']) # create extension client as3_client = ExtensionClient(mgmt_client, 'as3') # Get installed package version info version_info = as3_client.package.is_installed() LOGGER.info(version_info['installed']) LOGGER.info(version_info['installed_version']) LOGGER.info(version_info['latest_version']) # install package if not version_info['installed']: as3_client.package.install() # ensure service is available as3_client.service.is_available() # configure AS3 return as3_client.service.create(config_file=os.environ['F5_SDK_AS3_DECL']) if __name__ == '__main__': LOGGER.info(update_as3_config())