Cisco pxgrid部分函数封装
pxgrid.py
import requests import urllib3 import os import sys import json import websockets import asyncio from io import StringIO from base64 import b64encode import ssl urllib3.disable_warnings() headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } def gen_http_basic_auth(username, password): if isinstance(username, str): username = username.encode('latin1') if isinstance(password, str): password = password.encode('latin1') return 'Basic ' + b64encode(b':'.join((username, password))).decode().strip() class Config(object): def __init__( self, hostname, username, password=None, description=None, client_cert=None, client_key=None, client_key_password=None, server_cert=None ): """ :param hostname: ISE server :param username: client_node_name :param password: password (optional) :param description: Description (optional) :param client_cert: Client certificate chain filename (optional) :param client_key: Client key filename (optional) :param client_key_password: Client key password (optional) :param server_cert: Server certificates filename """ self.hostname = hostname self.username = username self.password = password self.description = description self.client_cert = client_cert self.client_key = client_key self.client_key_password = client_key_password self.server_cert = server_cert def get_ssl_context(self): context = ssl.create_default_context() if self.client_cert is not None: context.load_cert_chain( certfile=self.client_cert, keyfile=self.client_key, password=self.client_key_password ) context.load_verify_locations(cafile=self.server_cert) return context class StompFrame: def __init__(self): self.headers = {} self.command = None self.content = None def get_command(self): return self.command def set_command(self, command): self.command = command def get_content(self): return self.content def set_content(self, content): self.content = content def get_header(self, key): return self.headers[key] def set_header(self, key, value): self.headers[key] = value def write(self, out): out.write(self.command) out.write('\n') for key in self.headers: out.write(key) out.write(':') out.write(self.headers[key]) out.write('\n') out.write('\n') if self.content is not None: out.write(self.content) out.write('\0') @staticmethod def parse(_input): frame = StompFrame() frame.command = _input.readline().rstrip('\r\n') for line in _input: line = line.rstrip('\r\n') if line == '': break (name, value) = line.split(':') frame.headers[name] = value frame.content = _input.read()[:-1] return frame class WebSocketStomp: def __init__(self, ws_url, user, password, ssl_ctx): self.ws_url = ws_url self.user = user self.password = password self.ssl_ctx = ssl_ctx self.ws = None async def connect(self): authorization = gen_http_basic_auth(self.user, self.password) self.ws = await websockets.connect( uri=self.ws_url, extra_headers={ 'Authorization': authorization }, ssl=self.ssl_ctx ) async def stomp_connect(self, hostname): print('STOMP CONNECT host=' + hostname) frame = StompFrame() frame.set_command("CONNECT") frame.set_header('accept-version', '1.2') frame.set_header('host', hostname) out = StringIO() frame.write(out) await self.ws.send(out.getvalue().encode()) async def stomp_subscribe(self, topic): print('STOMP SUBSCRIBE topic=' + topic) frame = StompFrame() frame.set_command("SUBSCRIBE") frame.set_header('destination', topic) frame.set_header('id', 'my-id') out = StringIO() frame.write(out) await self.ws.send(out.getvalue().encode()) async def stomp_send(self, topic, message): print('STOMP SEND topic=' + topic) frame = StompFrame() frame.set_command("SEND") frame.set_header('destination', topic) frame.set_header('content-length', str(len(message))) frame.set_content(message) out = StringIO() frame.write(out) await self.ws.send(out.getvalue().encode()) # only returns for MESSAGE async def stomp_read_message(self): while True: message = await self.ws.recv() s_in = StringIO(message.decode()) stomp = StompFrame.parse(s_in) if stomp.get_command() == 'MESSAGE': return stomp.get_content() elif stomp.get_command() == 'CONNECTED': version = stomp.get_header('version') print('STOMP CONNECTED version=' + version) elif stomp.get_command() == 'RECEIPT': receipt = stomp.get_header('receipt-id') print('STOMP RECEIPT id=' + receipt) elif stomp.get_command() == 'ERROR': print('STOMP ERROR content=' + stomp.get_content()) async def stomp_disconnect(self, receipt=None): print('STOMP DISCONNECT receipt=' + receipt) frame = StompFrame() frame.set_command("DISCONNECT") if receipt is not None: frame.set_header('receipt', receipt) out = StringIO() frame.write(out) await self.ws.send(out.getvalue().encode()) async def disconnect(self): await self.ws.close() def is_open(self): return self.ws.open class PXGridProviderAPI(object): __doc__ = ( 'pxGrid nodes connect to pxGrid Controller to perform control operations that facilitates communications ' 'between consumer nodes and provider nodes. ' 'This guide discuss HTTP APIs use by provider nodes' ) SERVICE_NAME = None WS_PUBSUB_SERVICE = 'com.cisco.ise.pubsub' def __init__(self, config): self.config = config if self.SERVICE_NAME is not None: services = self.service_lookup(self.SERVICE_NAME).get('services') self.service = services[0] self.service_node_name = self.service['nodeName'] self.rest_base_url = self.service['properties']['restBaseUrl'] self.service_secret = self.access_secret(self.service_node_name).get('secret') # PubSub WSS self.pubsub_services = self.service_lookup(self.WS_PUBSUB_SERVICE).get('services') if self.pubsub_services: self.pubsub_service = self.pubsub_services[0] self.pubsub_node_name = self.pubsub_service.get('nodeName') self.pubsub_secret = self.access_secret(self.pubsub_node_name).get('secret') self.pubsub_ws_url = self.pubsub_service.get('properties').get('wsUrl') def _send_request(self, url_suffix, payload, ps_url_suffix=True, **others): if ps_url_suffix: url_suffix = url_suffix.title().replace('_', '') url = f'https://{self.config.hostname}:8910/pxgrid/control/{url_suffix}' kwargs = dict( url=url, verify=False, json=payload, auth=(self.config.username, self.config.password) ) kwargs.update(**others) res = requests.post(headers=headers, **kwargs) result = { 'status_code': res.status_code } try: result.update(res.json()) except: pass return result def _send_query(self, url_suffix, payload, ps_url_suffix=True): if ps_url_suffix: url_suffix = ''.join([url_suffix.split('_')[0]] + [word.title() for word in url_suffix.split('_')[1:]]) url = os.path.join(self.rest_base_url, url_suffix).replace('\\', '/') kwargs = dict( url=url, verify=False, json=payload, auth=(self.config.username, self.service_secret) ) res = requests.post(headers=headers, **kwargs) result = { 'status_code': res.status_code } try: result.update(res.json()) except: pass return result def service_register(self, **payload): """ ServiceRegister is used to register a service name with its properties and operations. name is a string (alphanumerics and periods(.) of max 50 characters) properties will be sent to the consumers who is looking up for the service. It is an array of name and value pairs. name is a string (alphanumerics of max 50 characters). value is a string (max 100 characters). operations are array of service and operation pairs this provider will used for Authorization API. This lets the pxGrid controller knows the possible combinations of services and operations, in which can be used to setup rules. service is a string (alphanumerics and periods(.) of max 50 characters). operation is a string (alphanumerics of max 50 characters). ServiceRegister returns id and a reregisterTimeMillis. id is used for subsequence ServiceReregister and ServiceUnregister commands. reregisterTimeMillis is the time in milliseconds that this service must re-register in order to keep the service alive. Otherwise, pxGrid Controller will assume the service is no long available and remove the entry. :param payload: { "name": "com.cisco.ise.config.anc", "properties": { "restBaseUrl":"https://pxgrid-041.cisco.com:8910/pxgrid/ise/config/anc", "wsPubsubService":"com.cisco.ise.pubsub", "statusTopic":"/topic/com.cisco.ise.config.anc.status" }, "operations":[ { "service": "com.cisco.ise.config.anc", "operation": "gets" }, { "service": "com.cisco.ise.config.anc", "operation": "sets" }, { "service": "com.cisco.ise.pubsub", "operation": "publish /topic/com.cisco.ise.config.anc.status" }, { "service": "com.cisco.ise.pubsub", "operation": "subscribe /topic/com.cisco.ise.config.anc.status" } ] } or { "id":"123" } :return: { "id":"123", "reregisterTimeMillis":60000 } or {} """ return self._send_request(sys._getframe().f_code.co_name, payload) def service_reregister(self, **payload): """ ServiceReregister is used to signify that the service is still active. This must be periodically triggered according to the reregisterTimeMillis @:param payload: { "id":"123" } :return: nothing """ return self._send_request(sys._getframe().f_code.co_name, payload) def service_unregister(self, **payload): """ ServiceUnregister is used to un-register a service. :param payload: { "id":"123" } :return: {} """ return self._send_request(sys._getframe().f_code.co_name, payload) def authorization(self, **payload): """ @:param payload: { "requestNodeName":"node1", "serviceName":"com.cisco.ise.config.anc", "serviceOperation":"gets" } :return: { "authorization":"PERMIT" } """ return self._send_request(sys._getframe().f_code.co_name, payload) def access_secret(self, peer_node_name): """ :param peer_node_name: :return: { "secret":"oWhgNC7oNpaulpJ6" } """ payload = {'peerNodeName': peer_node_name} return self._send_request(sys._getframe().f_code.co_name, payload) def account_create(self, username): """ :param username: python_test :return: {"nodeName": "python_test", "password": "QVTXCDgoQlbspqmQ", "userName": "python_test"} """ payload = {'nodeName': username} return self._send_request(sys._getframe().f_code.co_name, payload) def account_activate(self): """ Request { "description": string (max 50 characters. Alphanumerics, spaces, underscores(_), comma(,), dashes(-) and periods(.)) } Response { "accountState": string (PENDING,DISABLE or ENABLED) "version": string (e.g "2.0.2.1") } :return: { "accountState": string (PENDING,DISABLE or ENABLED) "version": string (e.g "2.0.2.1") } """ payload = {} if self.config.description is not None: payload['description'] = self.config.description return self._send_request(sys._getframe().f_code.co_name, payload) def service_lookup(self, name): payload = {'name': name} return self._send_request(sys._getframe().f_code.co_name, payload) @classmethod async def future_read_message(cls, ws, future): try: message = await ws.stomp_read_message() future.set_result(message) except websockets.ConnectionClosed: print('Websocket connection closed') async def subscribe_loop(self, topic, callback): ws = WebSocketStomp( ws_url=self.pubsub_ws_url, user=self.config.username, password=self.pubsub_secret, ssl_ctx=self.config.get_ssl_context() ) await ws.connect() await ws.stomp_connect(self.pubsub_node_name) await ws.stomp_subscribe(topic) print("Ctrl-C to disconnect...") while True: future = asyncio.Future() future_read = self.future_read_message(ws, future) try: await asyncio.wait([future_read], return_when=asyncio.FIRST_COMPLETED) except asyncio.CancelledError: await ws.stomp_disconnect('123') # wait for receipt await asyncio.sleep(0.05) await ws.disconnect() future.cancel() break else: message = json.loads(future.result()) callback(message) class ANCConfiguration(PXGridProviderAPI): __doc__ = 'This is Adaptive Network Control configuration service' SERVICE_NAME = 'com.cisco.ise.config.anc' ANC_STATUS_TOPIC = '/topic/com.cisco.ise.config.anc.status' def get_policies(self): """ This is used to get policies. An empty json structure must be sent as the request. If no policy is found, policies will have an empty array. :return: { "policies": [ array of policy object ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) def get_policy_by_name(self, name): """ If policy does not exist, HTTP status "204 No content" will be returned with empty body :param name: 'Quarantine' :return: { policy object } """ payload = {'name': name} return self._send_query(sys._getframe().f_code.co_name, payload) def create_policy(self, policy): """ here is no need to set the "id" field for the request policy object. After successful creation, the "id" field will be populated in the returned policy object If the policy name is already used in an existing policy, HTTP status "409 Conflict" will be returned. :param policy: { policy object } :return: """ payload = {'policy ': policy} return self._send_query(sys._getframe().f_code.co_name, payload) def delete_policy_by_name(self, name): """ This is no response body for this query. If policy is deleted, HTTP status "200" will be returned. If policy does not exist, HTTP status "204 No content" will be returned. :param name : :return: (empty) """ payload = {'name ': name} return self._send_query(sys._getframe().f_code.co_name, payload) def get_endpoints(self): """ This is used to get endpoints with policies applied An empty json structure must be sent as the request. If no endpoint policy is found, endpointPolicies will have an empty array. :return: { "endpoints": [ array of endpoint object ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) def get_endpoint_by_mac_address(self, mac_address): """ If endpoint does not exist, HTTP status "204 No content" will be returned. :param mac_address: :return: { endpoint object } """ payload = {'macAddress': mac_address} return self._send_query(sys._getframe().f_code.co_name, payload) def apply_endpoint_by_ip_address(self, policy_name, ip_address): """ Apply a policy to the endpoint using IP Address. If endpoint already has existing policy applied, the return status will be FAILURE with reason "mac address is already associated with this policy". If endpoint does not exist, the return status will be FAILURE with reason "Session lookup failure". :param policy_name: :param ip_address: :return: { status object } """ payload = { "policyName": policy_name, "ipAddress": ip_address } return self._send_query(sys._getframe().f_code.co_name, payload) def apply_endpoint_by_mac_address(self, policy_name, mac_address): """ Apply a policy to the endpoint using MAC Address. If endpoint already has existing policy applied, the return status will be FAILURE with reason "mac address is already associated with this policy". :param policy_name: :param mac_address: :return: { status object } """ payload = { "policyName": policy_name, "macAddress": mac_address } return self._send_query(sys._getframe().f_code.co_name, payload) def clear_endpoint_by_mac_address(self, mac_address): """ Apply a policy to the endpoint using MAC Address If endpoint does not have an existing policy applied, the return status will be FAILURE with reason "mac address is not associated with a policy". :param mac_address: :return: { status object } """ payload = { "macAddress": mac_address } return self._send_query(sys._getframe().f_code.co_name, payload) def get_operation_status(self, operation_id): """ If operation does not exist, HTTP status "204 No content" will be returned. :param operation_id: :return: { status object } """ payload = { "operationId": operation_id } return self._send_query(sys._getframe().f_code.co_name, payload) class EndpointAsset(PXGridProviderAPI): __doc__ = ( 'This is ISE pxGrid Context-In feature This is for providers to publish asset data into ISE ' 'where ISE Profiler component acts as a subscriber to collect' ) SERVICE_NAME = 'com.cisco.endpoint.asset' ENDPOINT_ASSET_TOPIC = '/topic/com.cisco.endpoint.asset' class Endpoint(PXGridProviderAPI): __doc__ = ( 'This is ISE pxGrid Context-In feature This is for providers to publish asset data into ISE ' 'where ISE Profiler component acts as a subscriber to collect' ) SERVICE_NAME = 'com.cisco.ise.endpoint' ENDPOINT_TOPIC = '/topic/com.cisco.ise.endpoint' class MDM(PXGridProviderAPI): __doc__ = 'This is Mobile Device Management (MDM) service' SERVICE_NAME = 'com.cisco.ise.mdm' MDM_ENDPOINT_TOPIC = '/topic/com.cisco.ise.mdm.endpoint' def get_endpoints(self, _filter=None): """ This is used to get endpoints. An optional filter can be used in which entries matching the attributes specified will be returned. If no filter is used, an empty json structure must be sent as the request. If no policy is found, endpoints will have an empty array. :param _filter: :return: { "endpoints": [ array of endpoint object ] } """ payload = {} if _filter is not None: payload = { 'filter': _filter } return self._send_query(sys._getframe().f_code.co_name, payload=payload) def get_endpoint_by_mac_address(self, mac_address): """ If not found, HTTP status "204 No content" will be returned. :param mac_address: :return: { endpoint object } """ payload = { "macAddress": mac_address } return self._send_query(sys._getframe().f_code.co_name, payload) def get_endpoints_by_type(self, endpoint_type): """ This is used to get endpoints by type, either non-compliant, registered or disconnected endpoints. If no policy is found, endpoints will have an empty array. :param endpoint_type: (required. values: NON_COMPLIANT, REGISTERED, DISCONNECTED) :return: { "endpoints": [ array of endpoint object ] } """ payload = { "type": endpoint_type } return self._send_query(sys._getframe().f_code.co_name, payload) def get_endpoints_by_os_type(self, os_type): """ This is used to get endpoints by OS type, either ANDROID, IOS or WINDOWS. If no policy is found, endpoints will have an empty array. :param os_type: (required. values: ANDROID, IOS or WINDOWS) :return: { "endpoints": [ array of endpoint object ] } """ payload = { "osType": os_type } return self._send_query(sys._getframe().f_code.co_name, payload) class ProfilerConfiguration(PXGridProviderAPI): __doc__ = 'This is ISE Profiler configuration' SERVICE_NAME = 'com.cisco.ise.config.profiler' PROFILER_TOPIC = '/topic/com.cisco.ise.config.profiler' def get_profiles(self): """ :return: { "profiles": [ array of profile object ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) class RadiusFailure(PXGridProviderAPI): __doc__ = 'This service provides information about Radius protocol. RFC2865(https://tools.ietf.org/html/rfc2865)' SERVICE_NAME = 'com.cisco.ise.radius' RADIUS_FAILURE_TOPIC = '/topic/com.cisco.ise.radius.failure' def get_failures(self, start_timestamp=None): """ This gets the Radius authentication failures since startTimestamp If startTimestamp is not specified, the failures for the last hour is returned. The failures included are ISE syslog message codes 5400 to 5499 that are listed here If no failure is found, failures attribute will contain an empty array. Note that radius authentication failures can be suppressed, so the timestamps being reported may not be the latest events :param start_timestamp: '2020-09-11T11:48:32.518+08:00' (optional) :return: { "failures": [ array of failure objects ] } """ payload = {} if start_timestamp is not None: payload['start_timestamp'] = start_timestamp return self._send_query(sys._getframe().f_code.co_name, payload) def get_failure_by_id(self, _id): """ This gets the failure object with the specified id. If not found, HTTP status "204 No content" will be returned. Note that radius authentication failures can be suppressed, so the timestamps being reported may not be the latest events. @:param _id: :return: { failure objects } """ payload = {'id': _id} return self._send_query(sys._getframe().f_code.co_name, payload) class SessionDirectory(PXGridProviderAPI): __doc__ = ''' This service provides access to ISE Session Directory. There are 2 objects that can be accessed: Session UserGroup UserGroup is being separated out from Session object because of its size and static nature ''' SERVICE_NAME = 'com.cisco.ise.session' SESSION_TOPIC = '/topic/com.cisco.ise.session' SESSION_GROUP_TOPIC = '/topic/com.cisco.ise.session.group' def get_sessions(self, start_timestamp=None): """ This query returns a session object if found. If not, HTTP status "204 No content" will be returned. :param start_timestamp: '2020-09-11T11:48:32.518+08:00' (optional) :return: { "sessions": [ array of session objects ] } """ payload = {} if start_timestamp is not None: payload = {'startTimestamp': start_timestamp} return self._send_query(sys._getframe().f_code.co_name, payload) def get_session_by_ip_address(self, ip_address): """ This query returns a session object if found. If not, HTTP status "204 No content" will be returned. :param ip_address: :return: { session object } """ payload = { 'ipAddress': ip_address, } return self._send_query(sys._getframe().f_code.co_name, payload) def get_session_by_mac_address(self, mac_address): """ This query returns a session object if found. If not, HTTP status "204 No content" will be returned. :param mac_address: FC:FC:48:98:E2:79 :return: { session object } """ payload = { 'macAddress': mac_address, } return self._send_query(sys._getframe().f_code.co_name, payload) def get_user_groups(self): """ This gets all user groups. These user groups represent only the groups of the users that have been authenticated by ISE. If no user group is found, userGroups will have an empty array. :return: { "userGroups": [ array of userGroup objects ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) def get_user_group_by_username(self, username): """ This query returns an array of group object. If the user has no group association, groups will have an empty array. If user does not exist, HTTP status "204 No content" will be returned. :param username: :return: { "groups": [ array of group objects ] } """ payload = { 'userName': username } return self._send_query(sys._getframe().f_code.co_name, payload) class SystemHealth(PXGridProviderAPI): __doc__ = 'This is ISE System Health service' SERVICE_NAME = 'com.cisco.ise.system' def get_healths(self, node_name=None, start_timestamp=None): """ @:param node_name: string (optional) // All nodes if not present @:param start_timestamp: ISO8601 Datetime (optional) // Last 1 hour if not present '2020-09-11T17:00:32.518+08:00' :return: { "healths": [ array of syshealth objects // { "timestamp":"2017-05-10T15:21:14.294-07:00", "serverName":"pxgrid-001", "ioWait":0.3, "cpuUsage":41.93, "memoryUsage":71.72, "diskUsageRoot":14.0, "diskUsageOpt":18.0, "loadAverage":2.1, "networkSent":2587, "networkReceived":93292 }, ] } """ payload = {} if node_name: payload['nodeName'] = node_name if start_timestamp: payload['startTimestamp'] = start_timestamp return self._send_query(sys._getframe().f_code.co_name, payload) def get_performances(self, node_name=None, start_timestamp=None): """ @:param node_name: string (optional) // All nodes if not present @:param start_timestamp: ISO8601 Datetime (optional) // Last 1 hour if not present '2020-09-11T17:00:32.518+08:00' :return: { "performances": [ array of performance objects // { "timestamp":"2017-05-10T18:06:15.011336-07:00", "serverName":"pxgrid-001", "radiusRate":0.0, "radiusCount":0, "radiusLatency":0.0 }, ] } """ payload = {} if node_name: payload['nodeName'] = node_name if start_timestamp: payload['startTimestamp'] = start_timestamp return self._send_query(sys._getframe().f_code.co_name, payload) class TrustSec(PXGridProviderAPI): __doc__ = 'This is ISE TrustSec service. Currently, it provides the status of SGACL downloads.' SERVICE_NAME = 'com.cisco.ise.trustsec' TRUSTSEC_POLICY_DOWNLOAD_TOPIC = '/topic/com.cisco.ise.trustsec.policy.download' class TrustSecConfiguration(PXGridProviderAPI): __doc__ = 'This provides the configuration for TrustSec' SERVICE_NAME = 'com.cisco.ise.config.trustsec' TRUSTSEC_SECURITY_GROUP_TOPIC = '/topic/com.cisco.ise.config.trustsec.security.group' TRUSTSEC_SECURITY_GROUP_ACL_TOPIC = '/topic/com.cisco.ise.config.trustsec.security.group.acl' def get_security_groups(self, group_id=None): """ The is used to get security groups. The security group id can be specified. If not specified, all security groups are returned. If no request parameter is used, an empty json structure must be sent. If no security group is found, securityGroups will have an empty array. :param group_id: (optional) :return: { "securityGroups": [ array of securityGroup object ] } """ payload = {} if group_id: payload = {'id': str(group_id)} return self._send_query(sys._getframe().f_code.co_name, payload) def get_security_group_acls(self, group_id=None): """ The is used to get security group ACLs. The id for security group ACLs can be specified. If not specified, all security group ACLs are returned. If no request parameter is used, an empty json structure must be sent. If no security group ACL is found, securityGroupAcls will have an empty array. :param group_id: (optional) :return: { "securityGroupAcls": [ array of securityGroupAcl object ] } """ payload = {} if group_id: payload = {'id': str(group_id)} return self._send_query(sys._getframe().f_code.co_name, payload) def get_egress_policies(self): """ This is used to get egress policies. An empty json structure must be sent as the request. If no egress policy is found, egressPolicies will have an empty array. :return: { "egressPolicies": [ array of egressPolicy object ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) def get_egress_matrices(self): """ This is used to get egress policies. An empty json structure must be sent as the request. If no egress matrix is found, egressMatrices will have an empty array. :return: { "egressMatrices": [ array of egressMatrix object ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) class TrustSecSXP(PXGridProviderAPI): __doc__ = 'This is ISE SXP service' SERVICE_NAME = 'com.cisco.ise.sxp' SXP_BINDING_TOPIC = '/topic/com.cisco.ise.sxp.binding' def get_bindings(self): """ :return: { "bindings": [ array of binding objects ] } """ payload = {} return self._send_query(sys._getframe().f_code.co_name, payload) class PxGrid(object): __doc__ = ''' 0.PXGridProviderAPI(Common): HTTP API: service_register(**payload) ServiceRegister用于注册具有其属性和操作的服务名称。 名称是一个字符串(最多50个字符的字母数字和句点(。)) 属性将发送给正在寻找服务的消费者 它是名称和值对的数组。 name是一个字符串(最多50个字符的字母数字) value是一个字符串(最多100个字符) service_reregister(**payload) service_unregister(**payload) access_secret() account_create() account_activate() service_lookup() 1.ANCConfiguration: 自适应网络控制配置服务 HTTP API: get_policies() 获取所有策略 get_policy_by_name(name) [required]获取名字为'name'的策略 create_policy(policy) [required]创建策略 delete_policy_by_name(name) [required]删除策略 get_endpoints() 获取所有endpoints get_endpoint_by_mac_address(mac_address) [required]获取endpoint apply_endpoint_by_ip_address(policy_name, ip_address) [required]使用IP地址对端点应用策略 apply_endpoint_by_mac_address(policy_name, mac_address) [required]使用MAC地址对端点应用策略 clear_endpoint_by_mac_address(mac_address) [required] 如果端点没有应用现有的策略,返回状态将是失败 原因是MAC地址与策略不关联 get_operation_status(operation_id) [required]获取操作 WS STOMP: ANC_STATUS_TOPIC = '/topic/com.cisco.ise.config.anc.status' 2.EndpointAsset: ISE pxGrid的上下文连接特性, 这是为提供者发布资产数据到ISE, 而ISE Profiler组件充当收集的订阅者 WS STOMP: ENDPOINT_ASSET_TOPIC = '/topic/com.cisco.endpoint.asset' 3.MDM: 移动设备管理(MDM)服务 HTTP API: get_endpoints(_filter) [optional]获取端点, 可以使用可选的过滤器, 返回与指定属性匹配的条目 get_endpoint_by_mac_address(mac_address) [required] 通过MAC地址获取端点 get_endpoints_by_type(endpoint_type) [required. values: NON_COMPLIANT, REGISTERED, DISCONNECTED] 按端点类型获取端点,即不符合,已注册或已断开连接的端点 get_endpoints_by_os_type(os_type) 按操作系统类型(ANDROID,IOS或WINDOWS)获取端点 WS STOMP: MDM_ENDPOINT_TOPIC = '/topic/com.cisco.ise.mdm.endpoint' 4.ProfilerConfiguration: ISE Profiler配置 HTTP API: get_profiles() 获取所有profiler配置 WS STOMP: PROFILER_TOPIC = '/topic/com.cisco.ise.config.profiler' 5.RadiusFailure: 该服务提供有关Radius协议的信息 HTTP API: get_failures(start_timestamp) [ISO8601 Datetime (optional)] 获取startTimestamp以后的Radius身份验证失败的数据 如果未指定start_timestamp, 则返回上一小时的失败的数据 get_failure_by_id(_id) [required]获取具有指定ID的失败对象 WS STOMP: RADIUS_FAILURE_TOPIC = '/topic/com.cisco.ise.radius.failure' 6.SessionDirectory: 此服务提供对ISE会话目录的访问 HTTP API: get_sessions(start_timestamp) [ISO8601 Datetime (optional)] 获取所有会话, 在请求中可以选择使用start_timestamp来获取比时间戳更新的会话 get_session_by_ip_address(ip_address) [required]获取指定IP地址的会话 get_session_by_mac_address(mac_address) [required]获取指定MAC地址的会话 get_user_groups() 获取所有用户组 get_user_group_by_username(username) [required]获取指定用户的组 WS STOMP: SESSION_TOPIC = '/topic/com.cisco.ise.session' SESSION_GROUP_TOPIC = '/topic/com.cisco.ise.session.group' 7.SystemHealth: ISE系统健康服务 HTTP API: get_healths(node_name, start_timestamp) [node_name(optional), start_timestamp(optional)] 8.TrustSec: ISE TrustSec服务。 当前它提供SGACL下载的状态 WS STOMP: TRUSTSEC_POLICY_DOWNLOAD_TOPIC = '/topic/com.cisco.ise.trustsec.policy.download' 9.TrustSecConfiguration: 提供了TrustSec的配置 HTTP API: get_security_groups(group_id) [optional]用于获取安全组, 可以指定安全组ID。 get_security_group_acls(group_id) [optional]用于获取安全组ACL, 可以指定安全组ACL的ID。 如果未指定, 则返回所有安全组ACL get_egress_policies() 获取出口策略, egressPolicies get_egress_matrices() 获取出口策略, egressMatrices WS STOMP: TRUSTSEC_SECURITY_GROUP_TOPIC = '/topic/com.cisco.ise.config.trustsec.security.group' TRUSTSEC_SECURITY_GROUP_ACL_TOPIC = '/topic/com.cisco.ise.config.trustsec.security.group.acl' 10.TrustSecSXP: ISE SXP服务 HTTP API: get_bindings() WS STOMP: SXP_BINDING_TOPIC = '/topic/com.cisco.ise.sxp.binding' ''' ANCConfiguration = ANCConfiguration EndpointAsset = EndpointAsset Endpoint = Endpoint MDM = MDM ProfilerConfiguration = ProfilerConfiguration RadiusFailure = RadiusFailure SessionDirectory = SessionDirectory SystemHealth = SystemHealth TrustSec = TrustSec TrustSecConfiguration = TrustSecConfiguration TrustSecSXP = TrustSecSXP
subscribe_test.py
from pxgrid import PxGrid, Config import json import time import asyncio def callback_session(message): print(json.dumps(message, indent=4)) def callback_radius_failure(message): print(json.dumps(message, indent=4)) def callback_endpoint(message): print(json.dumps(message, indent=4)) def test(): anc = PxGrid.EndpointAsset(config) print(anc.get_endpoint_by_mac_address('34:AB:37:F2:8D:A2')) return endpoint = PxGrid.Endpoint(config) print(endpoint) loop = asyncio.get_event_loop() task_endpoint = asyncio.ensure_future( endpoint.subscribe_loop(topic=endpoint.ENDPOINT_TOPIC, callback=callback_radius_failure) ) # Setup signal handlers # loop.add_signal_handler(signal.SIGINT, task_session.cancel) # loop.add_signal_handler(signal.SIGTERM, task_session.cancel) # Event loop tasks = [ task_endpoint, # task_radius ] loop.run_until_complete(asyncio.wait(tasks)) def main(): session = PxGrid.SessionDirectory(config=config) while session.account_activate()['accountState'] != 'ENABLED': time.sleep(60) loop = asyncio.get_event_loop() task_session = asyncio.ensure_future( session.subscribe_loop(topic=session.SESSION_TOPIC, callback=callback_session) ) radius = PxGrid.RadiusFailure(config=config) task_radius = asyncio.ensure_future( radius.subscribe_loop(topic=radius.RADIUS_FAILURE_TOPIC, callback=callback_radius_failure) ) # Setup signal handlers # loop.add_signal_handler(signal.SIGINT, task_session.cancel) # loop.add_signal_handler(signal.SIGTERM, task_session.cancel) # Event loop tasks = [ task_session, # task_radius ] loop.run_until_complete(asyncio.wait(tasks)) if __name__ == '__main__': config = Config( hostname='10.96.83.245', username='python_test', password='password', description='python test', server_cert=r'certs/CertificateServicesRootCA-ISE-PAN-CNBJ_.cer' ) test()