class ApiClient(): """ RestFull Client :param config: :type config: """ def __init__(self, config, log=None): self.config = config self.log = log self.protocol = 'http' self.cache = mcache.Mcache() self.zauth_conn = ZmqREQConnection(ZmqFactory()) self.zacct_conn = ZmqREQConnection(ZmqFactory()) self.init_client().addCallback(self.log.info) reactor.callLater( 1.0, self.check_api, ) @defer.inlineCallbacks def init_client(self): try: reqdata = apiutils.make_request(self.config.api.api_secret, **{}) resp = yield self.send_http( "%s/radagent/fetch" % self.config.api.api_url, reqdata) auth_endpoints = [ ZmqEndpoint('connect', e) for e in resp.get('auth_endpoints', '').split(",") ] acct_endpoints = [ ZmqEndpoint('connect', e) for e in resp.get('acct_endpoints', '').split(",") ] self.api_auth_url = resp.get("api_auth_url") self.api_acct_url = resp.get("api_acct_url") self.log.info('auth_endpoints: %s' % auth_endpoints) self.log.info('acct_endpoints: %s' % acct_endpoints) self.log.info('api_auth_url: %s' % self.api_auth_url) self.log.info('api_acct_url: %s' % self.api_acct_url) self.protocol = resp.get('protocol') self.zauth_conn.addEndpoints(auth_endpoints) self.zacct_conn.addEndpoints(acct_endpoints) defer.returnValue("ApiClient init done") except Exception as err: import traceback traceback.print_exc() self.log.error(u"[ApiClient] :: fetch radagent failure, %s" % safeunicode(err.message)) defer.returnValue("ApiClient init error") def check_api(self): try: self.log.info("ping api service") retry = lambda err: self.init_client().addCallback(self.log.info) msg = apiutils.make_request(self.config.api.api_secret, action='ping') self.send_zmq('authorize', msg).addErrback(retry) self.send_zmq('accounting', msg).addErrback(retry) except Exception as err: self.log.error("ping api service error, %s" % apiutils.safeunicode(err.message)) reactor.callLater( 30.0, self.check_api, ) @defer.inlineCallbacks def send_http(self, apiurl, reqdata): """ send radius request :param apiurl: oss server api :param reqdata: json data """ try: if self.config.defaults.debug: self.log.debug( "[HttpClient] :: Send http request to {0}, {1}".format( safestr(apiurl), safeunicode(reqdata))) headers = {"Content-Type": ["application/json;charset=utf-8"]} resp = yield requests.post(safestr(apiurl), data=reqdata, headers=headers) if resp.code != 200: defer.returnValue( dict( code=1, msg=u'server return error http status code {0}'.format( resp.code))) else: result = yield resp.json() if self.config.defaults.debug: self.log.debug( "[HttpClient] :: Received http response from {0}, {1}". format(safestr(apiurl), safeunicode(result))) if result.get('code') == 0 and not apiutils.check_sign( self.config.api.api_secret, result): defer.returnValue(dict(code=1, msg=u"sign error")) else: defer.returnValue(result) except Exception as err: import traceback traceback.print_exc() defer.returnValue(dict(code=1, msg=u'server error')) @defer.inlineCallbacks def send_zmq(self, rtype, reqdata): """ send radius request :param rtype: radius msg type :param reqdata: json data """ try: if self.config.defaults.debug: self.log.debug("[ZmqClient] :: Send zmq request {0}".format( safestr(reqdata))) resp = None if rtype == 'authorize': resp = yield self.zauth_conn.sendMsg(reqdata, timeout=15.0) elif rtype == 'accounting': resp = yield self.zacct_conn.sendMsg(reqdata, timeout=15.0) else: defer.returnValue( dict(code=1, msg=u"not support radius msg type")) if self.config.defaults.debug: self.log.debug( "[ZmqClient] :: Received zmq response {0}".format( safeunicode(resp))) result = json.loads(resp[0]) if not apiutils.check_sign(self.config.api.api_secret, result): defer.returnValue(dict(code=1, msg=u"zmq msg sign error")) defer.returnValue(result) except Exception as err: import traceback traceback.print_exc() defer.returnValue(dict(code=1, msg=u'server error')) @defer.inlineCallbacks def get_nas(self, nasaddr, nas_identify=None): _start = time.clock() cache_key = "toughengine.get_nas.{0}".format(nasaddr) if cache_key in self.cache.cache: log.msg("[get_nas cast:%.6f second (hit cache)]" % (time.clock() - _start)) defer.returnValue(self.cache.get(cache_key)) api_url = self.config.api.api_url if not api_url: raise ValueError("api_url is None") try: _reqdata = dict( nasaddr=nasaddr, nas_identify=nas_identify, ) reqdata = apiutils.make_request(self.config.api.api_secret, _reqdata) resp = yield self.send_http("%s/nas/fetch" % api_url, reqdata) if resp['code'] == 0: self.cache.set(cache_key, resp, expire=120) self.log.info("[init_nas cast:%.6f second]" % (time.clock() - _start)) defer.returnValue(resp) except Exception as err: import traceback traceback.print_exc() self.log.error(u"[HttpClient] :: fetch nas failure,%s" % safestr(err.message)) defer.returnValue( dict(code=1, msg=u"fetch nas error, please see log detail")) @defer.inlineCallbacks def authorize(self, username, domain, macaddr, nasaddr, vlanid1, vlanid2, textinfo=None): """send radius auth request :param username: not contain @doamin :param domain: :param macaddr: :param nasaddr: :param vlanid1: :param vlanid2: :param textinfo: """ _start = time.clock() try: _reqdata = dict(username=username, domain=safestr(domain), macaddr=safestr(macaddr), nasaddr=nasaddr, vlanid1=vlanid1, vlanid2=vlanid2, textinfo=safestr(textinfo)) reqdata = apiutils.make_request(self.config.api.api_secret, _reqdata) if self.protocol == 'http': resp = yield self.send_http(self.api_auth_url, reqdata) self.log.info("[http authorize cast:%.6f second]" % (time.clock() - _start)) defer.returnValue(resp) elif self.protocol == 'zmq': resp = yield self.send_zmq('authorize', reqdata) self.log.info("[zmq authorize cast:%.6f second]" % (time.clock() - _start)) defer.returnValue(resp) else: defer.returnValue(dict(code=1, msg=u"not support")) except Exception as err: import traceback traceback.print_exc() self.log.error(u"[ApiClient] :: authorize failure,%s" % safestr(err.message)) defer.returnValue( dict(code=1, msg=u"authorize error, please see log detail")) @defer.inlineCallbacks def accounting(self, req_type, username, session_id, session_time, session_timeout, macaddr, nasaddr, ipaddr, input_octets, output_octets, input_pkts, output_pkts, nas_port, event_timestamp, nas_port_type, nas_port_id, textinfo=None): """send radius accounting request :param req_type: 1 Start 2 Stop 3 Alive :param username: :param session_id: :param session_time: :param session_timeout: :param macaddr: :param nasaddr: :param ipaddr: :param input_octets: :param output_octets: :param input_pkts: :param output_pkts: :param textinfo: """ _start = time.clock() try: _reqdata = dict(req_type=req_type, username=username, session_id=session_id, session_time=session_time, session_timeout=session_timeout, macaddr=macaddr, nasaddr=nasaddr, ipaddr=ipaddr, input_octets=input_octets, output_octets=output_octets, input_pkts=input_pkts, output_pkts=output_pkts, nas_port=nas_port, event_timestamp=event_timestamp, nas_port_type=nas_port_type, nas_port_id=nas_port_id, textinfo=safestr(textinfo)) reqdata = apiutils.make_request(self.config.api.api_secret, _reqdata) if self.protocol == 'http': resp = yield self.send_http(self.api_acct_url, reqdata) self.log.info("[http accounting cast:%.6f second]" % (time.clock() - _start)) defer.returnValue(resp) elif self.protocol == 'zmq': resp = yield self.send_zmq('accounting', reqdata) self.log.info("[zmq accounting cast:%.6f second]" % (time.clock() - _start)) defer.returnValue(resp) else: defer.returnValue(dict(code=1, msg=u"not support")) except Exception as err: self.log.error(u"[HttpClient] :: accounting failure,%s" % safestr(err.message)) defer.returnValue( dict(code=1, msg=u"accounting error, please see log detail"))