def wxrouter_customer_service(self, msg, gdata = None, wechat = None, isp_code = None, **kwargs): """ 帮助信息 """ yield articles = [] mp_domain_addr = gdata.get_param_value('mp_domain_addr') if not mp_domain_addr: logger.error(u'未设置微信公众号域名') defer.returnValue(wechat.response_news(articles)) article1 = Storage() article1.title = u'账号管理' article1.description = '' article1.url = '%s/mps/userbind' % mp_domain_addr article1.picurl = '' articles.append(article1) article2 = Storage() article2.title = u'交易记录' article2.description = '' article2.url = '%s/mps/userorder' % mp_domain_addr article2.picurl = '' articles.append(article2) article3 = Storage() article3.title = u'密码修改' article3.description = '' article3.url = '%s/mps/useruppw' % mp_domain_addr article3.picurl = '' articles.append(article3) article4 = Storage() article4.title = u'资费套餐' article4.description = '' article4.url = '%s/mps/products' % mp_domain_addr article4.picurl = '' articles.append(article4) defer.returnValue(wechat.response_news(articles))
def post(self): try: pic_path = os.path.join(os.path.dirname(taurusxradius.__file__), 'static/pics') try: if not os.path.exists(pic_path): os.makedirs(pic_path) except: pass f = self.request.files['Filedata'][0] filename = os.path.basename(utils.safestr(f['filename'])) savename = 'pic{0}_{1}'.format(tools.gen_num_id(13), filename) save_path = os.path.join(pic_path, savename) tf = open(save_path, 'wb') tf.write(f['body']) tf.close() if not safefile.isimg(save_path): os.remove(save_path) logger.error('error upload file %s' % save_path) self.write(u'上传的文件不是图片类型') return logger.info('write {0}'.format(save_path)) self.write(u'upload ok') except Exception as err: logger.error(err) self.write(u'上传失败 %s' % utils.safeunicode(err))
def disconnect(self): try: is_chap = self.settings.config.portal.chap in (1, '1', 'chap') userIp = self.current_user.ipaddr nas = self.get_nas(self.current_user.nasaddr) ac_addr = nas['ip_addr'] ac_port = int(nas['ac_port']) secret = utils.safestr(nas['bas_secret']) _vendor = utils.safestr(nas['portal_vendor']) if _vendor not in ('cmccv1', 'cmccv2', 'huaweiv1', 'huaweiv2'): defer.returnValue('not support vendor %s' % _vendor) send_portal = functools.partial(client.send, secret, log=self.syslog, debug=self.settings.config.debug, vendor=_vendor) vendor = client.PortalClient.vendors.get(_vendor) logout_req = vendor.proto.newReqLogout(userIp, secret, chap=is_chap) logout_resp = yield send_portal(data=logout_req, host=ac_addr, port=ac_port) if logout_resp.errCode > 0: _err_msg = u'{0},{1}'.format( vendor.mod.AckLogoutErrs[logout_resp.errCode], utils.safeunicode(logout_resp.get_text_info()[0] or '')) logger.error(_err_msg) defer.returnValue('disconnect done!') except Exception as err: defer.returnValue(err)
def post(self): try: xml_str = self.request.body ret, ret_dict = self.wxpay.verify_notify(xml_str) if not ret: logger.error('order verify_notify failure', trace='wxpay') self.write(self.wxpay.generate_notify_resp(self.failure)) return order_id = ret_dict['out_trade_no'] order_fee = ret_dict['total_fee'] attach = ret_dict['attach'] order = self.db.query(models.TrCustomerOrder).get(order_id) if order and order.pay_status == 1: logger.error(u'order %s already process' % order_id, trace='wxpay') self.write(self.wxpay.generate_notify_resp(self.success)) return formdata = self.paycache.get(order_wxpaycaache_key(order_id)) if not formdata: raise ValueError('order %s not exists' % order_id) if attach == 'neworder': self.do_new_order(formdata) elif attach == 'reneworder': self.do_renew_order(formdata) elif attach == 'rechargeorder': self.do_recharge_order(formdata) else: raise ValueError('unknow order %s' % order_id) except Exception as err: logger.exception(err, trace='wxpay') self.write(self.wxpay.generate_notify_resp(self.failure))
def post(self, order_type): isok = self.alipay.notify_verify(self.get_params()) if not isok: self.write('failure') logger.info(u'收到支付宝订单通知,订单无效', trace='alipay', **self.get_params()) return order_id = self.get_argument('out_trade_no') if self.db.query(models.TrCustomerOrder).filter_by( order_id=order_id, pay_status=1).count() == 1: self.write('success') return formdata = self.paycache.get(order_paycaache_key(order_id)) if not formdata: logger.error(u'收到支付宝订单通知,但是本地缓存查不到订单%s' % order_id, trace='alipay') self.write('failure') return ret = False if order_type == 'new': manager = CustomerAdd(self.db, self.aes) ret = manager.add(formdata) if order_type == 'renew': manager = AccountRenew(self.db, self.aes) ret = manager.renew(formdata) if order_type == 'charge': manager = AccountChange(self.db, self.aes) ret = manager.charge(formdata) if ret: self.write('success') logger.info(u'收到支付宝订单通知,处理成功', trace='alipay', account_number=formdata.account_number, order_id=formdata.order_id) else: logger.error(u'订单处理失败', trace='alipay')
def acctounting(self): if self.is_online(self.request.nas_addr, self.request.acct_session_id): return logger.error(u'用户:%s 已经在线' % self.request.acct_session_id, tag='radius_acct_start_error') if not self.account: dispatch.pub(UNLOCK_ONLINE_EVENT, self.request.account_number, self.request.nas_addr, self.request.acct_session_id, async=True) return logger.error(u'用户:%s 不存在' % self.request.account_number, tag='radius_acct_start_error') online = Storage(account_number=self.request.account_number, nas_addr=self.request.nas_addr, acct_session_id=self.request.acct_session_id, acct_start_time=datetime.datetime.now().strftime( '%Y-%m-%d %H:%M:%S'), framed_ipaddr=self.request.framed_ipaddr, mac_addr=self.request.mac_addr or '', nas_port_id=self.request.nas_port_id, billing_times=0, input_total=0, output_total=0, start_source=STATUS_TYPE_START) self.add_online(online) logger.info(u'用户:%s 记账开始, 新增在线用户数据' % online.account_number, trace='radius', username=online.account_number)
def post(self): try: phone = self.get_argument('phone') domain = self.get_argument('domain') last_send = self.session.get('sms_last_send', 0) if last_send > 0: sec = int(time.time()) - last_send if sec < 60: self.render_json(code=1, msg=u'还需等待%s秒' % sec) return self.session['sms_last_send'] = int(time.time()) self.session.save() vcode = str(time.time()).replace('.', '')[-6:] gateway = self.get_param_value('sms_gateway') apikey = self.get_param_value('sms_api_user') apisecret = self.get_param_value('sms_api_pwd') resp = yield smsapi.send_vcode(gateway, apikey, apisecret, phone, vcode) cmanager = CustomerAdd(self.db, self.aes, config=self.settings.config) customer = cmanager.add_wlan_user(domain, phone, vcode, u'hotspot sms verify join') if not customer: logger.error(cmanager.last_error) self.render_json(code=1, msg=u'自动注册失败') return self.render_json(code=0, msg='ok') except Exception as err: logger.exception(err) self.render_json(code=1, msg=u'发送短信失败')
def load_routes(route_path = None, pkg_prefix = None): """ 加载指定目录下所有的事件模块,同时注册所有模块的时间函数 微信事件模块,必须有一个 router属性,通常为事件类的实例 比如: from twisted.internet import defer class WechatEventDispatch: @defer.inlineCallbacks def wxrouter_event_unsubscribe(self, msg, gdata=None, **kwargs): defer.returnValue("") router = WechatEventDispatch() """ evs = set((os.path.splitext(it)[0] for it in os.listdir(route_path))) for ev in [ it for it in evs ]: try: sub_module = os.path.join(route_path, ev) if os.path.isdir(sub_module): from taurusxradius.taurusxlib.permit import load_events load_events(route_path=sub_module, pkg_prefix='{0}.{1}'.format(pkg_prefix, ev)) _ev = '{0}.{1}'.format(pkg_prefix, ev) robj = importlib.import_module(_ev) if hasattr(robj, 'router'): wxrouter.register(robj.router) except Exception as err: logger.error('%s, skip module %s.%s' % (str(err), pkg_prefix, ev), trace='admin') import traceback traceback.print_exc() continue
def post(self): try: if os.environ.get('DEMO_VER'): self.write(u'这是一个演示版本,不提供此功能') return file_path = os.path.join(os.path.dirname(taurusxradius.__file__), 'static/dnsv') try: if not os.path.exists(file_path): os.makedirs(file_path) except: pass f = self.request.files['Filedata'][0] filename = os.path.basename(utils.safestr(f['filename'])) save_path = os.path.join(file_path, filename) tf = open(save_path, 'wb') filestr = f['body'] tf.write(filestr.strip()) tf.close() logger.info('write {0}'.format(save_path)) self.write(u'上传完成') except Exception as err: logger.error(err) self.write(u'上传失败 %s' % utils.safeunicode(err))
def password(self, formdata, **kwargs): """用户密码修改 :param formdata: 密码修改参数表 :type formdata: dict formdata params: :param account_number: 用户账号 :type account_number: string :param password: 用户新密码 :type password: string """ try: account_number = self.parse_arg(formdata, 'account_number', rule=rules.not_null) password = self.parse_arg(formdata, 'password', rule=rules.not_null) print password account = self.db.query(models.TrAccount).get(account_number) account.password = self.aes.encrypt(password) account.sync_ver = tools.gen_sync_ver() node_id = self.db.query(models.TrCustomer.node_id).filter(models.TrCustomer.customer_id == models.TrAccount.customer_id, models.TrAccount.account_number == account_number).scalar() self.add_oplog(u'修改用户%s密码 ' % account_number) self.db.commit() dispatch.pub(CACHE_DELETE_EVENT, account_cache_key(account_number), async=True) return True except Exception as err: self.db.rollback() self.last_error = u'用户修改密码失败:%s' % utils.safeunicode(err.message) logger.error(self.last_error, tag='account_uppwd_error', username=formdata.get('account_number')) return False
def sendMailaaa(self, topic, content): smtp_server = self.get_argument('smtp_server') smtp_port = self.get_argument('smtp_port') smtp_tls = self.get_argument('smtp_tls') smtp_from = self.get_argument('smtp_from') smtp_user = self.get_argument('smtp_user') smtp_pwd = self.get_argument('smtp_pwd') mail_to = self.get_argument('mail_to') msg = MIMEMultipart() msg['Subject'] = Header(topic, 'utf-8') msg['From'] = smtp_from msg['To'] = mail_to part = MIMEText(content, 'plain', 'utf-8') msg.attach(part) try: smtpServer = smtplib.SMTP(smtp_server, str(smtp_port)) except Exception as e: logger.error('SMTP连接邮件服务器失败,可能原因:' + str(e)) return False try: smtpServer.login(smtp_user, smtp_pwd) smtpServer.sendmail(smtp_from, mail_to, msg.as_string()) logger.info('send mail to:' + mail_to) except smtplib.SMTPException as e: logger.error('SMTP发送邮件失败,可能原因:' + str(e)) finally: smtpServer.quit() return True
def delete(self, account_number, **kwargs): """用户账号删除 :param account_number: 用户账号 :type account_number: string """ try: if not account_number: raise ValueError(u'账号不能为空') account = self.db.query(models.TrAccount).get(account_number) self.db.query(models.TrAcceptLog).filter_by(account_number=account.account_number).delete() self.db.query(models.TrAccountAttr).filter_by(account_number=account.account_number).delete() self.db.query(models.TrBilling).filter_by(account_number=account.account_number).delete() self.db.query(models.TrTicket).filter_by(account_number=account.account_number).delete() self.db.query(models.TrOnline).filter_by(account_number=account.account_number).delete() self.db.query(models.TrAccount).filter_by(account_number=account.account_number).delete() self.db.query(models.TrCustomerOrder).filter_by(account_number=account.account_number).delete() self.add_oplog(u'删除用户账号%s' % account.account_number) self.db.commit() dispatch.pub(ACCOUNT_DELETE_EVENT, account.account_number, async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrAcceptLog.__tablename__, dict(account_number=account.account_number)), async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrAccountAttr.__tablename__, dict(account_number=account.account_number)), async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrBilling.__tablename__, dict(account_number=account.account_number)), async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrOnline.__tablename__, dict(account_number=account.account_number)), async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrAccount.__tablename__, dict(account_number=account.account_number)), async=True) dispatch.pub(DBSYNC_STATUS_ADD, models.warp_sdel_obj(models.TrCustomerOrder.__tablename__, dict(account_number=account.account_number)), async=True) return True except Exception as err: self.db.rollback() self.last_error = u'用户删除失败:%s' % utils.safeunicode(err.message) logger.error(self.last_error, tag='account_delete_error', username=account_number) return False
def process(self, *args, **kwargs): next_interval = self.get_next_interval() user_total = 0 online_total = 0 with make_db(self.db) as db: try: user_total = db.query(models.TrAccount).count() online_total = db.query(models.TrOnline).count() except Exception as err: pass try: api_url = 'http://www.taurusxcloud.net/api/v1/ping' api_token = yield tools.get_sys_token() params = dict(token=api_token, app='taurusxee', ver=__version__, release=os.environ.get('LICENSE_TYPE', 'taurusxee'), unum=user_total, onum=online_total, dist=pf.linux_distribution()) param_str = urlencode(params) resp = yield httpclient.fetch(api_url + '?' + param_str, followRedirect=True) logger.info('taurusxcloud ping resp code: %s' % resp.code) except Exception as err: logger.error(err) defer.returnValue(next_interval)
def get(self, order_type): isok = self.alipay.notify_verify(self.get_params()) if not isok: logger.info(u'收到支付宝订单通知,订单校验无效', trace='alipay', **self.get_params()) return self.render_error(code=1, msg=u'订单校验无效') order_id = self.get_argument('out_trade_no') order = self.db.query(models.TrCustomerOrder).get(order_id) if order and order.pay_status == 1: return self.render('alipay_return.html', order=order) formdata = self.paycache.get(order_paycaache_key(order_id)) if not formdata: logger.error(u'收到支付宝订单通知,但是本地查不到订单%s' % order_id, trace='alipay') return self.render_error(code=1, msg=u'订单不存在') ret = False if order_type == 'new': manager = CustomerAdd(self.db, self.aes) ret = manager.add(formdata) if order_type == 'renew': manager = AccountRenew(self.db, self.aes) ret = manager.renew(formdata) if order_type == 'charge': manager = AccountCharge(self.db, self.aes) ret = manager.charge(formdata) if ret: order = self.db.query(models.TrCustomerOrder).get(order_id) logger.info(u'收到支付宝订单通知,处理成功', trace='alipay', account_number=formdata.account_number, order_id=order_id) self.render('alipay_return.html', order=order) else: return self.render_error(code=1, msg=u'订单处理失败 %s' % manager.last_error)
def on_reply(self, result, sync_id): try: reply = msgpack.unpackb(result[0]) code, msg = reply['code'], reply['msg'] self.repops[code](sync_id, msg=msg) except Exception as err: logger.error(traceback.format_exc())
def update(self, formdata, **kwargs): """用户账号策略修改 :param formdata: 密码修改参数表 :type formdata: dict formdata params: :param account_number: 用户账号 :type account_number: string :param ip_address: 用户IP地址 :type ip_address: string - x.x.x.x :param install_address: 用户安装地址 :type install_address: string :param domain: 用户域,对BRAS的特定扩展 :type domain: string :param user_concur_number: 用户在线数限制 :type user_concur_number: int :param bind_mac: 用户是否绑定mac :type bind_mac: int - 0 不绑定 1 绑定 :param bind_vlan: 用户是否绑定vlan :type bind_vlan: int 0 不绑定 1 绑定 :param account_desc: 用户描述 :type account_desc: string """ try: account_number = self.parse_arg(formdata, 'account_number', rule=rules.not_null) user_concur_number = self.parse_arg(formdata, 'user_concur_number', rule=rules.is_number) bind_mac = self.parse_arg(formdata, 'bind_mac', rule=rules.is_number) bind_vlan = self.parse_arg(formdata, 'bind_vlan', rule=rules.is_number) ip_address = self.parse_arg(formdata, 'ip_address') install_address = self.parse_arg(formdata, 'install_address') domain = self.parse_arg(formdata, 'domain') account_desc = self.parse_arg(formdata, 'account_desc') account = self.db.query(models.TrAccount).get(account_number) node_id = self.db.query(models.TrCustomer.node_id).filter(models.TrCustomer.customer_id == models.TrAccount.customer_id, models.TrAccount.account_number == account_number).scalar() if ip_address is not None: account.ip_address = ip_address if install_address is not None: account.install_address = install_address account.user_concur_number = user_concur_number account.bind_mac = bind_mac account.bind_vlan = bind_vlan if domain is not None: account.domain = domain if account_desc is not None: account.account_desc = account_desc account.sync_ver = tools.gen_sync_ver() self.add_oplog(u'修改上网账号信息:%s' % account.account_number) self.db.commit() dispatch.pub(CACHE_DELETE_EVENT, account_cache_key(account.account_number), async=True) return True except Exception as err: self.db.rollback() self.last_error = u'用户修改失败:%s' % utils.safeunicode(err.message) logger.error(self.last_error, tag='account_update_error', username=formdata.get('account_number')) return False return
def do_succ(self, sync_id, **kwargs): try: with self.db_engine.begin() as db: table = models.TrRepliSyncStatus.__table__ db.execute(models.TrRepliSyncStatus.__table__.delete().where( table.c.id == sync_id)) except Exception as err: logger.error(traceback.format_exc())
def dataReceived(self, msgid, request): if 'HASYNC_DISABLE' in os.environ: return try: message = msgpack.unpackb(request) self.que.appendleft([msgid, Storage(message)]) except: logger.error(traceback.print_exc())
def get_bas_ros(self, bas_id): try: api_addr, api_port, api_user, api_pwd = self.get_bas_ros_params(bas_id) if all([api_addr, api_port, api_user]): return rospool.get_client(api_addr, api_port, api_user, api_pwd) logger.error('bas sync not support', trace='routeros') except Exception as err: logger.error('ros connect fail: %s' % repr(err), trace='routeros')
def get(self): self.init_wechat() echostr = self.get_argument('echostr', '') if self.check_signature(): self.write(echostr) logger.info('Signature check success.') else: logger.error('Signature check failed.')
def onSendError(self, err, disconnect_req): try: with make_db(self.db) as db: if disconnect_req and db.query(models.TrOnline).filter_by(nas_addr=disconnect_req.nas_addr, acct_session_id=disconnect_req.acct_session_id).count() > 0: radius_acct_stop.RadiusAcctStop(self.dbengine, self.mcache, self.aes, disconnect_req).acctounting() logger.info(u'系统触发用户强制下线失败: %s; OnlineInfo: %s ' % (err.getErrorMessage(), json.dumps(disconnect_req)), trace='event') logger.error(u'send disconnect done! %s' % err.getErrorMessage()) except Exception as err: logger.exception(err)
def post(self, *args, **kwargs): """ 更新菜单,保存菜单数据为json字符串 """ menudata = self.get_argument('menudata') menu_json = json.loads(menudata) try: menu_object = {'button': []} for menu in ['menu1', 'menu2', 'menu3']: menu_buttons = {'name': menu_json['%s_name' % menu]} menu_type = menu_json.get('%s_type' % menu) menu_url = menu_json.get('%s_url' % menu) menu_key = menu_json.get('%s_key' % menu) if all([menu_type, menu_url]) or all([menu_type, menu_key ]): menu_buttons['type'] = menu_type if 'click' in menu_type: menu_buttons['key'] = menu_key else: menu_buttons['url'] = menu_url menu_object['button'].append(menu_buttons) continue menu_buttons['sub_button'] = [] for ms in range(1, 6): menu_button = {} _menu_type = menu_json['%s_sub%s_type' % (menu, ms)] _menu_name = menu_json['%s_sub%s_name' % (menu, ms)] _menu_key = menu_json['%s_sub%s_key' % (menu, ms)] _menu_url = menu_json['%s_sub%s_url' % (menu, ms)] if len(_menu_name) > 1: menu_button['type'] = _menu_type menu_button['name'] = _menu_name if 'click' in _menu_type: menu_button['key'] = _menu_key else: menu_button['url'] = _menu_url menu_buttons['sub_button'].append(menu_button) menu_object['button'].append(menu_buttons) menu_result = json.dumps(menu_object, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ': ')) logger.info(menu_result) self.cache.set(self.MpsMenuCacheKey, menu_result) _resp = self.wechat.create_menu(menu_object) if int(_resp.get('errcode')) > 0: logger.error(u'同步菜单失败,' + _resp.get('errmsg')) logger.error(menu_result) return self.render_json(code=0, msg=u'同步微信菜单失败了[%s],请检查错误再试试' % _resp.get('errmsg')) except: logger.exception(u'更新菜单失败') return self.render_json(code=0, msg=u'更新菜单失败') self.render_json(code=0, msg=u'更新菜单成功')
def process(self, *args, **kwargs): try: self.statdata.run_stat(delay=5.0) self.cache.update(radius_statcache_key, self.statdata) if self.flow_stat: self.cache.set(flow_statcache_key, self.flow_stat) except Exception as err: logger.error('radius stat process error %s' % utils.safeunicode(err.message)) return 5.0
def do_fail(self, sync_id, msg='', **kwargs): try: with self.db_engine.begin() as db: table = models.TrRepliSyncStatus.__table__ stmt = table.update().where(table.c.id == sync_id).values( last_sync=utils.get_currtime(), sync_times=table.c.sync_times + 1, sync_status=2, error=utils.safeunicode(msg)[:2000]) db.execute(stmt) except Exception as err: logger.error(traceback.format_exc())
def init_superrpc(self): """ 初始化进程管理器 """ self.superrpc = None if self.config.system.get('superrpc'): try: import xmlrpclib self.superrpc = xmlrpclib.Server(self.config.system.superrpc) os.environ['TAURUSXEE_SUPER_RPC'] = 'true' except: logger.error(traceback.format_exc()) return
def do_renew_order(self, formdata): """ 续费订单结果处理 """ manager = AccountRenew(self.db, self.aes) if manager.renew(formdata): self.write(self.wxpay.generate_notify_resp(self.success)) logger.info('reneworder process done', trace='wxpay', order_id=formdata.order_id) self.send_user_paynotify(formdata) else: logger.error(u'收到续费支付结果通知,但处理订单失败 %s' % manager.last_error, trace='wxpay')
def do_new_order(self, formdata): """ 开户订单结果处理 """ manager = CustomerAdd(self.db, self.aes) if manager.add(formdata): self.write(self.wxpay.generate_notify_resp(self.success)) logger.info('neworder process done', trace='wxpay', order_id=formdata.order_id) self.send_user_paynotify(formdata) else: logger.error(u'收到支付结果通知,但处理订单失败 %s' % manager.last_error, trace='wxpay')
def parse_form_request(self): try: return apiutils.parse_form_request( self.settings.config.system.secret, self.get_params()) except Exception as err: logger.error(u'api authorize parse error, %s' % utils.safeunicode(traceback.format_exc())) self.render_parse_err(err, msg=u'ParseRequest Error: %s' % utils.safeunicode(err.message)) return None return None
def process(self, msgid, message): datagram, host, port = msgpack.unpackb(message) reply = self.processAuth(datagram, host, port) if not reply: return if reply.code == packet.AccessReject: logger.error(u'[Radiusd] :: Send Radius Reject %s' % repr(reply), tag='radius_auth_reject') else: logger.info(u'[Radiusd] :: Send radius response: %s' % repr(reply)) if self.config.system.debug: logger.debug(reply.format_str()) self.zmqrep.reply(msgid, msgpack.packb([reply.ReplyPacket(), host, port])) self.do_stat(reply.code)
def get_all_ros(self): ros_array = [] bas_array = [] with make_db(self.db) as db: bas_array = self.db.query(models.TrBas.id).all() for bas_id, in bas_array: api_addr, api_port, api_user, api_pwd = self.get_bas_ros_params(bas_id) try: if all([api_addr, api_port, api_user]): roscli = rospool.get_client(api_addr, api_port, api_user, api_pwd) ros_array.append(roscli) except Exception as err: logger.error('ros connect fail: %s' % repr(err), trace='routeros') return ros_array