接入自建redis与华为云redis同步。
parent
341d305ae7
commit
bc8defae7f
|
@ -7,7 +7,7 @@ skey_path = 'ConsulManager/assets/secret/skey'
|
|||
if consul_kv.get_kv_dict(skey_path) == {}:
|
||||
consul_kv.put_kv(skey_path,{'sk':''.join(str(uuid.uuid4()).split('-'))})
|
||||
|
||||
from views import login, blackbox, consul, jobs, nodes, selfnode, selfrds, avd, exp, jms, edit_cloud, ldap, rds
|
||||
from views import login, blackbox, consul, jobs, nodes, selfnode, selfrds, selfredis, avd, exp, jms, edit_cloud, ldap, rds, redis
|
||||
from views.prom import cloud_mysql_metrics
|
||||
from units.cloud import huaweicloud,alicloud,tencent_cloud
|
||||
from units.avd import avd_list
|
||||
|
@ -24,6 +24,7 @@ app.register_blueprint(jobs.blueprint)
|
|||
app.register_blueprint(nodes.blueprint)
|
||||
app.register_blueprint(selfnode.blueprint)
|
||||
app.register_blueprint(selfrds.blueprint)
|
||||
app.register_blueprint(selfredis.blueprint)
|
||||
app.register_blueprint(avd.blueprint)
|
||||
app.register_blueprint(exp.blueprint)
|
||||
app.register_blueprint(jms.blueprint)
|
||||
|
@ -31,6 +32,8 @@ app.register_blueprint(edit_cloud.blueprint)
|
|||
app.register_blueprint(cloud_mysql_metrics.blueprint)
|
||||
app.register_blueprint(ldap.blueprint)
|
||||
app.register_blueprint(rds.blueprint)
|
||||
app.register_blueprint(redis.blueprint)
|
||||
|
||||
class Config(object):
|
||||
JOBS = []
|
||||
SCHEDULER_API_ENABLED = True
|
||||
|
|
|
@ -11,12 +11,13 @@ xlrd==1.2.0
|
|||
pycryptodome==3.14.1
|
||||
beautifulsoup4==4.11.1
|
||||
ldap3==2.9.1
|
||||
huaweicloudsdkcore==3.1.8
|
||||
huaweicloudsdkecs==3.1.8
|
||||
huaweicloudsdkeps==3.1.8
|
||||
huaweicloudsdkbss==3.1.8
|
||||
huaweicloudsdkrds==3.1.8
|
||||
huaweicloudsdkces==3.1.8
|
||||
huaweicloudsdkcore==3.1.11
|
||||
huaweicloudsdkecs==3.1.11
|
||||
huaweicloudsdkeps==3.1.11
|
||||
huaweicloudsdkbss==3.1.11
|
||||
huaweicloudsdkrds==3.1.11
|
||||
huaweicloudsdkces==3.1.11
|
||||
huaweicloudsdkdcs==3.1.11
|
||||
alibabacloud_resourcemanager20200331==2.1.1
|
||||
alibabacloud_ecs20140526==2.1.1
|
||||
alibabacloud_rds20140815==2.1.1
|
||||
|
|
|
@ -8,10 +8,13 @@ from huaweicloudsdkecs.v2 import *
|
|||
from huaweicloudsdkecs.v2.region.ecs_region import EcsRegion
|
||||
from huaweicloudsdkrds.v3 import *
|
||||
from huaweicloudsdkrds.v3.region.rds_region import RdsRegion
|
||||
from huaweicloudsdkdcs.v2 import *
|
||||
from huaweicloudsdkdcs.v2.region.dcs_region import DcsRegion
|
||||
import sys,datetime,hashlib
|
||||
from units import consul_kv
|
||||
from units.cloud import sync_ecs
|
||||
from units.cloud import sync_rds
|
||||
from units.cloud import sync_redis
|
||||
from units.cloud import notify
|
||||
|
||||
def exp(account,collect_days,notify_days,notify_amount):
|
||||
|
@ -220,3 +223,53 @@ def rds(account,region):
|
|||
except Exception as e:
|
||||
data = {'count':'无','update':f'失败','status':50000,'msg':str(e)}
|
||||
consul_kv.put_kv(f'ConsulManager/record/jobs/huaweicloud/{account}/rds/{region}', data)
|
||||
|
||||
def redis(account,region):
|
||||
ak,sk = consul_kv.get_aksk('huaweicloud',account)
|
||||
now = datetime.datetime.now().strftime('%m.%d/%H:%M')
|
||||
group_dict = consul_kv.get_value(f'ConsulManager/assets/huaweicloud/group/{account}')
|
||||
credentials = BasicCredentials(ak, sk)
|
||||
try:
|
||||
client = DcsClient.new_builder() \
|
||||
.with_credentials(credentials) \
|
||||
.with_region(DcsRegion.value_of(region)) \
|
||||
.build()
|
||||
request = ListInstancesRequest()
|
||||
request.include_failure = "false"
|
||||
request.include_delete = "false"
|
||||
request.limit = 1000
|
||||
info = client.list_instances(request).to_dict()['instances']
|
||||
|
||||
redis_dict = {i['instance_id']:{'name':i['name'],
|
||||
'domain':i['domain_name'],
|
||||
'ip':i['ip'],
|
||||
'port':i['port'],
|
||||
'region':region,
|
||||
'group':group_dict[i['enterprise_project_id']],
|
||||
'status':i['status'],
|
||||
'itype':i['spec_code'],
|
||||
'ver':i['engine_version'],
|
||||
'mem':f"{i['max_memory']}MB",
|
||||
'exp': '-'
|
||||
} for i in info}
|
||||
count = len(redis_dict)
|
||||
off,on = sync_redis.w2consul('huaweicloud',account,region,redis_dict)
|
||||
data = {'count':count,'update':now,'status':20000,'on':on,'off':off,'msg':f'REDIS同步成功!总数:{count},开机:{on},关机:{off}'}
|
||||
consul_kv.put_kv(f'ConsulManager/record/jobs/huaweicloud/{account}/redis/{region}', data)
|
||||
print('【JOB】===>', 'huaweicloud_redis', account,region, data, flush=True)
|
||||
except exceptions.ClientRequestException as e:
|
||||
print(e.status_code, flush=True)
|
||||
print(e.request_id, flush=True)
|
||||
print(e.error_code, flush=True)
|
||||
print(e.error_msg, flush=True)
|
||||
data = consul_kv.get_value(f'ConsulManager/record/jobs/huaweicloud/{account}/redis/{region}')
|
||||
if data == {}:
|
||||
data = {'count':'无','update':f'失败{e.status_code}','status':50000,'on':0,'off':0,'msg':e.error_msg}
|
||||
else:
|
||||
data['update'] = f'失败{e.status_code}'
|
||||
data['msg'] = e.error_msg
|
||||
consul_kv.put_kv(f'ConsulManager/record/jobs/huaweicloud/{account}/redis/{region}', data)
|
||||
except Exception as e:
|
||||
data = {'count':'无','update':f'失败','status':50000,'msg':str(e)}
|
||||
consul_kv.put_kv(f'ConsulManager/record/jobs/huaweicloud/{account}/redis/{region}', data)
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/python3
|
||||
import requests,json
|
||||
from units import consul_kv
|
||||
from config import consul_token,consul_url,vendors,regions
|
||||
headers = {'X-Consul-Token': consul_token}
|
||||
geturl = f'{consul_url}/agent/services'
|
||||
delurl = f'{consul_url}/agent/service/deregister'
|
||||
puturl = f'{consul_url}/agent/service/register'
|
||||
def w2consul(vendor,account,region,redis_dict):
|
||||
service_name = f'{vendor}_{account}_redis'
|
||||
params = {'filter': f'Service == "{service_name}" and "{region}" in Tags and Meta.account == "{account}"'}
|
||||
try:
|
||||
consul_redis_iid_list = requests.get(geturl, headers=headers, params=params).json().keys()
|
||||
except:
|
||||
consul_redis_iid_list = []
|
||||
|
||||
#在consul中删除云厂商不存在的redis
|
||||
for del_redis in [x for x in consul_redis_iid_list if x not in redis_dict.keys()]:
|
||||
dereg = requests.put(f'{delurl}/{del_redis}', headers=headers)
|
||||
if dereg.status_code == 200:
|
||||
print({"code": 20000,"data": f"{account}-删除成功!"}, flush=True)
|
||||
else:
|
||||
print({"code": 50000,"data": f'{dereg.status_code}:{dereg.text}'}, flush=True)
|
||||
off,on = 0,0
|
||||
for k,v in redis_dict.items():
|
||||
iid = k
|
||||
#对consul中关机的redis做标记。
|
||||
if v['status'] in ['SHUTDOWN']:
|
||||
off = off + 1
|
||||
tags = ['shutoff',v['itype'],v['ver'], region]
|
||||
stat = 'off'
|
||||
else:
|
||||
on = on + 1
|
||||
tags = [v['itype'],v['ver'],region]
|
||||
stat = 'on'
|
||||
custom_redis = consul_kv.get_value(f'ConsulManager/assets/sync_redis_custom/{iid}')
|
||||
port = custom_redis.get('port')
|
||||
ip = custom_redis.get('ip')
|
||||
if port == None:
|
||||
port = v['port']
|
||||
if ip == None:
|
||||
ip = v['ip']
|
||||
instance = f'{ip}:{port}'
|
||||
data = {
|
||||
'id': iid,
|
||||
'name': service_name,
|
||||
'Address': ip,
|
||||
'port': port,
|
||||
'tags': tags,
|
||||
'Meta': {
|
||||
'iid': iid,
|
||||
'name': v['name'],
|
||||
'region': regions[vendor].get(region,'未找到'),
|
||||
'group': v['group'],
|
||||
'instance': instance,
|
||||
'account': account,
|
||||
'itype': v['itype'],
|
||||
'vendor': vendors.get(vendor,'未找到'),
|
||||
'mem': v['mem'],
|
||||
'ver': v['ver'],
|
||||
'domain':v['domain'],
|
||||
'stat': stat
|
||||
},
|
||||
"check": {
|
||||
"tcp": f"{ip}:{port}",
|
||||
"interval": "60s"
|
||||
}
|
||||
}
|
||||
reg = requests.put(puturl, headers=headers, data=json.dumps(data))
|
||||
if reg.status_code == 200:
|
||||
pass
|
||||
#print({f"{account}:code": 20000,"data": "增加成功!"}, flush=True)
|
||||
else:
|
||||
print({f"{account}:code": 50000,"data": f'{reg.status_code}:{reg.text}'}, flush=True)
|
||||
#return {"code": 50000,"data": f'{reg.status_code}:{reg.text}'}
|
||||
return off,on
|
|
@ -0,0 +1,72 @@
|
|||
import requests,json
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from config import consul_token,consul_url
|
||||
|
||||
headers = {'X-Consul-Token': consul_token}
|
||||
|
||||
def get_all_list(vendor,account,region,group):
|
||||
vendor = f'and Meta.vendor=="{vendor}"' if vendor != '' else f'and Meta.vendor != ""'
|
||||
account = f'and Meta.account=="{account}"' if account != '' else f'and Meta.account != ""'
|
||||
region = f'and Meta.region=="{region}"' if region != '' else f'and Meta.region != ""'
|
||||
group = f'and Meta.group=="{group}"' if group != '' else f'and Meta.group != ""'
|
||||
url = f'{consul_url}/agent/services?filter=Service == selfredis_exporter {vendor} {account} {region} {group}'
|
||||
response = requests.get(url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
info = response.json()
|
||||
all_list = [i['Meta'] for i in info.values()]
|
||||
vendor_list = sorted(list(set([i['vendor'] for i in all_list])))
|
||||
account_list = sorted(list(set([i['account'] for i in all_list])))
|
||||
region_list = sorted(list(set([i['region'] for i in all_list])))
|
||||
group_list = sorted(list(set([i['group'] for i in all_list])))
|
||||
return {'code': 20000,'all_list':all_list,'vendor_list':vendor_list,
|
||||
'account_list':account_list,'region_list':region_list,'group_list':group_list}
|
||||
else:
|
||||
return {'code': 50000, 'data': f'{response.status_code}:{response.text}'}
|
||||
|
||||
def get_service():
|
||||
response = requests.get(f'{consul_url}/agent/services?filter=Service == selfredis_exporter', headers=headers)
|
||||
if response.status_code == 200:
|
||||
info = response.json()
|
||||
all_list = [i['Meta'] for i in info.values()]
|
||||
vendor_list = sorted(list(set([i['vendor'] for i in all_list])))
|
||||
account_list = sorted(list(set([i['account'] for i in all_list])))
|
||||
region_list = sorted(list(set([i['region'] for i in all_list])))
|
||||
group_list = sorted(list(set([i['group'] for i in all_list])))
|
||||
return {'code': 20000,'all_list':all_list,'vendor_list':vendor_list,
|
||||
'account_list':account_list,'region_list':region_list,'group_list':group_list}
|
||||
else:
|
||||
return {'code': 50000, 'data': f'{response.status_code}:{response.text}'}
|
||||
|
||||
def add_service(vendor,account,region,group,name,ip,port,os):
|
||||
if port is None or name is None:
|
||||
return {"code": 50000, "data": f"名称或IP不能为空!"}
|
||||
sid = f"{vendor}/{account}/{region}/{group}@{name}"
|
||||
instance = f'{ip}:{port}'
|
||||
if '//' in sid or sid.startswith('/') or sid.endswith('/'):
|
||||
return {"code": 50000, "data": f"服务ID【{sid}】首尾不能包含'/',并且不能包含两个连续的'/'"}
|
||||
data = {
|
||||
"id": sid,
|
||||
"name": 'selfredis_exporter',
|
||||
'Address': ip,
|
||||
'port': int(port),
|
||||
"tags": [vendor,os],
|
||||
"Meta": {'vendor':vendor,'account':account,'region':region,'group':group,
|
||||
'name':name,'instance':instance,'os':os},
|
||||
"check": {"tcp": instance,"interval": "60s"}
|
||||
}
|
||||
reg = requests.put(f'{consul_url}/agent/service/register', headers=headers, data=json.dumps(data))
|
||||
if reg.status_code == 200:
|
||||
return {"code": 20000, "data": f"【{sid}】增加成功!"}
|
||||
else:
|
||||
return {"code": 50000, "data": f"{reg.status_code}【{sid}】{reg.text}"}
|
||||
|
||||
def del_service(vendor,account,region,group,name):
|
||||
sid = f"{vendor}/{account}/{region}/{group}@{name}"
|
||||
reg = requests.put(f'{consul_url}/agent/service/deregister/{sid}', headers=headers)
|
||||
if reg.status_code == 200:
|
||||
return {"code": 20000, "data": f"【{sid}】删除成功!"}
|
||||
else:
|
||||
print(f"{reg.status_code}【{sid}】{reg.text}")
|
||||
return {"code": 50000, "data": f"{reg.status_code}【{sid}】{reg.text}"}
|
||||
|
|
@ -47,6 +47,22 @@ def importconsul(row,imptype):
|
|||
'name':name,'instance':instance,'os':os},
|
||||
"check": {"tcp": instance,"interval": "60s"}
|
||||
}
|
||||
elif imptype == 'selfredis':
|
||||
vendor,account,region,group,name,instance,os = row
|
||||
print(row)
|
||||
sid = f"{vendor}/{account}/{region}/{group}@{name}"
|
||||
ip = instance.split(':')[0]
|
||||
port = instance.split(':')[1]
|
||||
data = {
|
||||
"id": sid,
|
||||
"name": 'selfredis_exporter',
|
||||
'Address': ip,
|
||||
'port': int(port),
|
||||
"tags": [vendor,os],
|
||||
"Meta": {'vendor':vendor,'account':account,'region':region,'group':group,
|
||||
'name':name,'instance':instance,'os':os},
|
||||
"check": {"tcp": instance,"interval": "60s"}
|
||||
}
|
||||
except Exception as e:
|
||||
print("【import】导入失败",e,flush=True)
|
||||
return {"code": 50000, "data": f"导入内容格式异常!{row}"}
|
||||
|
|
|
@ -58,6 +58,7 @@ class Edit(Resource):
|
|||
proj_interval = int(editjob_dict['proj_interval'])
|
||||
ecs_interval = int(editjob_dict['ecs_interval'])
|
||||
rds_interval = int(editjob_dict['rds_interval'])
|
||||
redis_interval = int(editjob_dict['redis_interval'])
|
||||
print(editjob_dict)
|
||||
if editjob_dict['akskswitch']:
|
||||
ak = editjob_dict['ak']
|
||||
|
@ -73,6 +74,7 @@ class Edit(Resource):
|
|||
|
||||
ecs_jobid = f'{vendor}/{account}/ecs/{region}'
|
||||
rds_jobid = f'{vendor}/{account}/rds/{region}'
|
||||
redis_jobid = f'{vendor}/{account}/redis/{region}'
|
||||
if 'ecs' in restype:
|
||||
isecs = [x for x in self.job_list if x['id'] == f'{vendor}/{account}/ecs/{region}']
|
||||
if len(isecs) == 1:
|
||||
|
@ -82,7 +84,10 @@ class Edit(Resource):
|
|||
modjob_interval(ecs_jobid,ecs_interval)
|
||||
|
||||
if len(isecs[0]['args']) != 3 or isextip != isecs[0]['args'][2]:
|
||||
isecs[0]['args'][2] = isextip
|
||||
try:
|
||||
isecs[0]['args'][2] = isextip
|
||||
except:
|
||||
isecs[0]['args'].append(isextip)
|
||||
consul_kv.put_kv(f'ConsulManager/jobs/{ecs_jobid}',isecs[0])
|
||||
modjob_args(ecs_jobid,isecs[0]['args'])
|
||||
else:
|
||||
|
@ -121,5 +126,28 @@ class Edit(Resource):
|
|||
deljob(rds_jobid)
|
||||
except:
|
||||
pass
|
||||
|
||||
if 'redis' in restype:
|
||||
isredis = [x for x in self.job_list if x['id'] == f'{vendor}/{account}/redis/{region}']
|
||||
if len(isredis) == 1:
|
||||
if redis_interval != isredis[0]['minutes']:
|
||||
isredis[0]['minutes'] = redis_interval
|
||||
consul_kv.put_kv(f'ConsulManager/jobs/{redis_jobid}',isredis[0])
|
||||
modjob_interval(redis_jobid,redis_interval)
|
||||
else:
|
||||
job_func = f"__main__:{vendor}.redis"
|
||||
job_args = [account,region]
|
||||
job_interval = redis_interval
|
||||
addjob(redis_jobid, job_func, job_args, job_interval)
|
||||
job_dict = {'id':redis_jobid,'func':job_func,'args':job_args,'minutes':job_interval,
|
||||
"trigger": "interval","replace_existing": True}
|
||||
consul_kv.put_kv(f'ConsulManager/jobs/{redis_jobid}',job_dict)
|
||||
else:
|
||||
try:
|
||||
consul_kv.del_key(f'ConsulManager/jobs/{redis_jobid}')
|
||||
deljob(redis_jobid)
|
||||
except:
|
||||
pass
|
||||
|
||||
return {'code': 20000, 'data': f'{vendor}/{account}/{region}:编辑成功!'}
|
||||
api.add_resource(Edit, '/api/edit/<stype>')
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
from flask import Blueprint
|
||||
from flask_restful import reqparse, Resource, Api
|
||||
from flask_apscheduler import APScheduler
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
from units import token_auth,consul_kv,gen_config,consul_svc
|
||||
|
||||
blueprint = Blueprint('redis',__name__)
|
||||
api = Api(blueprint)
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('job_id',type=str)
|
||||
parser.add_argument('services_dict',type=dict)
|
||||
parser.add_argument('cst_redis_dict',type=dict)
|
||||
parser.add_argument('iid',type=str)
|
||||
parser.add_argument('jobredis_name',type=str)
|
||||
parser.add_argument('checked',type=str)
|
||||
|
||||
class Redis(Resource):
|
||||
decorators = [token_auth.auth.login_required]
|
||||
def get(self, stype):
|
||||
job_id = parser.parse_args()['job_id']
|
||||
if stype == 'jobredis':
|
||||
jobredis = consul_kv.get_keys_list('ConsulManager/jobs')
|
||||
jobredis_list = [i.split('/jobs/')[1] for i in jobredis if '/redis/' in i]
|
||||
return {'code': 20000,'jobredis':jobredis_list}
|
||||
elif stype == 'redis_services':
|
||||
jobecs = consul_kv.get_keys_list('ConsulManager/jobs')
|
||||
jobecs_list = [i.split('/jobs/')[1] for i in jobecs if '/redis/' in i]
|
||||
services_list = []
|
||||
for i in jobecs_list:
|
||||
serivces = i.split("/")
|
||||
services_list.append(f'{serivces[0]}_{serivces[1]}_{serivces[2]}')
|
||||
return {'code': 20000,'services_list': sorted(set(services_list))}
|
||||
elif stype == 'redisrules':
|
||||
return gen_config.get_redisrules()
|
||||
elif stype == 'cstredisconf':
|
||||
args = parser.parse_args()
|
||||
iid = args['iid']
|
||||
cst_redis_config = consul_kv.get_value(f'ConsulManager/assets/sync_redis_custom/{iid}')
|
||||
cst_redis_config.update({'iid': iid,'ipswitch': False,'portswitch': False})
|
||||
if 'ip' in cst_redis_config and cst_redis_config['ip'] != '':
|
||||
cst_redis_config['ipswitch'] = True
|
||||
if 'port' in cst_redis_config and cst_redis_config['port'] != '':
|
||||
cst_redis_config['portswitch'] = True
|
||||
return {'code': 20000, 'cst_redis': cst_redis_config}
|
||||
elif stype == 'cstredislist':
|
||||
args = parser.parse_args()
|
||||
jobredis_name = args['jobredis_name']
|
||||
checked = args['checked']
|
||||
cst_redis_dict = consul_kv.get_kv_dict('ConsulManager/assets/sync_redis_custom/')
|
||||
cst_redis_keylist = [k.split('/')[-1] for k,v in cst_redis_dict.items() if v != {}]
|
||||
redis_info = consul_kv.get_res_services(jobredis_name)
|
||||
if checked == 'false':
|
||||
return redis_info
|
||||
else:
|
||||
cst_redis_list = [i for i in redis_info['res_list'] if i['iid'] in cst_redis_keylist]
|
||||
return {'code': 20000, 'res_list': cst_redis_list}
|
||||
|
||||
def post(self, stype):
|
||||
if stype == 'redispconfig':
|
||||
args = parser.parse_args()
|
||||
services_dict = args['services_dict']
|
||||
return gen_config.redis_config(services_dict['jobredis_list'],services_dict['cm_exporter'],services_dict['services_list'],services_dict['exporter'])
|
||||
elif stype == 'cstredis':
|
||||
args = parser.parse_args()
|
||||
cst_redis_dict = args['cst_redis_dict']
|
||||
consul_redis_cst = {}
|
||||
iid = cst_redis_dict['iid']
|
||||
try:
|
||||
sid_dict = consul_svc.get_sid(iid)['instance']
|
||||
if cst_redis_dict['portswitch'] and cst_redis_dict['port'] != '':
|
||||
consul_redis_cst['port'] = int(cst_redis_dict['port'])
|
||||
sid_dict['Port'] = consul_redis_cst['port']
|
||||
if cst_redis_dict['ipswitch'] and cst_redis_dict['ip'] != '':
|
||||
consul_redis_cst['ip'] = cst_redis_dict['ip']
|
||||
sid_dict['Address'] = consul_redis_cst['ip']
|
||||
consul_kv.put_kv(f'ConsulManager/assets/sync_redis_custom/{iid}',consul_redis_cst)
|
||||
del sid_dict['Weights']
|
||||
del sid_dict['ContentHash']
|
||||
del sid_dict['Datacenter']
|
||||
sid_dict['name'] = sid_dict.pop('Service')
|
||||
sid_dict['Meta']['instance'] = f"{sid_dict['Address']}:{sid_dict['Port']}"
|
||||
sid_dict["check"] = { "tcp": sid_dict['Meta']['instance'],"interval": "60s" }
|
||||
consul_svc.del_sid(iid)
|
||||
consul_svc.add_sid(sid_dict)
|
||||
return {'code': 20000, 'data': '自定义实例信息修改成功!'}
|
||||
except Exception as e:
|
||||
print(e,flush=True)
|
||||
return {'code': 50000, "data": '提交自定义实例信息格式错误!'}
|
||||
|
||||
api.add_resource(Redis, '/api/redis/<stype>')
|
|
@ -0,0 +1,69 @@
|
|||
from flask import Blueprint
|
||||
from flask_restful import reqparse, Resource, Api
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from units import token_auth,selfredis_manager
|
||||
from werkzeug.datastructures import FileStorage
|
||||
from units import upload
|
||||
|
||||
blueprint = Blueprint('selfredis',__name__)
|
||||
api = Api(blueprint)
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('vendor',type=str)
|
||||
parser.add_argument('account',type=str)
|
||||
parser.add_argument('region',type=str)
|
||||
parser.add_argument('group',type=str)
|
||||
parser.add_argument('name',type=str)
|
||||
parser.add_argument('ip',type=str)
|
||||
parser.add_argument('port',type=str)
|
||||
parser.add_argument('os',type=str)
|
||||
parser.add_argument('del_dict',type=dict)
|
||||
parser.add_argument('up_dict',type=dict)
|
||||
parser.add_argument('file',type=FileStorage, location="files", help="File is wrong.")
|
||||
|
||||
class Upload(Resource):
|
||||
@token_auth.auth.login_required
|
||||
def post(self):
|
||||
file = parser.parse_args().get("file")
|
||||
try:
|
||||
return upload.read_execl(file.read(),'selfredis')
|
||||
except Exception as e:
|
||||
print("【selfredis】导入失败",e,flush=True)
|
||||
return {"code": 50000, "data": f"导入失败!"}
|
||||
|
||||
class GetAllList(Resource):
|
||||
@token_auth.auth.login_required
|
||||
def get(self):
|
||||
args = parser.parse_args()
|
||||
return selfredis_manager.get_all_list(args['vendor'],args['account'],args['region'],args['group'])
|
||||
|
||||
class SelfredisApi(Resource):
|
||||
decorators = [token_auth.auth.login_required]
|
||||
def get(self):
|
||||
return selfredis_manager.get_service()
|
||||
def post(self):
|
||||
args = parser.parse_args()
|
||||
print('=======\n',args,flush=True)
|
||||
return selfredis_manager.add_service(args['vendor'],args['account'],args['region'],
|
||||
args['group'],args['name'],args['ip'],args['port'],args['os'])
|
||||
def put(self):
|
||||
args = parser.parse_args()
|
||||
del_dict = args['del_dict']
|
||||
up_dict = args['up_dict']
|
||||
resp_del = selfredis_manager.del_service(del_dict['vendor'],del_dict['account'],
|
||||
del_dict['region'],del_dict['group'],del_dict['name'])
|
||||
resp_add = selfredis_manager.add_service(up_dict['vendor'],up_dict['account'],up_dict['region'],
|
||||
up_dict['group'],up_dict['name'],up_dict['ip'],
|
||||
up_dict['port'],up_dict['os'])
|
||||
if resp_del["code"] == 20000 and resp_add["code"] == 20000:
|
||||
return {"code": 20000, "data": f"更新成功!"}
|
||||
else:
|
||||
return {"code": 50000, "data": f"更新失败!"}
|
||||
def delete(self):
|
||||
args = parser.parse_args()
|
||||
return selfredis_manager.del_service(args['vendor'],args['account'],args['region'],args['group'],args['name'])
|
||||
|
||||
api.add_resource(GetAllList,'/api/selfredis/alllist')
|
||||
api.add_resource(SelfredisApi, '/api/selfredis/service')
|
||||
api.add_resource(Upload,'/api/selfredis/upload')
|
|
@ -0,0 +1,61 @@
|
|||
import request from '@/utils/request-ops'
|
||||
|
||||
export function getResList(job_id) {
|
||||
return request({
|
||||
url: '/api/nodes/res',
|
||||
method: 'get',
|
||||
params: { job_id }
|
||||
})
|
||||
}
|
||||
|
||||
export function getJobRedis() {
|
||||
return request({
|
||||
url: '/api/redis/jobredis',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getRedisServicesList() {
|
||||
return request({
|
||||
url: '/api/redis/redis_services',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getRedisConfig(services_dict) {
|
||||
return request({
|
||||
url: '/api/redis/redispconfig',
|
||||
method: 'post',
|
||||
data: { services_dict }
|
||||
})
|
||||
}
|
||||
export function getRedisRules() {
|
||||
return request({
|
||||
url: '/api/redis/redisrules',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function postCstRedis(cst_redis_dict) {
|
||||
return request({
|
||||
url: '/api/redis/cstredis',
|
||||
method: 'post',
|
||||
data: { cst_redis_dict }
|
||||
})
|
||||
}
|
||||
|
||||
export function getCstRedisConfig(iid) {
|
||||
return request({
|
||||
url: '/api/redis/cstredisconf',
|
||||
method: 'get',
|
||||
params: { iid }
|
||||
})
|
||||
}
|
||||
|
||||
export function getCstRedisList(jobredis_name, checked) {
|
||||
return request({
|
||||
url: '/api/redis/cstredislist',
|
||||
method: 'get',
|
||||
params: { jobredis_name, checked }
|
||||
})
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import request from '@/utils/request-ops'
|
||||
|
||||
export function getAllList(vendor, account, region, group) {
|
||||
return request({
|
||||
url: '/api/selfredis/alllist',
|
||||
method: 'get',
|
||||
params: { vendor, account, region, group }
|
||||
})
|
||||
}
|
||||
|
||||
export function getAllInfo() {
|
||||
return request({
|
||||
url: '/api/selfredis/service',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function addService(data) {
|
||||
return request({
|
||||
url: '/api/selfredis/service',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function updateService(del_dict, up_dict) {
|
||||
return request({
|
||||
url: '/api/selfredis/service',
|
||||
method: 'put',
|
||||
data: { del_dict, up_dict }
|
||||
})
|
||||
}
|
||||
export function delService(data) {
|
||||
return request({
|
||||
url: '/api/selfredis/service',
|
||||
method: 'delete',
|
||||
data
|
||||
})
|
||||
}
|
|
@ -182,6 +182,44 @@ export const constantRoutes = [
|
|||
meta: { title: 'Grafana 看板', icon: 'el-icon-data-line' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'redis',
|
||||
name: 'REDIS',
|
||||
component: () => import('@/views/redis/index'),
|
||||
meta: { title: 'REDIS管理', icon: 'el-icon-guide' },
|
||||
children: [
|
||||
{
|
||||
path: 'lists',
|
||||
name: '云REDIS列表',
|
||||
component: () => import('@/views/redis/lists'),
|
||||
meta: { title: '云REDIS列表', icon: 'el-icon-cloudy' }
|
||||
},
|
||||
{
|
||||
path: 'self',
|
||||
name: '自建REDIS管理',
|
||||
component: () => import('@/views/redis/self'),
|
||||
meta: { title: '自建REDIS管理', icon: 'el-icon-s-platform' }
|
||||
},
|
||||
{
|
||||
path: 'pconfig',
|
||||
name: 'redis-pconfig',
|
||||
component: () => import('@/views/redis/pconfig'),
|
||||
meta: { title: 'Prometheus 配置', icon: 'el-icon-set-up' }
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
name: 'redis-rules',
|
||||
component: () => import('@/views/redis/rules'),
|
||||
meta: { title: '告警规则', icon: 'el-icon-bell' }
|
||||
},
|
||||
{
|
||||
path: 'grafana',
|
||||
name: 'redis-grafana',
|
||||
component: () => import('@/views/redis/grafana'),
|
||||
meta: { title: 'Grafana 看板', icon: 'el-icon-data-line' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="新增云资源" :visible.sync="newFormVisible" width="40%">
|
||||
<el-dialog title="新增云资源" :visible.sync="newFormVisible" width="45%">
|
||||
<el-form ref="dataForm" :rules="rules" :model="ecsJob" label-position="right" label-width="auto" style="width: 90%; margin-left: 1px;">
|
||||
<el-form-item label="云厂商" prop="vendor">
|
||||
<el-select v-model="ecsJob.vendor" placeholder="请选择" @change="ecsJob.region=[]">
|
||||
|
@ -123,6 +123,7 @@
|
|||
<el-checkbox label="group" disabled>分组</el-checkbox>
|
||||
<el-checkbox label="ecs">ECS</el-checkbox>
|
||||
<el-checkbox label="rds">MySQL</el-checkbox>
|
||||
<el-checkbox label="redis">REDIS</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="restype.includes('ecs') && ecsJob.vendor === 'alicloud'" label="优先获取外网IP" prop="isextip">
|
||||
|
@ -145,6 +146,9 @@
|
|||
<el-form-item v-if="restype.includes('rds')" label="MySQL同步间隔(分钟)" prop="rds_interval">
|
||||
<el-input v-model="ecsJob.rds_interval" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="restype.includes('redis')" label="REDIS同步间隔(分钟)" prop="redis_interval">
|
||||
<el-input v-model="ecsJob.redis_interval" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
|
@ -160,7 +164,7 @@
|
|||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="编辑云资源" :visible.sync="editFormVisible" width="40%">
|
||||
<el-dialog title="编辑云资源" :visible.sync="editFormVisible" width="45%">
|
||||
<el-form ref="dataForm" :rules="rules" :model="editJob" label-position="right" label-width="auto" style="width: 90%; margin-left: 1px;">
|
||||
<el-form-item label="云厂商" prop="vendor">
|
||||
<el-select v-model="editJob.vendor" placeholder="请选择" @change="editJob.region=[];editJob.account=''">
|
||||
|
@ -194,6 +198,7 @@
|
|||
<el-checkbox label="group" disabled>分组</el-checkbox>
|
||||
<el-checkbox label="ecs">ECS</el-checkbox>
|
||||
<el-checkbox label="rds">MySQL</el-checkbox>
|
||||
<el-checkbox label="redis">REDIS</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="editJob.restype.includes('ecs') && editJob.vendor === 'alicloud'" label="优先获取外网IP" prop="isextip">
|
||||
|
@ -216,6 +221,9 @@
|
|||
<el-form-item v-if="editJob.restype.includes('rds')" label="MySQL同步间隔(分钟)" prop="rds_interval">
|
||||
<el-input v-model="editJob.rds_interval" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="editJob.restype.includes('redis')" label="REDIS同步间隔(分钟)" prop="redis_interval">
|
||||
<el-input v-model="editJob.redis_interval" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
|
@ -333,7 +341,7 @@ export default {
|
|||
]
|
||||
},
|
||||
|
||||
ecsJob: { vendor: '', ak: '', sk: '', region: [], account: '', proj_interval: 60, ecs_interval: 10, rds_interval: 20 },
|
||||
ecsJob: { vendor: '', ak: '', sk: '', region: [], account: '', proj_interval: 60, ecs_interval: 10, rds_interval: 20, redis_interval: 20 },
|
||||
editJob: { restype: ['group'] },
|
||||
cloud_dict: {},
|
||||
upjob: { jobid: '', interval: '' },
|
||||
|
@ -361,6 +369,8 @@ export default {
|
|||
return 'success-row'
|
||||
} else if (row.itype === 'rds') {
|
||||
return 'warning-row'
|
||||
} else if (row.itype === 'redis') {
|
||||
return 'info-row'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
@ -387,18 +397,19 @@ export default {
|
|||
this.editJob.proj_interval = response.interval.proj_interval
|
||||
this.editJob.ecs_interval = response.interval.ecs_interval
|
||||
this.editJob.rds_interval = response.interval.rds_interval
|
||||
this.editJob.redis_interval = response.interval.redis_interval
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleEdit() {
|
||||
this.editJob = { vendor: '', akskswitch: false, ak: '', sk: '', region: '', account: '', restype: ['group'], proj_interval: 60, ecs_interval: 10, rds_interval: 20, isextip: false }
|
||||
this.editJob = { vendor: '', akskswitch: false, ak: '', sk: '', region: '', account: '', restype: ['group'], proj_interval: 60, ecs_interval: 10, rds_interval: 20, redis_interval: 20, isextip: false }
|
||||
getCloud().then(response => {
|
||||
this.cloud_dict = response.cloud_dict
|
||||
})
|
||||
this.editFormVisible = true
|
||||
},
|
||||
handleCreate() {
|
||||
this.ecsJob = { vendor: '', ak: '', sk: '', region: [], account: '', proj_interval: 60, ecs_interval: 10, rds_interval: 20, isextip: false }
|
||||
this.ecsJob = { vendor: '', ak: '', sk: '', region: [], account: '', proj_interval: 60, ecs_interval: 10, rds_interval: 20, redis_interval: 20, isextip: false }
|
||||
this.ecsJob.account = this.query.account
|
||||
this.newFormVisible = true
|
||||
},
|
||||
|
@ -526,4 +537,7 @@ export default {
|
|||
.el-table .warning-row {
|
||||
background: oldlace;
|
||||
}
|
||||
.el-table .info-row {
|
||||
background: #f0f8ff;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<div>
|
||||
<br>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" :offset="6">
|
||||
<el-card shadow="always" style="text-align: center">
|
||||
Grafana 看板详情:
|
||||
<el-link href="https://grafana.com/grafana/dashboards/17320" target="_blank" type="primary">https://grafana.com/grafana/dashboards/17320</el-link><br><br>
|
||||
Grafana 看板ID:<strong>17320</strong>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<br>
|
||||
<div class="block">
|
||||
<el-image style="width: 100%; height: 100%" src="/mysql1.png" />
|
||||
<el-image style="width: 100%; height: 100%" src="/mysql2.png" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<router-view />
|
||||
</template>
|
|
@ -0,0 +1,154 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-select v-model="jobredis_name" placeholder="请选择需要查询的云MySQL列表" filterable collapse-tags clearable style="width: 350px" class="filter-item" @change="fetchRedis(jobredis_name)">
|
||||
<el-option v-for="item in jobredis_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-checkbox v-model="checked" style="margin-left: 10px;" label="仅显示修改过的" border @change="cstRedisList(jobredis_name,checked)" />
|
||||
<el-tooltip class="item" effect="light" content="刷新当前REDIS列表" placement="top">
|
||||
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-refresh" circle @click="fetchEcs(jobredis_name)" />
|
||||
</el-tooltip>
|
||||
<div style="float: right;margin-left: 10px;">
|
||||
<el-input v-model="iname" prefix-icon="el-icon-search" placeholder="请输入名称、实例或实例ID进行筛选" clearable style="width: 300px" class="filter-item" />
|
||||
</div>
|
||||
<el-dialog title="自定义实例信息" :visible.sync="dialogFormVisible" width="45%">
|
||||
<el-form ref="dataForm" :model="cst_redis" label-position="right" label-width="auto" style="width: 90%; margin-left: 20px;">
|
||||
<el-form-item label="自定义端口">
|
||||
<el-switch v-model="cst_redis.portswitch" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="cst_redis.portswitch" required label="端口:">
|
||||
<el-input v-model="cst_redis.port" />
|
||||
</el-form-item>
|
||||
<el-form-item label="自定义IP">
|
||||
<el-switch v-model="cst_redis.ipswitch" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="cst_redis.ipswitch" required label="IP:">
|
||||
<el-input v-model="cst_redis.ip" />
|
||||
</el-form-item>
|
||||
<font size="3px" color="#ff0000">如需恢复同步该实例的IP端口信息,请关闭开启的自定义选项后,再同步一次所属数据源。</font>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" @click="createData">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="redis_list.filter(data => !iname || (data.name.toLowerCase().includes(iname.toLowerCase()) || data.instance.toLowerCase().includes(iname.toLowerCase()) || data.iid.toLowerCase().includes(iname.toLowerCase())))"
|
||||
:default-sort="{ prop: 'exp', order: 'ascending' }"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
style="width: 100%;"
|
||||
>
|
||||
<el-table-column type="index" align="center" />
|
||||
<el-table-column prop="group" label="分组" sortable align="center" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="name" label="名称" sortable align="center" width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="instance" label="实例" sortable align="center" width="180">
|
||||
<template slot-scope="{row}">
|
||||
<span style="font-weight:bold">{{ row.instance }} </span>
|
||||
<el-tooltip style="diaplay:inline" effect="dark" placement="top">
|
||||
<div slot="content"> 域名:{{ row.domain }}</div>
|
||||
<i class="el-icon-info" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ver" label="版本" sortable align="center" width="80" />
|
||||
<el-table-column prop="mem" label="内存" sortable align="center" width="90" />
|
||||
<el-table-column prop="exp" label="到期日" sortable align="center" width="100" />
|
||||
<el-table-column prop="itype" label="类型" sortable align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="iid" label="实例ID" sortable align="center" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(row.iid)">
|
||||
自定义实例
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getResList, getJobRedis, postCstRedis, getCstRedisConfig, getCstRedisList } from '@/api/redis'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
listLoading: false,
|
||||
dialogFormVisible: false,
|
||||
checked: false,
|
||||
jobredis_name: '',
|
||||
iname: '',
|
||||
jobredis_list: [],
|
||||
redis_list: [],
|
||||
cst_redis: { iid: '', portswitch: false, ipswitch: false, port: '', ip: '' }
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getJobRedis().then(response => {
|
||||
this.jobredis_list = response.jobredis
|
||||
if (this.$route.query.job_id) {
|
||||
this.fetchRedis(this.$route.query.job_id)
|
||||
} else {
|
||||
this.jobredis_name = this.jobredis_list[0]
|
||||
this.fetchRedis(this.jobredis_name)
|
||||
}
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
if (this.$route.query.job_id) {
|
||||
this.jobredis_name = this.$route.query.job_id
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cstRedisList(jobredis_name, checked) {
|
||||
this.listLoading = true
|
||||
getCstRedisList(jobredis_name, checked).then(response => {
|
||||
this.redis_list = response.res_list
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleUpdate(iid) {
|
||||
this.listLoading = true
|
||||
this.dialogFormVisible = true
|
||||
getCstRedisConfig(iid).then(response => {
|
||||
this.cst_redis = response.cst_redis
|
||||
this.listLoading = false
|
||||
this.dialogFormVisible = true
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.dialogFormVisible = false
|
||||
this.listLoading = true
|
||||
postCstRedis(this.cst_redis).then(response => {
|
||||
this.fetchRedis(this.jobredis_name)
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
fetchJobRedis() {
|
||||
getJobRedis().then(response => {
|
||||
this.jobredis_list = response.jobredis
|
||||
})
|
||||
},
|
||||
fetchRedis(job_id) {
|
||||
this.checked = false
|
||||
this.listLoading = true
|
||||
getResList(job_id).then(response => {
|
||||
this.redis_list = response.res_list
|
||||
this.listLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-select v-model="services" multiple placeholder="选择需要自动发现的MySQL组" filterable collapse-tags clearable style="width: 260px" class="filter-item">
|
||||
<el-option v-for="item in services_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-input v-model="exporter" placeholder="Mysqld_Exporter IP端口" clearable style="width: 200px;" class="filter-item" />
|
||||
<el-select v-model="jobredis" multiple placeholder="选择需要采集指标的MySQL组" filterable collapse-tags clearable style="width: 260px" class="filter-item">
|
||||
<el-option v-for="item in jobredis_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-input v-model="cm_exporter" placeholder="ConsulManager IP端口" clearable style="width: 190px;" class="filter-item" />
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-magic-stick" @click="fetchRedisConfig">
|
||||
生成配置
|
||||
</el-button>
|
||||
<el-button v-clipboard:copy="configs" v-clipboard:success="onCopy" v-clipboard:error="onError" class="filter-item" type="warning" icon="el-icon-document-copy">
|
||||
复制配置
|
||||
</el-button>
|
||||
<pre v-highlightjs="configs" style="line-height:120%"><code class="yaml yamlcode" /></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRedisServicesList, getRedisConfig, getJobRedis } from '@/api/redis'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
listLoading: false,
|
||||
services: [],
|
||||
jobredis: [],
|
||||
ostype: [],
|
||||
services_list: [],
|
||||
services_dict: {},
|
||||
jobredis_list: [],
|
||||
exporter: '',
|
||||
cm_exporter: '',
|
||||
configs: '该功能用于生成Prometheus的两个JOB配置,生成后请复制到Prometheus配置中:\n\n1. 选择需要同步的账号,Prometheus即可自动发现该账号下的所有DRS实例。\n\n2. 由于Mysqld_Exporter无法监控到云数据库的CPU、内存、磁盘的使用情况,所以ConsulManager开发了Exporter功能,配置到Prometheus即可直接从云厂商采集到这些指标!\n 选择需要采集指标的REDIS账号区域,即可生成Prometheus的JOB配置。'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchRedisList()
|
||||
},
|
||||
methods: {
|
||||
onCopy() {
|
||||
this.$message({
|
||||
message: '复制成功!',
|
||||
type: 'success'
|
||||
})
|
||||
},
|
||||
onError() {
|
||||
this.$message.error('复制失败!')
|
||||
},
|
||||
fetchRedisList() {
|
||||
this.listLoading = true
|
||||
getRedisServicesList().then(response => {
|
||||
this.services_list = response.services_list
|
||||
this.services_list.push('selfredis_exporter')
|
||||
})
|
||||
getJobRedis().then(response => {
|
||||
this.jobredis_list = response.jobredis
|
||||
})
|
||||
this.listLoading = false
|
||||
},
|
||||
fetchRedisConfig() {
|
||||
this.listLoading = true
|
||||
this.services_dict.services_list = this.services
|
||||
this.services_dict.exporter = this.exporter
|
||||
this.services_dict.jobredis_list = this.jobredis
|
||||
this.services_dict.cm_exporter = this.cm_exporter
|
||||
getRedisConfig(this.services_dict).then(response => {
|
||||
this.configs = response.configs
|
||||
this.listLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.yamlcode {
|
||||
font-family:'Consolas';
|
||||
}
|
||||
pre {
|
||||
max-height: 640px;
|
||||
white-space: pre-wrap;
|
||||
overflow:auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-button v-clipboard:copy="rules" v-clipboard:success="onCopy" v-clipboard:error="onError" class="filter-item" type="warning" icon="el-icon-document-copy">
|
||||
复制配置
|
||||
</el-button>
|
||||
<pre v-highlightjs="rules" style="line-height:120%"><code class="yaml yamlcode" /></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRedisRules } from '@/api/redis'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
listLoading: false,
|
||||
rules: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchRules()
|
||||
},
|
||||
methods: {
|
||||
onCopy() {
|
||||
this.$message({
|
||||
message: '复制成功!',
|
||||
type: 'success'
|
||||
})
|
||||
},
|
||||
onError() {
|
||||
this.$message.error('复制失败!')
|
||||
},
|
||||
fetchRules() {
|
||||
this.listLoading = true
|
||||
getRedisRules().then(response => {
|
||||
this.rules = response.rules
|
||||
this.listLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.yamlcode {
|
||||
font-family:'Consolas';
|
||||
}
|
||||
pre {
|
||||
max-height: 640px;
|
||||
white-space: pre-wrap;
|
||||
overflow:auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,596 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div class="filter-container" style="flex: 1;display: flex;align-items: center;height: 50px;">
|
||||
<el-select v-model="listQuery.vendor" placeholder="机房/公司" clearable collapse-tags style="width: 150px" class="filter-item">
|
||||
<el-option v-for="item in vendor_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.account" placeholder="租户/部门" clearable style="width: 150px" class="filter-item">
|
||||
<el-option v-for="item in account_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.region" filterable placeholder="区域/项目" clearable style="width: 150px" class="filter-item">
|
||||
<el-option v-for="item in region_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.group" filterable placeholder="分组/环境" clearable style="width: 120px" class="filter-item">
|
||||
<el-option v-for="item in group_list" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-tooltip class="item" effect="light" content="点击清空查询条件" placement="top">
|
||||
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-refresh" circle @click="handleReset" />
|
||||
</el-tooltip>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button v-waves :loading="downloadLoading" class="filter-item" type="success" icon="el-icon-download" @click="handleDownload">
|
||||
导出
|
||||
</el-button>
|
||||
<el-upload
|
||||
style="margin-right: 9px;"
|
||||
class="upload-demo"
|
||||
action="/api/selfredis/upload"
|
||||
:headers="myHeaders"
|
||||
:on-success="success"
|
||||
:on-error="error"
|
||||
accept=".xlsx"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:show-file-list="false"
|
||||
:multiple="false"
|
||||
>
|
||||
<el-tooltip class="item" effect="light" content="点击【导出】可获取导入模板" placement="top">
|
||||
<el-button v-waves style="margin-left: 9px;margin-top: 0px;" :loading="downloadLoading" class="filter-item" type="warning" icon="el-icon-upload2">
|
||||
导入
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-upload>
|
||||
<el-button class="filter-item" type="danger" icon="el-icon-delete" @click="handleDelAll">
|
||||
批量删除
|
||||
</el-button>
|
||||
<div style="float: right;margin-left: 9px;">
|
||||
<el-input v-model="iname" prefix-icon="el-icon-search" placeholder="请输入名称或实例进行筛选" clearable style="width:180px" class="filter-item" @input="inameFilter(iname)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="all_list.filter(data => !iname || (data.name.toLowerCase().includes(iname.toLowerCase()) || data.instance.toLowerCase().includes(iname.toLowerCase())))"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
style="width: 100%;"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" align="center" width="35" />
|
||||
<el-table-column label="ID" align="center" width="40px">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.$index+1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="vendor" label="机房/公司" sortable align="center">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.vendor }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="account" label="租户/部门" sortable align="center">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.account }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="region" label="区域/项目" sortable align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.region }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="group" label="分组/环境" sortable align="center">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.group }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="名称" sortable align="center" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="instance" label="实例" sortable align="center" width="160" show-overflow-tooltip>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.instance }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="os" label="主机系统" sortable align="center" width="80">
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.os }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="handleFilter" />
|
||||
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="37%">
|
||||
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="auto" style="width: 90%; margin-left: 20px;">
|
||||
<font size="3px" color="#ff0000">【注意:前5个字段组合后需唯一,重复会覆盖已有监控项!】</font>
|
||||
<el-form-item label="机房/公司" prop="vendor">
|
||||
<el-autocomplete v-model="temp.vendor" :fetch-suggestions="Sugg_vendor" placeholder="优先选择" clearable class="filter-item" />
|
||||
</el-form-item>
|
||||
<el-form-item label="租户/部门" prop="account">
|
||||
<el-autocomplete v-model="temp.account" :fetch-suggestions="Sugg_account" placeholder="优先选择" clearable class="filter-item" />
|
||||
</el-form-item>
|
||||
<el-form-item label="区域/项目" prop="region">
|
||||
<el-autocomplete v-model="temp.region" :fetch-suggestions="Sugg_region" placeholder="优先选择" clearable class="filter-item" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分组/环境" prop="group">
|
||||
<el-autocomplete v-model="temp.group" :fetch-suggestions="Sugg_group" placeholder="优先选择" clearable class="filter-item" />
|
||||
</el-form-item>
|
||||
<el-form ref="dataForm" :inline="true" :rules="rules" :model="temp" class="demo-form-inline" label-position="right" label-width="50px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="temp.name" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="主机" prop="os">
|
||||
<el-select v-model="temp.os" placeholder="请选择" style="width: 130px;" @change="temp.port=osport[temp.os]">
|
||||
<el-option label="linux" value="linux" />
|
||||
<el-option label="windows" value="windows" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="IP" prop="ip">
|
||||
<el-input v-model="temp.ip" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="端口" prop="port">
|
||||
<el-input v-model="temp.port" placeholder="请输入" clearable style="width: 130px;" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button v-if="dialogStatus==='create'" type="primary" @click="createAndNew">
|
||||
确认并新增
|
||||
</el-button>
|
||||
<el-button @click="dialogFormVisible = false">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import waves from '@/directive/waves' // waves directive
|
||||
import Pagination from '@/components/Pagination' // secondary package based on el-pagination
|
||||
|
||||
import { getAllList, getAllInfo, addService, updateService, delService } from '@/api/selfredis'
|
||||
export default {
|
||||
name: 'ComplexTable',
|
||||
components: { Pagination },
|
||||
directives: { waves },
|
||||
filters: {
|
||||
statusFilter(status) {
|
||||
const statusMap = {
|
||||
published: 'success',
|
||||
draft: 'info',
|
||||
deleted: 'danger'
|
||||
}
|
||||
return statusMap[status]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validateInput = (rule, value, callback) => {
|
||||
if (!this.checkSpecialKey(value)) {
|
||||
callback(new Error('不能含有空格或 [ ]`~!#$^&*=|"{}\':;?\\'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
myHeaders: { Authorization: this.$store.getters.token },
|
||||
all_list: [],
|
||||
pall_list: [],
|
||||
iname: '',
|
||||
new_list: [],
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 30,
|
||||
vendor: '',
|
||||
account: '',
|
||||
region: '',
|
||||
group: ''
|
||||
},
|
||||
value_vendor: [],
|
||||
value_account: [],
|
||||
value_region: [],
|
||||
value_group: [],
|
||||
vendor_list: [],
|
||||
account_list: [],
|
||||
group_list: [],
|
||||
region_list: [],
|
||||
multipleSelection: [],
|
||||
del_dict: {},
|
||||
osport: { linux: '6379', windows: '6379' },
|
||||
temp: {
|
||||
vendor: '',
|
||||
account: '',
|
||||
region: '',
|
||||
group: '',
|
||||
name: '',
|
||||
os: '',
|
||||
ip: '',
|
||||
port: ''
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
update: '更新',
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
vendor: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
account: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
region: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
group: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
name: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
ip: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
port: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||||
os: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||||
{ validator: validateInput, trigger: ['blur', 'change'] }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
cvendor() {
|
||||
return this.listQuery.vendor
|
||||
},
|
||||
caccount() {
|
||||
return this.listQuery.account
|
||||
},
|
||||
cregion() {
|
||||
return this.listQuery.region
|
||||
},
|
||||
cgroup() {
|
||||
return this.listQuery.group
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
cvendor(new_vendor) {
|
||||
this.fetchList(new_vendor, this.listQuery.account, this.listQuery.region, this.listQuery.group)
|
||||
},
|
||||
caccount(new_account) {
|
||||
this.fetchList(this.listQuery.vendor, new_account, this.listQuery.region, this.listQuery.group)
|
||||
},
|
||||
cregion(new_region) {
|
||||
this.fetchList(this.listQuery.vendor, this.listQuery.account, new_region, this.listQuery.group)
|
||||
},
|
||||
cgroup(new_group) {
|
||||
this.fetchList(this.listQuery.vendor, this.listQuery.account, this.listQuery.region, new_group)
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.fetchData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleBeforeUpload(file) {
|
||||
const uploadLimit = 5
|
||||
const uploadTypes = ['xlsx']
|
||||
const filetype = file.name.replace(/.+\./, '')
|
||||
const isRightSize = (file.size || 0) / 1024 / 1024 < uploadLimit
|
||||
if (!isRightSize) {
|
||||
this.$message.error(`文件大小超过${uploadLimit}MB!`)
|
||||
return false
|
||||
}
|
||||
if (uploadTypes.indexOf(filetype.toLowerCase()) === -1) {
|
||||
this.$message.warning({
|
||||
message: '仅支持上传xlsx格式的文件!'
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
success(response) {
|
||||
if (response.code === 20000) {
|
||||
this.fetchData()
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
},
|
||||
error(response) {
|
||||
if (response.code === 50000) {
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
},
|
||||
inameFilter(iname) {
|
||||
if (iname === '') {
|
||||
this.handleFilter()
|
||||
} else {
|
||||
this.total = 0
|
||||
this.all_list = this.pall_list
|
||||
}
|
||||
},
|
||||
handleFilter() {
|
||||
this.total = this.pall_list.length
|
||||
this.all_list = this.pall_list.slice(0 + this.listQuery.limit * (this.listQuery.page - 1), this.listQuery.limit + this.listQuery.limit * (this.listQuery.page - 1))
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val
|
||||
},
|
||||
checkSpecialKey(str) {
|
||||
const specialKey = '[]`~!#$^&*=|{}\'":;? \\'
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (specialKey.indexOf(str.substr(i, 1)) !== -1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
fetchData() {
|
||||
this.listLoading = true
|
||||
getAllInfo().then(response => {
|
||||
this.all_list = response.all_list
|
||||
this.vendor_list = response.vendor_list
|
||||
this.account_list = response.account_list
|
||||
this.region_list = response.region_list
|
||||
this.group_list = response.group_list
|
||||
this.listLoading = false
|
||||
this.xvendor = this.load_vendor()
|
||||
this.xaccount = this.load_account()
|
||||
this.xregion = this.load_region()
|
||||
this.xgroup = this.load_group()
|
||||
this.pall_list = response.all_list
|
||||
this.handleFilter()
|
||||
})
|
||||
},
|
||||
fetchList(vendor, account, region, group) {
|
||||
this.listLoading = true
|
||||
getAllList(vendor, account, region, group).then(response => {
|
||||
this.all_list = response.all_list
|
||||
this.listLoading = false
|
||||
this.vendor_list = response.vendor_list
|
||||
this.account_list = response.account_list
|
||||
this.region_list = response.region_list
|
||||
this.group_list = response.group_list
|
||||
this.listQuery.page = 1
|
||||
this.pall_list = response.all_list
|
||||
this.handleFilter()
|
||||
})
|
||||
},
|
||||
resetTemp() {
|
||||
this.temp = {}
|
||||
},
|
||||
|
||||
handleCreate() {
|
||||
this.resetTemp()
|
||||
var newone = {
|
||||
vendor: this.listQuery.vendor,
|
||||
account: this.listQuery.account,
|
||||
region: this.listQuery.region,
|
||||
group: this.listQuery.group,
|
||||
os: 'linux',
|
||||
port: '6379'
|
||||
}
|
||||
this.temp = Object.assign({}, this.temp, newone)
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
addService(this.temp).then(response => {
|
||||
this.temp.instance = this.temp.ip + ':' + this.temp.port
|
||||
this.all_list.unshift(this.temp)
|
||||
this.dialogFormVisible = false
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
createAndNew() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
addService(this.temp).then(response => {
|
||||
this.temp.instance = this.temp.ip + ':' + this.temp.port
|
||||
this.all_list.unshift(this.temp)
|
||||
this.dialogFormVisible = false
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
var newtemp = {
|
||||
vendor: this.temp.vendor,
|
||||
account: this.temp.account,
|
||||
region: this.temp.region,
|
||||
group: this.temp.group,
|
||||
os: 'linux',
|
||||
port: '6379'
|
||||
}
|
||||
this.resetTemp()
|
||||
this.temp = Object.assign({}, this.temp, newtemp)
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleReset() {
|
||||
this.listQuery.vendor = ''
|
||||
this.listQuery.account = ''
|
||||
this.listQuery.region = ''
|
||||
this.listQuery.group = ''
|
||||
},
|
||||
handleUpdate(row) {
|
||||
row.ip = row.instance.split(':')[0]
|
||||
row.port = row.instance.split(':')[1]
|
||||
this.temp = Object.assign({}, row) // copy obj
|
||||
this.del_dict = row
|
||||
this.dialogStatus = 'update'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
const up_dict = Object.assign({}, this.temp)
|
||||
updateService(this.del_dict, up_dict).then(response => {
|
||||
this.dialogFormVisible = false
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
up_dict.instance = up_dict.ip + ':' + up_dict.port
|
||||
this.all_list.splice(this.all_list.indexOf(this.del_dict), 1, up_dict)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$confirm('此操作将删除【' + row.group + ':' + row.region + ':' + row.name + '】,是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
delService(row).then(response => {
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
this.$delete(this.all_list, this.all_list.indexOf(row))
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelAll() {
|
||||
this.$confirm('此操作将批量删除选中行,是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
delService(this.multipleSelection[i]).then(response => {
|
||||
this.$message({
|
||||
message: response.data,
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
this.$delete(this.all_list, this.all_list.indexOf(this.multipleSelection[i]))
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['机房/公司', '租户/部门', '区域/项目', '分组/环境', '名称', '实例(IP:端口)', '主机系统(linux/windows)']
|
||||
const filterVal = ['vendor', 'account', 'region', 'group', 'name', 'instance', 'os']
|
||||
const data = this.formatJson(filterVal)
|
||||
excel.export_json_to_excel({
|
||||
header: tHeader,
|
||||
data,
|
||||
filename: 'selfredis-list'
|
||||
})
|
||||
this.downloadLoading = false
|
||||
})
|
||||
},
|
||||
formatJson(filterVal) {
|
||||
return this.all_list.map(v => filterVal.map(j => {
|
||||
return v[j]
|
||||
}))
|
||||
},
|
||||
Sugg_vendor(queryString, cb) {
|
||||
var xvendor = this.xvendor
|
||||
var results = queryString ? xvendor.filter(this.createFilter(queryString)) : xvendor
|
||||
cb(results)
|
||||
},
|
||||
Sugg_account(queryString, cb) {
|
||||
var xaccount = this.xaccount
|
||||
var results = queryString ? xaccount.filter(this.createFilter(queryString)) : xaccount
|
||||
cb(results)
|
||||
},
|
||||
Sugg_region(queryString, cb) {
|
||||
var xregion = this.xregion
|
||||
var results = queryString ? xregion.filter(this.createFilter(queryString)) : xregion
|
||||
cb(results)
|
||||
},
|
||||
Sugg_group(queryString, cb) {
|
||||
var xgroup = this.xgroup
|
||||
var results = queryString ? xgroup.filter(this.createFilter(queryString)) : xgroup
|
||||
cb(results)
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return (restaurant) => {
|
||||
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
|
||||
}
|
||||
},
|
||||
load_vendor() {
|
||||
for (const x in this.vendor_list) {
|
||||
this.value_vendor.push({ 'value': this.vendor_list[x] })
|
||||
}
|
||||
return this.value_vendor
|
||||
},
|
||||
load_account() {
|
||||
for (const x in this.account_list) {
|
||||
this.value_account.push({ 'value': this.account_list[x] })
|
||||
}
|
||||
return this.value_account
|
||||
},
|
||||
load_region() {
|
||||
for (const x in this.region_list) {
|
||||
this.value_region.push({ 'value': this.region_list[x] })
|
||||
}
|
||||
return this.value_region
|
||||
},
|
||||
load_group() {
|
||||
for (const x in this.group_list) {
|
||||
this.value_group.push({ 'value': this.group_list[x] })
|
||||
}
|
||||
return this.value_group
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue