mirror of https://github.com/openspug/spug
upgrade monitor module
parent
2ed651bd52
commit
540fc3511c
|
@ -6,6 +6,7 @@ from django.conf import settings
|
||||||
from django_redis import get_redis_connection
|
from django_redis import get_redis_connection
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from apps.schedule.executors import schedule_worker_handler
|
from apps.schedule.executors import schedule_worker_handler
|
||||||
|
from apps.monitor.executors import monitor_worker_handler
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
MONITOR_WORKER_KEY = settings.MONITOR_WORKER_KEY
|
MONITOR_WORKER_KEY = settings.MONITOR_WORKER_KEY
|
||||||
|
@ -24,7 +25,7 @@ class Worker:
|
||||||
if key.decode() == SCHEDULE_WORKER_KEY:
|
if key.decode() == SCHEDULE_WORKER_KEY:
|
||||||
self._executor.submit(schedule_worker_handler, job)
|
self._executor.submit(schedule_worker_handler, job)
|
||||||
else:
|
else:
|
||||||
pass
|
self._executor.submit(monitor_worker_handler, job)
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
|
@ -8,13 +8,18 @@ import subprocess
|
||||||
import platform
|
import platform
|
||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
logging.captureWarnings(True)
|
logging.captureWarnings(True)
|
||||||
|
|
||||||
|
|
||||||
def site_check(url):
|
def site_check(url, limit):
|
||||||
try:
|
try:
|
||||||
res = requests.get(url, timeout=10, verify=False)
|
res = requests.get(url, timeout=10, verify=False)
|
||||||
|
if limit:
|
||||||
|
duration = int(res.elapsed.total_seconds() * 1000)
|
||||||
|
if duration > int(limit):
|
||||||
|
return False, f'响应时间:{duration}ms'
|
||||||
return 200 <= res.status_code < 400, f'返回状态码:{res.status_code}'
|
return 200 <= res.status_code < 400, f'返回状态码:{res.status_code}'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, f'异常信息:{e}'
|
return False, f'异常信息:{e}'
|
||||||
|
@ -58,9 +63,41 @@ def host_executor(host, command):
|
||||||
return False, f'异常信息:{e}'
|
return False, f'异常信息:{e}'
|
||||||
|
|
||||||
|
|
||||||
def dispatch(tp, addr, extra, in_view=False):
|
def monitor_worker_handler(job):
|
||||||
if not in_view:
|
print('enter: ', job)
|
||||||
|
task_id, tp, addr, extra = json.loads(job)
|
||||||
|
if tp == '1':
|
||||||
|
is_ok, message = site_check(addr, extra)
|
||||||
|
elif tp == '2':
|
||||||
|
is_ok, message = port_check(addr, extra)
|
||||||
|
elif tp == '5':
|
||||||
|
is_ok, message = ping_check(addr)
|
||||||
|
elif tp not in ('3', '4'):
|
||||||
|
is_ok, message = False, f'invalid monitor type for {tp!r}'
|
||||||
|
else:
|
||||||
close_old_connections()
|
close_old_connections()
|
||||||
|
command = f'ps -ef|grep -v grep|grep {extra!r}' if tp == '3' else extra
|
||||||
|
host = Host.objects.filter(pk=addr).first()
|
||||||
|
if not host:
|
||||||
|
is_ok, message = False, f'unknown host id for {addr!r}'
|
||||||
|
else:
|
||||||
|
is_ok, message = host_executor(host, command)
|
||||||
|
|
||||||
|
|
||||||
|
# is_notified = True if obj.latest_notify_time else False
|
||||||
|
# if obj.latest_status in [0, None] and is_ok is False:
|
||||||
|
# obj.latest_fault_time = int(time.time())
|
||||||
|
# if is_ok:
|
||||||
|
# obj.latest_notify_time = 0
|
||||||
|
# obj.fault_times = 0
|
||||||
|
# else:
|
||||||
|
# obj.fault_times += 1
|
||||||
|
# obj.latest_status = 0 if is_ok else 1
|
||||||
|
# obj.latest_run_time = human_datetime(event.scheduled_run_time)
|
||||||
|
# obj.save()
|
||||||
|
# self._handle_notify(obj, is_notified, out)
|
||||||
|
|
||||||
|
def dispatch(tp, addr, extra):
|
||||||
if tp == '1':
|
if tp == '1':
|
||||||
return site_check(addr)
|
return site_check(addr)
|
||||||
elif tp == '2':
|
elif tp == '2':
|
||||||
|
|
|
@ -22,7 +22,8 @@ class Detection(models.Model, ModelMixin):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
type = models.CharField(max_length=2, choices=TYPES)
|
type = models.CharField(max_length=2, choices=TYPES)
|
||||||
group = models.CharField(max_length=255, null=True)
|
group = models.CharField(max_length=255, null=True)
|
||||||
addr = models.CharField(max_length=255)
|
addr = models.CharField(max_length=255) # 要删除的
|
||||||
|
targets = models.TextField()
|
||||||
extra = models.TextField(null=True)
|
extra = models.TextField(null=True)
|
||||||
desc = models.CharField(max_length=255, null=True)
|
desc = models.CharField(max_length=255, null=True)
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
|
@ -48,6 +49,7 @@ class Detection(models.Model, ModelMixin):
|
||||||
tmp['latest_status_alias'] = self.get_latest_status_display()
|
tmp['latest_status_alias'] = self.get_latest_status_display()
|
||||||
tmp['notify_mode'] = json.loads(self.notify_mode)
|
tmp['notify_mode'] = json.loads(self.notify_mode)
|
||||||
tmp['notify_grp'] = json.loads(self.notify_grp)
|
tmp['notify_grp'] = json.loads(self.notify_grp)
|
||||||
|
tmp['targets'] = json.loads(self.targets)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
|
@ -10,7 +10,6 @@ from django.utils.functional import SimpleLazyObject
|
||||||
from django.db import close_old_connections
|
from django.db import close_old_connections
|
||||||
from apps.monitor.models import Detection
|
from apps.monitor.models import Detection
|
||||||
from apps.alarm.models import Alarm
|
from apps.alarm.models import Alarm
|
||||||
from apps.monitor.executors import dispatch
|
|
||||||
from apps.monitor.utils import seconds_to_human
|
from apps.monitor.utils import seconds_to_human
|
||||||
from apps.notify.models import Notify
|
from apps.notify.models import Notify
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -20,6 +19,8 @@ import logging
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
MONITOR_WORKER_KEY = settings.MONITOR_WORKER_KEY
|
||||||
|
|
||||||
|
|
||||||
class Scheduler:
|
class Scheduler:
|
||||||
timezone = settings.TIME_ZONE
|
timezone = settings.TIME_ZONE
|
||||||
|
@ -28,7 +29,8 @@ class Scheduler:
|
||||||
self.scheduler = BackgroundScheduler(timezone=self.timezone, executors={'default': ThreadPoolExecutor(30)})
|
self.scheduler = BackgroundScheduler(timezone=self.timezone, executors={'default': ThreadPoolExecutor(30)})
|
||||||
self.scheduler.add_listener(
|
self.scheduler.add_listener(
|
||||||
self._handle_event,
|
self._handle_event,
|
||||||
EVENT_SCHEDULER_SHUTDOWN | EVENT_JOB_ERROR | EVENT_JOB_MAX_INSTANCES | EVENT_JOB_EXECUTED)
|
EVENT_SCHEDULER_SHUTDOWN | EVENT_JOB_ERROR | EVENT_JOB_MAX_INSTANCES
|
||||||
|
)
|
||||||
|
|
||||||
def _record_alarm(self, obj, status):
|
def _record_alarm(self, obj, status):
|
||||||
duration = seconds_to_human(time.time() - obj.latest_fault_time)
|
duration = seconds_to_human(time.time() - obj.latest_fault_time)
|
||||||
|
@ -97,15 +99,22 @@ class Scheduler:
|
||||||
obj.save()
|
obj.save()
|
||||||
self._handle_notify(obj, is_notified, out)
|
self._handle_notify(obj, is_notified, out)
|
||||||
|
|
||||||
|
def _dispatch(self, task_id, tp, targets, extra):
|
||||||
|
close_old_connections()
|
||||||
|
Detection.objects.filter(pk=task_id).update(latest_run_time=human_datetime())
|
||||||
|
rds_cli = get_redis_connection()
|
||||||
|
for t in json.loads(targets):
|
||||||
|
rds_cli.rpush(MONITOR_WORKER_KEY, json.dumps([task_id, tp, t, extra]))
|
||||||
|
|
||||||
def _init(self):
|
def _init(self):
|
||||||
self.scheduler.start()
|
self.scheduler.start()
|
||||||
for item in Detection.objects.filter(is_active=True):
|
for item in Detection.objects.filter(is_active=True):
|
||||||
trigger = IntervalTrigger(minutes=int(item.rate), timezone=self.timezone)
|
trigger = IntervalTrigger(minutes=int(item.rate), timezone=self.timezone)
|
||||||
self.scheduler.add_job(
|
self.scheduler.add_job(
|
||||||
dispatch,
|
self._dispatch,
|
||||||
trigger,
|
trigger,
|
||||||
id=str(item.id),
|
id=str(item.id),
|
||||||
args=(item.type, item.addr, item.extra),
|
args=(item.id, item.type, item.targets, item.extra),
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -119,10 +128,10 @@ class Scheduler:
|
||||||
if task.action in ('add', 'modify'):
|
if task.action in ('add', 'modify'):
|
||||||
trigger = IntervalTrigger(minutes=int(task.rate), timezone=self.timezone)
|
trigger = IntervalTrigger(minutes=int(task.rate), timezone=self.timezone)
|
||||||
self.scheduler.add_job(
|
self.scheduler.add_job(
|
||||||
dispatch,
|
self._dispatch,
|
||||||
trigger,
|
trigger,
|
||||||
id=str(task.id),
|
id=str(task.id),
|
||||||
args=(task.type, task.addr, task.extra),
|
args=(task.id, task.type, task.targets, task.extra),
|
||||||
replace_existing=True
|
replace_existing=True
|
||||||
)
|
)
|
||||||
elif task.action == 'remove':
|
elif task.action == 'remove':
|
||||||
|
|
|
@ -21,7 +21,7 @@ class DetectionView(View):
|
||||||
Argument('id', type=int, required=False),
|
Argument('id', type=int, required=False),
|
||||||
Argument('name', help='请输入任务名称'),
|
Argument('name', help='请输入任务名称'),
|
||||||
Argument('group', help='请选择任务分组'),
|
Argument('group', help='请选择任务分组'),
|
||||||
Argument('addr', help='请输入监控地址'),
|
Argument('targets', type=list, filter=lambda x: len(x), help='请输入监控地址'),
|
||||||
Argument('type', filter=lambda x: x in dict(Detection.TYPES), help='请选择监控类型'),
|
Argument('type', filter=lambda x: x in dict(Detection.TYPES), help='请选择监控类型'),
|
||||||
Argument('extra', required=False),
|
Argument('extra', required=False),
|
||||||
Argument('desc', required=False),
|
Argument('desc', required=False),
|
||||||
|
@ -32,6 +32,7 @@ class DetectionView(View):
|
||||||
Argument('notify_mode', type=list, help='请选择报警方式'),
|
Argument('notify_mode', type=list, help='请选择报警方式'),
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
|
form.targets = json.dumps(form.targets)
|
||||||
form.notify_grp = json.dumps(form.notify_grp)
|
form.notify_grp = json.dumps(form.notify_grp)
|
||||||
form.notify_mode = json.dumps(form.notify_mode)
|
form.notify_mode = json.dumps(form.notify_mode)
|
||||||
if form.id:
|
if form.id:
|
||||||
|
@ -63,7 +64,7 @@ class DetectionView(View):
|
||||||
if form.is_active:
|
if form.is_active:
|
||||||
task = Detection.objects.filter(pk=form.id).first()
|
task = Detection.objects.filter(pk=form.id).first()
|
||||||
message = {'id': form.id, 'action': 'add'}
|
message = {'id': form.id, 'action': 'add'}
|
||||||
message.update(task.to_dict(selects=('addr', 'extra', 'rate', 'type')))
|
message.update(task.to_dict(selects=('targets', 'extra', 'rate', 'type')))
|
||||||
else:
|
else:
|
||||||
message = {'id': form.id, 'action': 'remove'}
|
message = {'id': form.id, 'action': 'remove'}
|
||||||
rds_cli = get_redis_connection()
|
rds_cli = get_redis_connection()
|
||||||
|
@ -86,10 +87,10 @@ class DetectionView(View):
|
||||||
def run_test(request):
|
def run_test(request):
|
||||||
form, error = JsonParser(
|
form, error = JsonParser(
|
||||||
Argument('type', help='请选择监控类型'),
|
Argument('type', help='请选择监控类型'),
|
||||||
Argument('addr', help='请输入监控地址'),
|
Argument('targets', type=list, filter=lambda x: len(x), help='请输入监控地址'),
|
||||||
Argument('extra', required=False)
|
Argument('extra', required=False)
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
is_success, message = dispatch(form.type, form.addr, form.extra, True)
|
is_success, message = dispatch(form.type, form.targets[0], form.extra)
|
||||||
return json_response({'is_success': is_success, 'message': message})
|
return json_response({'is_success': is_success, 'message': message})
|
||||||
return json_response(error=error)
|
return json_response(error=error)
|
||||||
|
|
|
@ -3,15 +3,16 @@
|
||||||
* Copyright (c) <spug.dev@gmail.com>
|
* Copyright (c) <spug.dev@gmail.com>
|
||||||
* Released under the AGPL-3.0 License.
|
* Released under the AGPL-3.0 License.
|
||||||
*/
|
*/
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
import { Modal, Form, Input, Select, Button } from 'antd';
|
import { Modal, Form, Input, Select, Button, message } from 'antd';
|
||||||
import TemplateSelector from '../exec/task/TemplateSelector';
|
import TemplateSelector from '../exec/task/TemplateSelector';
|
||||||
|
import Selector from 'pages/host/Selector';
|
||||||
import { LinkButton, ACEditor } from 'components';
|
import { LinkButton, ACEditor } from 'components';
|
||||||
import { http, cleanCommand, hasHostPermission } from 'libs';
|
import { http, cleanCommand } from 'libs';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
import hostStore from '../host/store';
|
import lds from 'lodash';
|
||||||
|
|
||||||
const helpMap = {
|
const helpMap = {
|
||||||
'1': '返回HTTP状态码200-399则判定为正常,其他为异常。',
|
'1': '返回HTTP状态码200-399则判定为正常,其他为异常。',
|
||||||
|
@ -21,20 +22,12 @@ const helpMap = {
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [showTmp, setShowTmp] = useState(false);
|
const [showTmp, setShowTmp] = useState(false);
|
||||||
|
const [showSelector, setShowSelector] = useState(false);
|
||||||
useEffect(() => {
|
|
||||||
const { type, addr } = store.record;
|
|
||||||
if (type === '1' && addr) {
|
|
||||||
store.record.sitePrefix = addr.startsWith('http://') ? 'http://' : 'https://';
|
|
||||||
store.record.domain = store.record.addr.replace(store.record.sitePrefix, '')
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
function handleTest() {
|
function handleTest() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const { type, sitePrefix, domain } = store.record;
|
const formData = lds.pick(store.record, ['type', 'targets', 'extra'])
|
||||||
if (type === '1') store.record.addr = sitePrefix + domain;
|
http.post('/api/monitor/test/', formData, { timeout: 120000 })
|
||||||
http.post('/api/monitor/test/', store.record, { timeout: 120000 })
|
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.is_success) {
|
if (res.is_success) {
|
||||||
Modal.success({ content: res.message })
|
Modal.success({ content: res.message })
|
||||||
|
@ -47,7 +40,7 @@ export default observer(function () {
|
||||||
|
|
||||||
function handleChangeType(v) {
|
function handleChangeType(v) {
|
||||||
store.record.type = v;
|
store.record.type = v;
|
||||||
store.record.addr = undefined;
|
store.record.targets = [];
|
||||||
store.record.extra = undefined;
|
store.record.extra = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,35 +64,30 @@ export default observer(function () {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const SiteBefore = (
|
|
||||||
<Select style={{ width: 90 }} value={store.record.sitePrefix} onChange={v => store.record.sitePrefix = v}>
|
|
||||||
<Select.Option value="http://">http://</Select.Option>
|
|
||||||
<Select.Option value="https://">https://</Select.Option>
|
|
||||||
</Select>
|
|
||||||
)
|
|
||||||
|
|
||||||
function canNext() {
|
function canNext() {
|
||||||
const { type, addr, extra, domain, group } = store.record;
|
const { type, targets, extra, group } = store.record;
|
||||||
if (type === '1') {
|
const is_verify = name && group && targets.length;
|
||||||
return name && domain && group
|
if (['2', '3', '4'].includes(type)) {
|
||||||
} else if (type === '5') {
|
return is_verify && extra
|
||||||
return name && addr && group
|
|
||||||
} else {
|
} else {
|
||||||
return name && addr && extra && group
|
return is_verify
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toNext() {
|
function toNext() {
|
||||||
|
const {type, extra} = store.record;
|
||||||
|
if (!Number(extra) > 0) {
|
||||||
|
if (type === '1' && extra) return message.error('请输入正确的响应时间')
|
||||||
|
if (type === '2') return message.error('请输入正确的端口号')
|
||||||
|
}
|
||||||
store.page += 1;
|
store.page += 1;
|
||||||
const { type, sitePrefix, domain } = store.record;
|
|
||||||
if (type === '1') store.record.addr = sitePrefix + domain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStyle(t) {
|
function getStyle(t) {
|
||||||
return t.includes(store.record.type) ? { display: 'flex' } : { display: 'none' }
|
return t.includes(store.record.type) ? { display: 'flex' } : { display: 'none' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, desc, type, addr, extra, domain, group } = store.record;
|
const { name, desc, type, targets, extra, group } = store.record;
|
||||||
return (
|
return (
|
||||||
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 14 }}>
|
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 14 }}>
|
||||||
<Form.Item required label="监控分组" style={{ marginBottom: 0 }}>
|
<Form.Item required label="监控分组" style={{ marginBottom: 0 }}>
|
||||||
|
@ -114,7 +102,7 @@ export default observer(function () {
|
||||||
<Button type="link" onClick={handleAddGroup}>添加分组</Button>
|
<Button type="link" onClick={handleAddGroup}>添加分组</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="监控类型" help={helpMap[type]}>
|
<Form.Item label="监控类型" tooltip={helpMap[type]}>
|
||||||
<Select placeholder="请选择监控类型" value={type} onChange={handleChangeType}>
|
<Select placeholder="请选择监控类型" value={type} onChange={handleChangeType}>
|
||||||
<Select.Option value="1">站点检测</Select.Option>
|
<Select.Option value="1">站点检测</Select.Option>
|
||||||
<Select.Option value="2">端口检测</Select.Option>
|
<Select.Option value="2">端口检测</Select.Option>
|
||||||
|
@ -127,29 +115,27 @@ export default observer(function () {
|
||||||
<Input value={name} onChange={e => store.record.name = e.target.value} placeholder="请输入监控名称" />
|
<Input value={name} onChange={e => store.record.name = e.target.value} placeholder="请输入监控名称" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="监控地址" style={getStyle(['1'])}>
|
<Form.Item required label="监控地址" style={getStyle(['1'])}>
|
||||||
<Input
|
<Select
|
||||||
value={domain}
|
mode="tags"
|
||||||
addonBefore={SiteBefore}
|
value={targets}
|
||||||
placeholder="请输入监控地址"
|
onChange={v => store.record.targets = v}
|
||||||
onChange={e => store.record.domain = e.target.value} />
|
placeholder="http(s)://开头,支持多个地址,每输入完成一个后按回车确认"
|
||||||
|
notFoundContent={null} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="监控地址" style={getStyle(['2', '5'])}>
|
<Form.Item required label="监控地址" style={getStyle(['2', '5'])}>
|
||||||
<Input value={addr} placeholder="请输入监控地址(IP/域名)" onChange={e => store.record.addr = e.target.value} />
|
<Select
|
||||||
|
mode="tags"
|
||||||
|
value={targets}
|
||||||
|
onChange={v => store.record.targets = v}
|
||||||
|
placeholder="IP或域名,支持多个地址,每输入完成一个后按回车确认"
|
||||||
|
notFoundContent={null} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="监控主机" style={getStyle(['3', '4'])}>
|
<Form.Item required label="监控主机" style={getStyle(['3', '4'])}>
|
||||||
<Select
|
{store.record.targets?.length > 0 && `已选择 ${store.record.targets.length} 台`}
|
||||||
showSearch
|
<Button type="link" onClick={() => setShowSelector(true)}>选择主机</Button>
|
||||||
value={addr}
|
</Form.Item>
|
||||||
placeholder="请选择主机"
|
<Form.Item label="响应时间" style={getStyle(['1'])}>
|
||||||
optionFilterProp="children"
|
<Input suffix="ms" placeholder="最长响应时间(毫秒),不设置则默认10秒超时" onChange={e => store.record.extra = e.target.value}/>
|
||||||
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
|
|
||||||
onChange={v => store.record.addr = v}>
|
|
||||||
{hostStore.records.filter(x => x.id === Number(addr) || hasHostPermission(x.id)).map(item => (
|
|
||||||
<Select.Option value={String(item.id)} key={item.id}>
|
|
||||||
{`${item.name}(${item.hostname}:${item.port})`}
|
|
||||||
</Select.Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item required label="检测端口" style={getStyle(['2'])}>
|
<Form.Item required label="检测端口" style={getStyle(['2'])}>
|
||||||
<Input value={extra} placeholder="请输入端口号" onChange={e => store.record.extra = e.target.value} />
|
<Input value={extra} placeholder="请输入端口号" onChange={e => store.record.extra = e.target.value} />
|
||||||
|
@ -175,9 +161,15 @@ export default observer(function () {
|
||||||
|
|
||||||
<Form.Item wrapperCol={{ span: 14, offset: 6 }} style={{ marginTop: 12 }}>
|
<Form.Item wrapperCol={{ span: 14, offset: 6 }} style={{ marginTop: 12 }}>
|
||||||
<Button disabled={!canNext()} type="primary" onClick={toNext}>下一步</Button>
|
<Button disabled={!canNext()} type="primary" onClick={toNext}>下一步</Button>
|
||||||
<Button disabled={false} type="link" loading={loading} onClick={handleTest}>执行测试</Button>
|
<Button disabled={!canNext()} type="link" loading={loading} onClick={handleTest}>执行测试</Button>
|
||||||
|
<span style={{color: '#888', fontSize: 12}}>Tips: 仅测试第一个监控地址</span>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{showTmp && <TemplateSelector onOk={v => store.record.extra += v} onCancel={() => setShowTmp(false)} />}
|
{showTmp && <TemplateSelector onOk={v => store.record.extra += v} onCancel={() => setShowTmp(false)} />}
|
||||||
|
<Selector
|
||||||
|
visible={showSelector}
|
||||||
|
selectedRowKeys={[...store.record.targets]}
|
||||||
|
onCancel={() => setShowSelector(false)}
|
||||||
|
onOk={(_, ids) => store.record.targets = ids}/>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
})
|
})
|
|
@ -34,7 +34,7 @@ export default observer(function () {
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const formData = form.getFieldsValue();
|
const formData = form.getFieldsValue();
|
||||||
Object.assign(formData, lds.pick(store.record, ['id', 'name', 'desc', 'addr', 'extra', 'type', 'group']))
|
Object.assign(formData, lds.pick(store.record, ['id', 'name', 'desc', 'targets', 'extra', 'type', 'group']))
|
||||||
formData['id'] = store.record.id;
|
formData['id'] = store.record.id;
|
||||||
http.post('/api/monitor/', formData)
|
http.post('/api/monitor/', formData)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Store {
|
||||||
};
|
};
|
||||||
|
|
||||||
showForm = (info) => {
|
showForm = (info) => {
|
||||||
info = info || {type: '1', sitePrefix: 'http://'};
|
info = info || {type: '1', targets: []};
|
||||||
this.page = 0;
|
this.page = 0;
|
||||||
this.record = lds.cloneDeep(info);
|
this.record = lds.cloneDeep(info);
|
||||||
this.formVisible = true;
|
this.formVisible = true;
|
||||||
|
|
Loading…
Reference in New Issue